2856 lines
130 KiB
HTML
2856 lines
130 KiB
HTML
|
||
<!doctype html>
|
||
<html lang="en" class="no-js">
|
||
<head>
|
||
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
||
<meta name="description" content="Single source of truth for the homelab">
|
||
|
||
|
||
|
||
<link rel="canonical" href="http://192.168.1.8:13080/services/cloud-gpu/">
|
||
|
||
|
||
<link rel="prev" href="../adguard-dns/">
|
||
|
||
|
||
<link rel="next" href="../arcane/">
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="icon" href="../../assets/images/favicon.png">
|
||
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
|
||
|
||
|
||
|
||
<title>Cloud GPU - nuclide.systems docs</title>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="../../assets/stylesheets/main.484c7ddc.min.css">
|
||
|
||
|
||
<link rel="stylesheet" href="../../assets/stylesheets/palette.ab4e12ef.min.css">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
||
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
||
|
||
|
||
|
||
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
||
|
||
|
||
|
||
|
||
|
||
</head>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="blue">
|
||
|
||
|
||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
||
<label class="md-overlay" for="__drawer"></label>
|
||
<div data-md-component="skip">
|
||
|
||
|
||
<a href="#cloud-gpu-extension-scaleway-l40s" class="md-skip">
|
||
Skip to content
|
||
</a>
|
||
|
||
</div>
|
||
<div data-md-component="announce">
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<header class="md-header" data-md-component="header">
|
||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||
<a href="../.." title="nuclide.systems docs" class="md-header__button md-logo" aria-label="nuclide.systems docs" data-md-component="logo">
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
||
|
||
</a>
|
||
<label class="md-header__button md-icon" for="__drawer">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
|
||
</label>
|
||
<div class="md-header__title" data-md-component="header-title">
|
||
<div class="md-header__ellipsis">
|
||
<div class="md-header__topic">
|
||
<span class="md-ellipsis">
|
||
nuclide.systems docs
|
||
</span>
|
||
</div>
|
||
<div class="md-header__topic" data-md-component="header-topic">
|
||
<span class="md-ellipsis">
|
||
|
||
Cloud GPU
|
||
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<form class="md-header__option" data-md-component="palette">
|
||
|
||
|
||
|
||
|
||
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="blue" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="blue" aria-hidden="true" type="radio" name="__palette" id="__palette_1">
|
||
|
||
|
||
</form>
|
||
|
||
|
||
|
||
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-header__button md-icon" for="__search">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
||
</label>
|
||
<div class="md-search" data-md-component="search" role="dialog">
|
||
<label class="md-search__overlay" for="__search"></label>
|
||
<div class="md-search__inner" role="search">
|
||
<form class="md-search__form" name="search">
|
||
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
||
<label class="md-search__icon md-icon" for="__search">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
|
||
</label>
|
||
<nav class="md-search__options" aria-label="Search">
|
||
|
||
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
||
</button>
|
||
</nav>
|
||
|
||
<div class="md-search__suggest" data-md-component="search-suggest"></div>
|
||
|
||
</form>
|
||
<div class="md-search__output">
|
||
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
|
||
<div class="md-search-result" data-md-component="search-result">
|
||
<div class="md-search-result__meta">
|
||
Initializing search
|
||
</div>
|
||
<ol class="md-search-result__list" role="presentation"></ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
</nav>
|
||
|
||
</header>
|
||
|
||
<div class="md-container" data-md-component="container">
|
||
|
||
|
||
|
||
|
||
|
||
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
|
||
<div class="md-grid">
|
||
<ul class="md-tabs__list">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../.." class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
Home
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../CHANGELOG/" class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
Changelog
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../RESUME/" class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
Resume
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../ct-inventory/" class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
CT inventory
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../infra/proxmox-state/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Infra
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item md-tabs__item--active">
|
||
<a href="../homelab-architecture/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Services
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../security/data-leak-audit-comparison/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Security & audits
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../ideas/stack-ideas/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Ideas
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../history/traefik-migration/" class="md-tabs__link">
|
||
|
||
|
||
|
||
History
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
|
||
|
||
|
||
<main class="md-main" data-md-component="main">
|
||
<div class="md-main__inner md-grid">
|
||
|
||
|
||
|
||
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
||
<div class="md-sidebar__scrollwrap">
|
||
<div class="md-sidebar__inner">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
|
||
<label class="md-nav__title" for="__drawer">
|
||
<a href="../.." title="nuclide.systems docs" class="md-nav__button md-logo" aria-label="nuclide.systems docs" data-md-component="logo">
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
||
|
||
</a>
|
||
nuclide.systems docs
|
||
</label>
|
||
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../.." class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Home
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../CHANGELOG/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Changelog
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../RESUME/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Resume
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../ct-inventory/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
CT inventory
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_5" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Infra
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_5">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Infra
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/proxmox-state/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Proxmox state
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/portmap/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Port map
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/storage/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Storage
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/volumes/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Volumes
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/docker-networks/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Docker networks
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/connection-hosts/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Connection hosts
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../infra/proxmox-memory-audit/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Memory audit
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" checked>
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Services
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="true">
|
||
<label class="md-nav__title" for="__nav_6">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Services
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../homelab-architecture/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Homelab architecture
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../dev-environment/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Dev environment (Coder + Gitea)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../mcp-gateway/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
MCP gateway
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../mcp-servers/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
MCP servers
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../pocket-id/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Pocket-ID (OIDC)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../backrest/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Backrest (backups)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../databases/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Databases
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../secrets-manager/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Secrets manager
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../comfyui/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
ComfyUI
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../zoraxy/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Zoraxy
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../adguard-dns/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
AdGuard DNS
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active">
|
||
|
||
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Cloud GPU
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<a href="./" class="md-nav__link md-nav__link--active">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Cloud GPU
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
|
||
|
||
|
||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__title" for="__toc">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Table of contents
|
||
</label>
|
||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pricing-current-as-of-may-2026" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pricing (current as of May 2026)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Pricing (current as of May 2026)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#realistic-monthly-cost" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Realistic monthly cost
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#architecture" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Architecture
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#prerequisites" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Prerequisites
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-1-persistent-block-volume-models-live-here" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 1 — Persistent block volume (models live here)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-2-create-the-l40s-instance-with-cloud-init" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 2 — Create the L40S instance with cloud-init
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-3-wireguard-on-the-nuc" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 3 — WireGuard on the NUC
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-4-gpu-proxy-seamless-on-demand-startup" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 4 — gpu-proxy (seamless on-demand startup)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Step 4 — gpu-proxy (seamless on-demand startup)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aigpu-proxydocker-composeyml" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ai/gpu-proxy/docker-compose.yml
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aigpu-proxyproxypy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ai/gpu-proxy/proxy.py
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aigpu-proxydockerfile" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ai/gpu-proxy/Dockerfile
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-5-wire-up-nuc-services" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 5 — Wire up NUC services
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-6-deploy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 6 — Deploy
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Step 6 — Deploy">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#what-the-user-experience-looks-like" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
What the user experience looks like
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#quick-start-stop-scripts" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Quick-start / stop scripts
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#scaleway-firewall-security-groups" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Scaleway firewall (security groups)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#model-storage-layout-on-the-200-gb-volume" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Model storage layout (on the 200 GB volume)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../arcane/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Arcane
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../doc-ingestion/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Doc ingestion pipeline
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../llm-benchmark/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
LLM benchmark
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_7" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_7" id="__nav_7_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Security & audits
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_7">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Security & audits
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/data-leak-audit-comparison/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Comparison
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/data-leak-audit-2026-05-20-tr004-cloud-sandbox/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
2026-05-20 · cloud-sandbox breach
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/data-leak-audit-2026-05-21-tr004-artifacts/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
2026-05-21 · artifacts (clean)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/audit-claude-code-meta/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Self-audit (Claude Code)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/transcripts/audit-chat-2026-05-21/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Transcript (audit session)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_8" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_8" id="__nav_8_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Ideas
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_8_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_8">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Ideas
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../ideas/stack-ideas/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Stack ideas
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_9" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_9" id="__nav_9_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
History
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_9_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_9">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
History
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/traefik-migration/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Traefik (abandoned 2026-05-16)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/traefik-migration-docker-labels/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Traefik labels (abandoned)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/mcp-gateway-requirements/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
MCP gateway requirements (superseded)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/scrubbing-list-2026-05-17/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Scrubbing list (2026-05-17)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/case-study/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Case study
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
||
<div class="md-sidebar__scrollwrap">
|
||
<div class="md-sidebar__inner">
|
||
|
||
|
||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__title" for="__toc">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Table of contents
|
||
</label>
|
||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pricing-current-as-of-may-2026" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pricing (current as of May 2026)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Pricing (current as of May 2026)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#realistic-monthly-cost" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Realistic monthly cost
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#architecture" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Architecture
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#prerequisites" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Prerequisites
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-1-persistent-block-volume-models-live-here" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 1 — Persistent block volume (models live here)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-2-create-the-l40s-instance-with-cloud-init" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 2 — Create the L40S instance with cloud-init
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-3-wireguard-on-the-nuc" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 3 — WireGuard on the NUC
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-4-gpu-proxy-seamless-on-demand-startup" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 4 — gpu-proxy (seamless on-demand startup)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Step 4 — gpu-proxy (seamless on-demand startup)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aigpu-proxydocker-composeyml" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ai/gpu-proxy/docker-compose.yml
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aigpu-proxyproxypy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ai/gpu-proxy/proxy.py
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#aigpu-proxydockerfile" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ai/gpu-proxy/Dockerfile
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-5-wire-up-nuc-services" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 5 — Wire up NUC services
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#step-6-deploy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Step 6 — Deploy
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Step 6 — Deploy">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#what-the-user-experience-looks-like" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
What the user experience looks like
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#quick-start-stop-scripts" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Quick-start / stop scripts
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#scaleway-firewall-security-groups" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Scaleway firewall (security groups)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#model-storage-layout-on-the-200-gb-volume" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Model storage layout (on the 200 GB volume)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="md-content" data-md-component="content">
|
||
|
||
<article class="md-content__inner md-typeset">
|
||
|
||
|
||
|
||
|
||
|
||
<h1 id="cloud-gpu-extension-scaleway-l40s">Cloud GPU Extension — Scaleway L40S<a class="headerlink" href="#cloud-gpu-extension-scaleway-l40s" title="Permanent link">¶</a></h1>
|
||
<p>Seamless on-demand GPU (FLUX.1-dev, video, multi-user) via a Scaleway L40S instance.
|
||
The instance auto-starts on first request and shuts down after 45 min idle.
|
||
Everything personal stays on the NUC.</p>
|
||
<hr />
|
||
<h2 id="pricing-current-as-of-may-2026">Pricing (current as of May 2026)<a class="headerlink" href="#pricing-current-as-of-may-2026" title="Permanent link">¶</a></h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Resource</th>
|
||
<th>Rate</th>
|
||
<th>Notes</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>L40S-1-48G compute</td>
|
||
<td><strong>€1.40/hour</strong></td>
|
||
<td>PAR-2, billed per minute</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Block volume 200 GB</td>
|
||
<td><strong>€16/month</strong></td>
|
||
<td>SSD, keeps models across restarts</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Flexible IP</td>
|
||
<td>€0.004/hour</td>
|
||
<td>Static IP for WireGuard endpoint</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Snapshots</td>
|
||
<td>€0.000044/GB/h</td>
|
||
<td>Only needed for image backups</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="realistic-monthly-cost">Realistic monthly cost<a class="headerlink" href="#realistic-monthly-cost" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Usage pattern</th>
|
||
<th>Compute</th>
|
||
<th>Storage</th>
|
||
<th>Total</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Weekend sessions (8 h/week)</td>
|
||
<td>€45</td>
|
||
<td>€16</td>
|
||
<td><strong>~€61/month</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Daily 1–2 h</td>
|
||
<td>€63–126</td>
|
||
<td>€16</td>
|
||
<td><strong>~€79–142/month</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Heavy (4 h/day)</td>
|
||
<td>€168</td>
|
||
<td>€16</td>
|
||
<td><strong>~€184/month</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Always-on (don't)</td>
|
||
<td>€1,008</td>
|
||
<td>€16</td>
|
||
<td>€1,024/month</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>The on-demand proxy below makes "daily 1–2 h" the natural default — you just click generate, it starts automatically.</p>
|
||
<hr />
|
||
<h2 id="architecture">Architecture<a class="headerlink" href="#architecture" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>NUC (home, always-on) Scaleway PAR-2 (on demand)
|
||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>───────────────────────────── ───────────────────────────────
|
||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>LobeChat ──▶ gpu-proxy:8190 ─── wg1 ──▶ ComfyUI :8188
|
||
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a>comfyui-mcp ──▶ (Docker) Ollama :11434 (optional)
|
||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a> │
|
||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> ├─ start/stop via Scaleway API
|
||
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a> └─ idle watchdog (45 min → stop)
|
||
</code></pre></div>
|
||
<p><code>gpu-proxy</code> is a small Docker service that:
|
||
1. Forwards requests to the GPU instance
|
||
2. Auto-starts the Scaleway instance if it's stopped (cold-start ~90 s)
|
||
3. Shuts it down after 45 min with no traffic</p>
|
||
<hr />
|
||
<h2 id="prerequisites">Prerequisites<a class="headerlink" href="#prerequisites" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="c1"># Scaleway CLI</span>
|
||
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a>curl<span class="w"> </span>-s<span class="w"> </span>https://raw.githubusercontent.com/scaleway/scaleway-cli/master/scripts/get.sh<span class="w"> </span><span class="p">|</span><span class="w"> </span>sh
|
||
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>scw<span class="w"> </span>init<span class="w"> </span><span class="c1"># enter API key + project ID</span>
|
||
</code></pre></div>
|
||
<hr />
|
||
<h2 id="step-1-persistent-block-volume-models-live-here">Step 1 — Persistent block volume (models live here)<a class="headerlink" href="#step-1-persistent-block-volume-models-live-here" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="c1"># Create 200 GB SSD volume in PAR-2</span>
|
||
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a>scw<span class="w"> </span>block<span class="w"> </span>volume<span class="w"> </span>create<span class="w"> </span><span class="nv">name</span><span class="o">=</span>nuclide-gpu-models<span class="w"> </span><span class="nv">size</span><span class="o">=</span>200GB<span class="w"> </span><span class="nv">zone</span><span class="o">=</span>fr-par-2
|
||
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="c1"># Note the volume ID: vol-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</span>
|
||
</code></pre></div>
|
||
<p>Models are kept on this volume. The compute instance can be deleted and recreated freely.</p>
|
||
<hr />
|
||
<h2 id="step-2-create-the-l40s-instance-with-cloud-init">Step 2 — Create the L40S instance with cloud-init<a class="headerlink" href="#step-2-create-the-l40s-instance-with-cloud-init" title="Permanent link">¶</a></h2>
|
||
<p>Save as <code>/opt/stacks/scripts/gpu-cloud-init.yaml</code>:</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1">#cloud-config</span>
|
||
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="nt">package_update</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
|
||
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="nt">packages</span><span class="p">:</span>
|
||
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">wireguard-tools</span>
|
||
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">docker.io</span>
|
||
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">docker-compose-v2</span>
|
||
<a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">nvidia-driver-545</span>
|
||
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">nvidia-container-toolkit</span>
|
||
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a>
|
||
<a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="nt">write_files</span><span class="p">:</span>
|
||
<a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/etc/wireguard/wg0.conf</span>
|
||
<a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a><span class="w"> </span><span class="nt">permissions</span><span class="p">:</span><span class="w"> </span><span class="s">'0600'</span>
|
||
<a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a><span class="w"> </span><span class="nt">content</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
|
||
<a id="__codelineno-3-14" name="__codelineno-3-14" href="#__codelineno-3-14"></a><span class="w"> </span><span class="no">[Interface]</span>
|
||
<a id="__codelineno-3-15" name="__codelineno-3-15" href="#__codelineno-3-15"></a><span class="w"> </span><span class="no">Address = 10.200.0.1/24</span>
|
||
<a id="__codelineno-3-16" name="__codelineno-3-16" href="#__codelineno-3-16"></a><span class="w"> </span><span class="no">ListenPort = 51820</span>
|
||
<a id="__codelineno-3-17" name="__codelineno-3-17" href="#__codelineno-3-17"></a><span class="w"> </span><span class="no">PrivateKey = SCALEWAY_WG_PRIVKEY</span>
|
||
<a id="__codelineno-3-18" name="__codelineno-3-18" href="#__codelineno-3-18"></a>
|
||
<a id="__codelineno-3-19" name="__codelineno-3-19" href="#__codelineno-3-19"></a><span class="w"> </span><span class="no">[Peer]</span>
|
||
<a id="__codelineno-3-20" name="__codelineno-3-20" href="#__codelineno-3-20"></a><span class="w"> </span><span class="no"># NUC</span>
|
||
<a id="__codelineno-3-21" name="__codelineno-3-21" href="#__codelineno-3-21"></a><span class="w"> </span><span class="no">PublicKey = NUC_WG_PUBKEY</span>
|
||
<a id="__codelineno-3-22" name="__codelineno-3-22" href="#__codelineno-3-22"></a><span class="w"> </span><span class="no">AllowedIPs = 10.200.0.2/32</span>
|
||
<a id="__codelineno-3-23" name="__codelineno-3-23" href="#__codelineno-3-23"></a><span class="w"> </span><span class="no">PersistentKeepalive = 25</span>
|
||
<a id="__codelineno-3-24" name="__codelineno-3-24" href="#__codelineno-3-24"></a>
|
||
<a id="__codelineno-3-25" name="__codelineno-3-25" href="#__codelineno-3-25"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/opt/gpu/docker-compose.yml</span>
|
||
<a id="__codelineno-3-26" name="__codelineno-3-26" href="#__codelineno-3-26"></a><span class="w"> </span><span class="nt">content</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
|
||
<a id="__codelineno-3-27" name="__codelineno-3-27" href="#__codelineno-3-27"></a><span class="w"> </span><span class="no">services:</span>
|
||
<a id="__codelineno-3-28" name="__codelineno-3-28" href="#__codelineno-3-28"></a><span class="w"> </span><span class="no">comfyui:</span>
|
||
<a id="__codelineno-3-29" name="__codelineno-3-29" href="#__codelineno-3-29"></a><span class="w"> </span><span class="no">image: yanwk/comfyui-boot:cu124</span>
|
||
<a id="__codelineno-3-30" name="__codelineno-3-30" href="#__codelineno-3-30"></a><span class="w"> </span><span class="no">container_name: comfyui</span>
|
||
<a id="__codelineno-3-31" name="__codelineno-3-31" href="#__codelineno-3-31"></a><span class="w"> </span><span class="no">ports:</span>
|
||
<a id="__codelineno-3-32" name="__codelineno-3-32" href="#__codelineno-3-32"></a><span class="w"> </span><span class="no">- "10.200.0.1:8188:8188"</span>
|
||
<a id="__codelineno-3-33" name="__codelineno-3-33" href="#__codelineno-3-33"></a><span class="w"> </span><span class="no">volumes:</span>
|
||
<a id="__codelineno-3-34" name="__codelineno-3-34" href="#__codelineno-3-34"></a><span class="w"> </span><span class="no">- /mnt/models:/root/ComfyUI/models</span>
|
||
<a id="__codelineno-3-35" name="__codelineno-3-35" href="#__codelineno-3-35"></a><span class="w"> </span><span class="no">- comfyui_config:/root/ComfyUI</span>
|
||
<a id="__codelineno-3-36" name="__codelineno-3-36" href="#__codelineno-3-36"></a><span class="w"> </span><span class="no">environment:</span>
|
||
<a id="__codelineno-3-37" name="__codelineno-3-37" href="#__codelineno-3-37"></a><span class="w"> </span><span class="no">- CLI_ARGS=--listen 0.0.0.0</span>
|
||
<a id="__codelineno-3-38" name="__codelineno-3-38" href="#__codelineno-3-38"></a><span class="w"> </span><span class="no">deploy:</span>
|
||
<a id="__codelineno-3-39" name="__codelineno-3-39" href="#__codelineno-3-39"></a><span class="w"> </span><span class="no">resources:</span>
|
||
<a id="__codelineno-3-40" name="__codelineno-3-40" href="#__codelineno-3-40"></a><span class="w"> </span><span class="no">reservations:</span>
|
||
<a id="__codelineno-3-41" name="__codelineno-3-41" href="#__codelineno-3-41"></a><span class="w"> </span><span class="no">devices:</span>
|
||
<a id="__codelineno-3-42" name="__codelineno-3-42" href="#__codelineno-3-42"></a><span class="w"> </span><span class="no">- driver: nvidia</span>
|
||
<a id="__codelineno-3-43" name="__codelineno-3-43" href="#__codelineno-3-43"></a><span class="w"> </span><span class="no">count: all</span>
|
||
<a id="__codelineno-3-44" name="__codelineno-3-44" href="#__codelineno-3-44"></a><span class="w"> </span><span class="no">capabilities: [gpu]</span>
|
||
<a id="__codelineno-3-45" name="__codelineno-3-45" href="#__codelineno-3-45"></a><span class="w"> </span><span class="no">restart: unless-stopped</span>
|
||
<a id="__codelineno-3-46" name="__codelineno-3-46" href="#__codelineno-3-46"></a>
|
||
<a id="__codelineno-3-47" name="__codelineno-3-47" href="#__codelineno-3-47"></a><span class="w"> </span><span class="no">ollama:</span>
|
||
<a id="__codelineno-3-48" name="__codelineno-3-48" href="#__codelineno-3-48"></a><span class="w"> </span><span class="no">image: ollama/ollama:latest</span>
|
||
<a id="__codelineno-3-49" name="__codelineno-3-49" href="#__codelineno-3-49"></a><span class="w"> </span><span class="no">container_name: ollama</span>
|
||
<a id="__codelineno-3-50" name="__codelineno-3-50" href="#__codelineno-3-50"></a><span class="w"> </span><span class="no">ports:</span>
|
||
<a id="__codelineno-3-51" name="__codelineno-3-51" href="#__codelineno-3-51"></a><span class="w"> </span><span class="no">- "10.200.0.1:11434:11434"</span>
|
||
<a id="__codelineno-3-52" name="__codelineno-3-52" href="#__codelineno-3-52"></a><span class="w"> </span><span class="no">volumes:</span>
|
||
<a id="__codelineno-3-53" name="__codelineno-3-53" href="#__codelineno-3-53"></a><span class="w"> </span><span class="no">- /mnt/models/ollama:/root/.ollama</span>
|
||
<a id="__codelineno-3-54" name="__codelineno-3-54" href="#__codelineno-3-54"></a><span class="w"> </span><span class="no">deploy:</span>
|
||
<a id="__codelineno-3-55" name="__codelineno-3-55" href="#__codelineno-3-55"></a><span class="w"> </span><span class="no">resources:</span>
|
||
<a id="__codelineno-3-56" name="__codelineno-3-56" href="#__codelineno-3-56"></a><span class="w"> </span><span class="no">reservations:</span>
|
||
<a id="__codelineno-3-57" name="__codelineno-3-57" href="#__codelineno-3-57"></a><span class="w"> </span><span class="no">devices:</span>
|
||
<a id="__codelineno-3-58" name="__codelineno-3-58" href="#__codelineno-3-58"></a><span class="w"> </span><span class="no">- driver: nvidia</span>
|
||
<a id="__codelineno-3-59" name="__codelineno-3-59" href="#__codelineno-3-59"></a><span class="w"> </span><span class="no">count: all</span>
|
||
<a id="__codelineno-3-60" name="__codelineno-3-60" href="#__codelineno-3-60"></a><span class="w"> </span><span class="no">capabilities: [gpu]</span>
|
||
<a id="__codelineno-3-61" name="__codelineno-3-61" href="#__codelineno-3-61"></a><span class="w"> </span><span class="no">restart: unless-stopped</span>
|
||
<a id="__codelineno-3-62" name="__codelineno-3-62" href="#__codelineno-3-62"></a>
|
||
<a id="__codelineno-3-63" name="__codelineno-3-63" href="#__codelineno-3-63"></a><span class="w"> </span><span class="no">volumes:</span>
|
||
<a id="__codelineno-3-64" name="__codelineno-3-64" href="#__codelineno-3-64"></a><span class="w"> </span><span class="no">comfyui_config:</span>
|
||
<a id="__codelineno-3-65" name="__codelineno-3-65" href="#__codelineno-3-65"></a>
|
||
<a id="__codelineno-3-66" name="__codelineno-3-66" href="#__codelineno-3-66"></a><span class="nt">runcmd</span><span class="p">:</span>
|
||
<a id="__codelineno-3-67" name="__codelineno-3-67" href="#__codelineno-3-67"></a><span class="w"> </span><span class="c1"># Mount the models volume (will be /dev/sdb or similar)</span>
|
||
<a id="__codelineno-3-68" name="__codelineno-3-68" href="#__codelineno-3-68"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mkdir -p /mnt/models</span>
|
||
<a id="__codelineno-3-69" name="__codelineno-3-69" href="#__codelineno-3-69"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="p p-Indicator">|</span>
|
||
<a id="__codelineno-3-70" name="__codelineno-3-70" href="#__codelineno-3-70"></a><span class="w"> </span><span class="no">DISK=$(lsblk -ndo NAME,SIZE | awk '$2=="200G"{print "/dev/"$1}' | head -1)</span>
|
||
<a id="__codelineno-3-71" name="__codelineno-3-71" href="#__codelineno-3-71"></a><span class="w"> </span><span class="no">if [ -n "$DISK" ]; then</span>
|
||
<a id="__codelineno-3-72" name="__codelineno-3-72" href="#__codelineno-3-72"></a><span class="w"> </span><span class="no">blkid "$DISK" || mkfs.ext4 "$DISK"</span>
|
||
<a id="__codelineno-3-73" name="__codelineno-3-73" href="#__codelineno-3-73"></a><span class="w"> </span><span class="no">echo "$DISK /mnt/models ext4 defaults 0 2" >> /etc/fstab</span>
|
||
<a id="__codelineno-3-74" name="__codelineno-3-74" href="#__codelineno-3-74"></a><span class="w"> </span><span class="no">mount "$DISK" /mnt/models</span>
|
||
<a id="__codelineno-3-75" name="__codelineno-3-75" href="#__codelineno-3-75"></a><span class="w"> </span><span class="no">fi</span>
|
||
<a id="__codelineno-3-76" name="__codelineno-3-76" href="#__codelineno-3-76"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mkdir -p /mnt/models/ollama</span>
|
||
<a id="__codelineno-3-77" name="__codelineno-3-77" href="#__codelineno-3-77"></a><span class="w"> </span><span class="c1"># Enable WireGuard</span>
|
||
<a id="__codelineno-3-78" name="__codelineno-3-78" href="#__codelineno-3-78"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">systemctl enable --now wg-quick@wg0</span>
|
||
<a id="__codelineno-3-79" name="__codelineno-3-79" href="#__codelineno-3-79"></a><span class="w"> </span><span class="c1"># Configure nvidia-container-toolkit</span>
|
||
<a id="__codelineno-3-80" name="__codelineno-3-80" href="#__codelineno-3-80"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">nvidia-ctk runtime configure --runtime=docker</span>
|
||
<a id="__codelineno-3-81" name="__codelineno-3-81" href="#__codelineno-3-81"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">systemctl restart docker</span>
|
||
<a id="__codelineno-3-82" name="__codelineno-3-82" href="#__codelineno-3-82"></a><span class="w"> </span><span class="c1"># Start GPU services</span>
|
||
<a id="__codelineno-3-83" name="__codelineno-3-83" href="#__codelineno-3-83"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cd /opt/gpu && docker compose up -d</span>
|
||
</code></pre></div>
|
||
<p><strong>Before using this file</strong>, replace:
|
||
- <code>SCALEWAY_WG_PRIVKEY</code> → output of <code>wg genkey</code> (run on Scaleway instance side first)
|
||
- <code>NUC_WG_PUBKEY</code> → output of <code>cat /etc/wireguard/nuc_wg_pub</code> (see Step 3)</p>
|
||
<p>Launch the instance:</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="c1"># Generate WireGuard keys first (do this on the NUC)</span>
|
||
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>wg<span class="w"> </span>genkey<span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span>/etc/wireguard/scaleway_wg_priv<span class="w"> </span><span class="p">|</span><span class="w"> </span>wg<span class="w"> </span>pubkey<span class="w"> </span>><span class="w"> </span>/etc/wireguard/scaleway_wg_pub
|
||
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a>wg<span class="w"> </span>genkey<span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span>/etc/wireguard/nuc_wg_priv<span class="w"> </span><span class="p">|</span><span class="w"> </span>wg<span class="w"> </span>pubkey<span class="w"> </span>><span class="w"> </span>/etc/wireguard/nuc_wg_pub
|
||
<a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a>
|
||
<a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="c1"># Fill in cloud-init.yaml with the keys, then:</span>
|
||
<a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="nv">INSTANCE_ID</span><span class="o">=</span><span class="k">$(</span>scw<span class="w"> </span>instance<span class="w"> </span>server<span class="w"> </span>create<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="w"> </span><span class="nv">type</span><span class="o">=</span>L40S-1-48G<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="w"> </span><span class="nv">image</span><span class="o">=</span>ubuntu_jammy_gpu<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="w"> </span><span class="nv">zone</span><span class="o">=</span>fr-par-2<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="w"> </span><span class="nv">name</span><span class="o">=</span>nuclide-gpu<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="w"> </span>cloud-init<span class="o">=</span>@/opt/stacks/scripts/gpu-cloud-init.yaml<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="w"> </span><span class="nv">output</span><span class="o">=</span>json<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>-r<span class="w"> </span><span class="s1">'.id'</span><span class="k">)</span>
|
||
<a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a>
|
||
<a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">"Instance ID: </span><span class="nv">$INSTANCE_ID</span><span class="s2">"</span>
|
||
<a id="__codelineno-4-15" name="__codelineno-4-15" href="#__codelineno-4-15"></a>
|
||
<a id="__codelineno-4-16" name="__codelineno-4-16" href="#__codelineno-4-16"></a><span class="c1"># Attach the models volume</span>
|
||
<a id="__codelineno-4-17" name="__codelineno-4-17" href="#__codelineno-4-17"></a>scw<span class="w"> </span>instance<span class="w"> </span>server<span class="w"> </span>attach-volume<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-18" name="__codelineno-4-18" href="#__codelineno-4-18"></a><span class="w"> </span>server-id<span class="o">=</span><span class="nv">$INSTANCE_ID</span><span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-19" name="__codelineno-4-19" href="#__codelineno-4-19"></a><span class="w"> </span>volume-id<span class="o">=</span>vol-xxxxxxxx<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-20" name="__codelineno-4-20" href="#__codelineno-4-20"></a><span class="w"> </span><span class="nv">zone</span><span class="o">=</span>fr-par-2
|
||
<a id="__codelineno-4-21" name="__codelineno-4-21" href="#__codelineno-4-21"></a>
|
||
<a id="__codelineno-4-22" name="__codelineno-4-22" href="#__codelineno-4-22"></a><span class="c1"># Allocate a Flexible IP (static IP that survives instance restarts)</span>
|
||
<a id="__codelineno-4-23" name="__codelineno-4-23" href="#__codelineno-4-23"></a><span class="nv">FLEXIP_ID</span><span class="o">=</span><span class="k">$(</span>scw<span class="w"> </span>instance<span class="w"> </span>ip<span class="w"> </span>create<span class="w"> </span><span class="nv">zone</span><span class="o">=</span>fr-par-2<span class="w"> </span><span class="nv">output</span><span class="o">=</span>json<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>-r<span class="w"> </span><span class="s1">'.id'</span><span class="k">)</span>
|
||
<a id="__codelineno-4-24" name="__codelineno-4-24" href="#__codelineno-4-24"></a>scw<span class="w"> </span>instance<span class="w"> </span>server<span class="w"> </span>attach-flexible-ip<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-25" name="__codelineno-4-25" href="#__codelineno-4-25"></a><span class="w"> </span>server-id<span class="o">=</span><span class="nv">$INSTANCE_ID</span><span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-26" name="__codelineno-4-26" href="#__codelineno-4-26"></a><span class="w"> </span>ip-id<span class="o">=</span><span class="nv">$FLEXIP_ID</span><span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-4-27" name="__codelineno-4-27" href="#__codelineno-4-27"></a><span class="w"> </span><span class="nv">zone</span><span class="o">=</span>fr-par-2
|
||
<a id="__codelineno-4-28" name="__codelineno-4-28" href="#__codelineno-4-28"></a>
|
||
<a id="__codelineno-4-29" name="__codelineno-4-29" href="#__codelineno-4-29"></a><span class="nv">FLEXIP</span><span class="o">=</span><span class="k">$(</span>scw<span class="w"> </span>instance<span class="w"> </span>ip<span class="w"> </span>get<span class="w"> </span><span class="nv">$FLEXIP_ID</span><span class="w"> </span><span class="nv">zone</span><span class="o">=</span>fr-par-2<span class="w"> </span><span class="nv">output</span><span class="o">=</span>json<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>-r<span class="w"> </span><span class="s1">'.address'</span><span class="k">)</span>
|
||
<a id="__codelineno-4-30" name="__codelineno-4-30" href="#__codelineno-4-30"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">"Scaleway public IP: </span><span class="nv">$FLEXIP</span><span class="s2">"</span>
|
||
</code></pre></div>
|
||
<hr />
|
||
<h2 id="step-3-wireguard-on-the-nuc">Step 3 — WireGuard on the NUC<a class="headerlink" href="#step-3-wireguard-on-the-nuc" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="c1"># /etc/wireguard/wg1.conf (separate from any existing VPN tunnel)</span>
|
||
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a>cat<span class="w"> </span>><span class="w"> </span>/etc/wireguard/wg1.conf<span class="w"> </span><span class="s"><< EOF</span>
|
||
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="s">[Interface]</span>
|
||
<a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="s">Address = 10.200.0.2/24</span>
|
||
<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="s">PrivateKey = $(cat /etc/wireguard/nuc_wg_priv)</span>
|
||
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a>
|
||
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="s">[Peer]</span>
|
||
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="s"># Scaleway GPU</span>
|
||
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="s">PublicKey = $(cat /etc/wireguard/scaleway_wg_pub)</span>
|
||
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="s">Endpoint = ${FLEXIP}:51820</span>
|
||
<a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a><span class="s">AllowedIPs = 10.200.0.1/32</span>
|
||
<a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a><span class="s">PersistentKeepalive = 25</span>
|
||
<a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a><span class="s">EOF</span>
|
||
<a id="__codelineno-5-14" name="__codelineno-5-14" href="#__codelineno-5-14"></a>
|
||
<a id="__codelineno-5-15" name="__codelineno-5-15" href="#__codelineno-5-15"></a>chmod<span class="w"> </span><span class="m">600</span><span class="w"> </span>/etc/wireguard/wg1.conf
|
||
<a id="__codelineno-5-16" name="__codelineno-5-16" href="#__codelineno-5-16"></a>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>--now<span class="w"> </span>wg-quick@wg1
|
||
</code></pre></div>
|
||
<p>Test when the instance is running:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>ping<span class="w"> </span><span class="m">10</span>.200.0.1<span class="w"> </span><span class="c1"># WireGuard tunnel</span>
|
||
<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a>curl<span class="w"> </span>http://10.200.0.1:8188<span class="w"> </span><span class="c1"># ComfyUI</span>
|
||
</code></pre></div></p>
|
||
<hr />
|
||
<h2 id="step-4-gpu-proxy-seamless-on-demand-startup">Step 4 — gpu-proxy (seamless on-demand startup)<a class="headerlink" href="#step-4-gpu-proxy-seamless-on-demand-startup" title="Permanent link">¶</a></h2>
|
||
<p>This Docker service runs on the NUC. It proxies to the GPU instance and auto-starts/stops it.</p>
|
||
<h3 id="aigpu-proxydocker-composeyml"><code>ai/gpu-proxy/docker-compose.yml</code><a class="headerlink" href="#aigpu-proxydocker-composeyml" title="Permanent link">¶</a></h3>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="nt">services</span><span class="p">:</span>
|
||
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="nt">gpu-proxy</span><span class="p">:</span>
|
||
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="nt">build</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">.</span>
|
||
<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">gpu-proxy</span>
|
||
<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>
|
||
<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SCW_SECRET_KEY=${SCW_SECRET_KEY}</span>
|
||
<a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SCW_PROJECT_ID=${SCW_PROJECT_ID}</span>
|
||
<a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SCW_INSTANCE_ID=${SCW_INSTANCE_ID}</span>
|
||
<a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SCW_ZONE=fr-par-2</span>
|
||
<a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">GPU_HOST=10.200.0.1</span>
|
||
<a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">COMFYUI_PORT=8188</span>
|
||
<a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">OLLAMA_PORT=11434</span>
|
||
<a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">IDLE_TIMEOUT=2700</span><span class="w"> </span><span class="c1"># 45 min</span>
|
||
<a id="__codelineno-7-14" name="__codelineno-7-14" href="#__codelineno-7-14"></a><span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
|
||
<a id="__codelineno-7-15" name="__codelineno-7-15" href="#__codelineno-7-15"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">"8190:8190"</span><span class="w"> </span><span class="c1"># ComfyUI proxy</span>
|
||
<a id="__codelineno-7-16" name="__codelineno-7-16" href="#__codelineno-7-16"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">"8191:8191"</span><span class="w"> </span><span class="c1"># Ollama proxy</span>
|
||
<a id="__codelineno-7-17" name="__codelineno-7-17" href="#__codelineno-7-17"></a><span class="w"> </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">unless-stopped</span>
|
||
<a id="__codelineno-7-18" name="__codelineno-7-18" href="#__codelineno-7-18"></a><span class="w"> </span><span class="nt">networks</span><span class="p">:</span>
|
||
<a id="__codelineno-7-19" name="__codelineno-7-19" href="#__codelineno-7-19"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">shared_backend</span>
|
||
<a id="__codelineno-7-20" name="__codelineno-7-20" href="#__codelineno-7-20"></a>
|
||
<a id="__codelineno-7-21" name="__codelineno-7-21" href="#__codelineno-7-21"></a><span class="nt">networks</span><span class="p">:</span>
|
||
<a id="__codelineno-7-22" name="__codelineno-7-22" href="#__codelineno-7-22"></a><span class="w"> </span><span class="nt">shared_backend</span><span class="p">:</span>
|
||
<a id="__codelineno-7-23" name="__codelineno-7-23" href="#__codelineno-7-23"></a><span class="w"> </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
|
||
</code></pre></div>
|
||
<h3 id="aigpu-proxyproxypy"><code>ai/gpu-proxy/proxy.py</code><a class="headerlink" href="#aigpu-proxyproxypy" title="Permanent link">¶</a></h3>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="sd">"""</span>
|
||
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="sd">On-demand GPU proxy. Auto-starts the Scaleway instance on first request,</span>
|
||
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="sd">shuts it down after IDLE_TIMEOUT seconds of inactivity.</span>
|
||
<a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="sd">"""</span>
|
||
<a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span><span class="o">,</span><span class="w"> </span><span class="nn">os</span><span class="o">,</span><span class="w"> </span><span class="nn">time</span><span class="o">,</span><span class="w"> </span><span class="nn">httpx</span><span class="o">,</span><span class="w"> </span><span class="nn">subprocess</span>
|
||
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastAPI</span><span class="p">,</span> <span class="n">Request</span>
|
||
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi.responses</span><span class="w"> </span><span class="kn">import</span> <span class="n">StreamingResponse</span><span class="p">,</span> <span class="n">JSONResponse</span>
|
||
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a>
|
||
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
|
||
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a>
|
||
<a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a><span class="n">SCW_KEY</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"SCW_SECRET_KEY"</span><span class="p">]</span>
|
||
<a id="__codelineno-8-12" name="__codelineno-8-12" href="#__codelineno-8-12"></a><span class="n">SCW_PROJECT</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"SCW_PROJECT_ID"</span><span class="p">]</span>
|
||
<a id="__codelineno-8-13" name="__codelineno-8-13" href="#__codelineno-8-13"></a><span class="n">INSTANCE_ID</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"SCW_INSTANCE_ID"</span><span class="p">]</span>
|
||
<a id="__codelineno-8-14" name="__codelineno-8-14" href="#__codelineno-8-14"></a><span class="n">ZONE</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"SCW_ZONE"</span><span class="p">,</span> <span class="s2">"fr-par-2"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-15" name="__codelineno-8-15" href="#__codelineno-8-15"></a><span class="n">GPU_HOST</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"GPU_HOST"</span><span class="p">,</span> <span class="s2">"10.200.0.1"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-16" name="__codelineno-8-16" href="#__codelineno-8-16"></a><span class="n">COMFYUI_PORT</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"COMFYUI_PORT"</span><span class="p">,</span> <span class="mi">8188</span><span class="p">))</span>
|
||
<a id="__codelineno-8-17" name="__codelineno-8-17" href="#__codelineno-8-17"></a><span class="n">OLLAMA_PORT</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"OLLAMA_PORT"</span><span class="p">,</span> <span class="mi">11434</span><span class="p">))</span>
|
||
<a id="__codelineno-8-18" name="__codelineno-8-18" href="#__codelineno-8-18"></a><span class="n">IDLE_TIMEOUT</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"IDLE_TIMEOUT"</span><span class="p">,</span> <span class="mi">2700</span><span class="p">))</span>
|
||
<a id="__codelineno-8-19" name="__codelineno-8-19" href="#__codelineno-8-19"></a>
|
||
<a id="__codelineno-8-20" name="__codelineno-8-20" href="#__codelineno-8-20"></a><span class="n">SCW_API</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"https://api.scaleway.com/instance/v1/zones/</span><span class="si">{</span><span class="n">ZONE</span><span class="si">}</span><span class="s2">"</span>
|
||
<a id="__codelineno-8-21" name="__codelineno-8-21" href="#__codelineno-8-21"></a><span class="n">HEADERS</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"X-Auth-Token"</span><span class="p">:</span> <span class="n">SCW_KEY</span><span class="p">,</span> <span class="s2">"Content-Type"</span><span class="p">:</span> <span class="s2">"application/json"</span><span class="p">}</span>
|
||
<a id="__codelineno-8-22" name="__codelineno-8-22" href="#__codelineno-8-22"></a>
|
||
<a id="__codelineno-8-23" name="__codelineno-8-23" href="#__codelineno-8-23"></a><span class="n">_state</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"last_activity"</span><span class="p">:</span> <span class="mf">0.0</span><span class="p">,</span> <span class="s2">"starting"</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span> <span class="s2">"up"</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
|
||
<a id="__codelineno-8-24" name="__codelineno-8-24" href="#__codelineno-8-24"></a><span class="n">_lock</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
|
||
<a id="__codelineno-8-25" name="__codelineno-8-25" href="#__codelineno-8-25"></a>
|
||
<a id="__codelineno-8-26" name="__codelineno-8-26" href="#__codelineno-8-26"></a>
|
||
<a id="__codelineno-8-27" name="__codelineno-8-27" href="#__codelineno-8-27"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_scw</span><span class="p">(</span><span class="n">method</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<a id="__codelineno-8-28" name="__codelineno-8-28" href="#__codelineno-8-28"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">httpx</span><span class="o">.</span><span class="n">AsyncClient</span><span class="p">()</span> <span class="k">as</span> <span class="n">c</span><span class="p">:</span>
|
||
<a id="__codelineno-8-29" name="__codelineno-8-29" href="#__codelineno-8-29"></a> <span class="n">r</span> <span class="o">=</span> <span class="k">await</span> <span class="n">c</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">SCW_API</span><span class="si">}{</span><span class="n">path</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">HEADERS</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
<a id="__codelineno-8-30" name="__codelineno-8-30" href="#__codelineno-8-30"></a> <span class="n">r</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
|
||
<a id="__codelineno-8-31" name="__codelineno-8-31" href="#__codelineno-8-31"></a> <span class="k">return</span> <span class="n">r</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
|
||
<a id="__codelineno-8-32" name="__codelineno-8-32" href="#__codelineno-8-32"></a>
|
||
<a id="__codelineno-8-33" name="__codelineno-8-33" href="#__codelineno-8-33"></a>
|
||
<a id="__codelineno-8-34" name="__codelineno-8-34" href="#__codelineno-8-34"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_instance_state</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
||
<a id="__codelineno-8-35" name="__codelineno-8-35" href="#__codelineno-8-35"></a> <span class="n">d</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_scw</span><span class="p">(</span><span class="s2">"GET"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"/servers/</span><span class="si">{</span><span class="n">INSTANCE_ID</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-36" name="__codelineno-8-36" href="#__codelineno-8-36"></a> <span class="k">return</span> <span class="n">d</span><span class="p">[</span><span class="s2">"server"</span><span class="p">][</span><span class="s2">"state"</span><span class="p">]</span> <span class="c1"># running | stopped | stopping | starting</span>
|
||
<a id="__codelineno-8-37" name="__codelineno-8-37" href="#__codelineno-8-37"></a>
|
||
<a id="__codelineno-8-38" name="__codelineno-8-38" href="#__codelineno-8-38"></a>
|
||
<a id="__codelineno-8-39" name="__codelineno-8-39" href="#__codelineno-8-39"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_start_instance</span><span class="p">():</span>
|
||
<a id="__codelineno-8-40" name="__codelineno-8-40" href="#__codelineno-8-40"></a> <span class="k">await</span> <span class="n">_scw</span><span class="p">(</span><span class="s2">"POST"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"/servers/</span><span class="si">{</span><span class="n">INSTANCE_ID</span><span class="si">}</span><span class="s2">/action"</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="p">{</span><span class="s2">"action"</span><span class="p">:</span> <span class="s2">"poweron"</span><span class="p">})</span>
|
||
<a id="__codelineno-8-41" name="__codelineno-8-41" href="#__codelineno-8-41"></a>
|
||
<a id="__codelineno-8-42" name="__codelineno-8-42" href="#__codelineno-8-42"></a>
|
||
<a id="__codelineno-8-43" name="__codelineno-8-43" href="#__codelineno-8-43"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_stop_instance</span><span class="p">():</span>
|
||
<a id="__codelineno-8-44" name="__codelineno-8-44" href="#__codelineno-8-44"></a> <span class="k">await</span> <span class="n">_scw</span><span class="p">(</span><span class="s2">"POST"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"/servers/</span><span class="si">{</span><span class="n">INSTANCE_ID</span><span class="si">}</span><span class="s2">/action"</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="p">{</span><span class="s2">"action"</span><span class="p">:</span> <span class="s2">"poweroff"</span><span class="p">})</span>
|
||
<a id="__codelineno-8-45" name="__codelineno-8-45" href="#__codelineno-8-45"></a>
|
||
<a id="__codelineno-8-46" name="__codelineno-8-46" href="#__codelineno-8-46"></a>
|
||
<a id="__codelineno-8-47" name="__codelineno-8-47" href="#__codelineno-8-47"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wait_ready</span><span class="p">(</span><span class="n">host</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">180</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
|
||
<a id="__codelineno-8-48" name="__codelineno-8-48" href="#__codelineno-8-48"></a> <span class="n">deadline</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">+</span> <span class="n">timeout</span>
|
||
<a id="__codelineno-8-49" name="__codelineno-8-49" href="#__codelineno-8-49"></a> <span class="k">while</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o"><</span> <span class="n">deadline</span><span class="p">:</span>
|
||
<a id="__codelineno-8-50" name="__codelineno-8-50" href="#__codelineno-8-50"></a> <span class="k">try</span><span class="p">:</span>
|
||
<a id="__codelineno-8-51" name="__codelineno-8-51" href="#__codelineno-8-51"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">httpx</span><span class="o">.</span><span class="n">AsyncClient</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="k">as</span> <span class="n">c</span><span class="p">:</span>
|
||
<a id="__codelineno-8-52" name="__codelineno-8-52" href="#__codelineno-8-52"></a> <span class="k">await</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">"http://</span><span class="si">{</span><span class="n">host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">port</span><span class="si">}</span><span class="s2">/"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-53" name="__codelineno-8-53" href="#__codelineno-8-53"></a> <span class="k">return</span> <span class="kc">True</span>
|
||
<a id="__codelineno-8-54" name="__codelineno-8-54" href="#__codelineno-8-54"></a> <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||
<a id="__codelineno-8-55" name="__codelineno-8-55" href="#__codelineno-8-55"></a> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||
<a id="__codelineno-8-56" name="__codelineno-8-56" href="#__codelineno-8-56"></a> <span class="k">return</span> <span class="kc">False</span>
|
||
<a id="__codelineno-8-57" name="__codelineno-8-57" href="#__codelineno-8-57"></a>
|
||
<a id="__codelineno-8-58" name="__codelineno-8-58" href="#__codelineno-8-58"></a>
|
||
<a id="__codelineno-8-59" name="__codelineno-8-59" href="#__codelineno-8-59"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">ensure_up</span><span class="p">(</span><span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
|
||
<a id="__codelineno-8-60" name="__codelineno-8-60" href="#__codelineno-8-60"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
|
||
<a id="__codelineno-8-61" name="__codelineno-8-61" href="#__codelineno-8-61"></a> <span class="k">if</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]:</span>
|
||
<a id="__codelineno-8-62" name="__codelineno-8-62" href="#__codelineno-8-62"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">]</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
|
||
<a id="__codelineno-8-63" name="__codelineno-8-63" href="#__codelineno-8-63"></a> <span class="k">return</span> <span class="kc">True</span>
|
||
<a id="__codelineno-8-64" name="__codelineno-8-64" href="#__codelineno-8-64"></a> <span class="k">if</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"starting"</span><span class="p">]:</span>
|
||
<a id="__codelineno-8-65" name="__codelineno-8-65" href="#__codelineno-8-65"></a> <span class="k">return</span> <span class="kc">False</span> <span class="c1"># caller will retry</span>
|
||
<a id="__codelineno-8-66" name="__codelineno-8-66" href="#__codelineno-8-66"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"starting"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<a id="__codelineno-8-67" name="__codelineno-8-67" href="#__codelineno-8-67"></a>
|
||
<a id="__codelineno-8-68" name="__codelineno-8-68" href="#__codelineno-8-68"></a> <span class="k">try</span><span class="p">:</span>
|
||
<a id="__codelineno-8-69" name="__codelineno-8-69" href="#__codelineno-8-69"></a> <span class="n">state</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_instance_state</span><span class="p">()</span>
|
||
<a id="__codelineno-8-70" name="__codelineno-8-70" href="#__codelineno-8-70"></a> <span class="k">if</span> <span class="n">state</span> <span class="o">!=</span> <span class="s2">"running"</span><span class="p">:</span>
|
||
<a id="__codelineno-8-71" name="__codelineno-8-71" href="#__codelineno-8-71"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"[gpu-proxy] instance </span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s2"> → starting"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-72" name="__codelineno-8-72" href="#__codelineno-8-72"></a> <span class="k">await</span> <span class="n">_start_instance</span><span class="p">()</span>
|
||
<a id="__codelineno-8-73" name="__codelineno-8-73" href="#__codelineno-8-73"></a> <span class="c1"># wait for API to report running</span>
|
||
<a id="__codelineno-8-74" name="__codelineno-8-74" href="#__codelineno-8-74"></a> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
|
||
<a id="__codelineno-8-75" name="__codelineno-8-75" href="#__codelineno-8-75"></a> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||
<a id="__codelineno-8-76" name="__codelineno-8-76" href="#__codelineno-8-76"></a> <span class="k">if</span> <span class="k">await</span> <span class="n">_instance_state</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"running"</span><span class="p">:</span>
|
||
<a id="__codelineno-8-77" name="__codelineno-8-77" href="#__codelineno-8-77"></a> <span class="k">break</span>
|
||
<a id="__codelineno-8-78" name="__codelineno-8-78" href="#__codelineno-8-78"></a> <span class="c1"># wait for service to respond</span>
|
||
<a id="__codelineno-8-79" name="__codelineno-8-79" href="#__codelineno-8-79"></a> <span class="k">if</span> <span class="k">await</span> <span class="n">_wait_ready</span><span class="p">(</span><span class="n">GPU_HOST</span><span class="p">,</span> <span class="n">port</span><span class="p">):</span>
|
||
<a id="__codelineno-8-80" name="__codelineno-8-80" href="#__codelineno-8-80"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
|
||
<a id="__codelineno-8-81" name="__codelineno-8-81" href="#__codelineno-8-81"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<a id="__codelineno-8-82" name="__codelineno-8-82" href="#__codelineno-8-82"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">]</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
|
||
<a id="__codelineno-8-83" name="__codelineno-8-83" href="#__codelineno-8-83"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"[gpu-proxy] GPU instance ready"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-84" name="__codelineno-8-84" href="#__codelineno-8-84"></a> <span class="k">return</span> <span class="kc">True</span>
|
||
<a id="__codelineno-8-85" name="__codelineno-8-85" href="#__codelineno-8-85"></a> <span class="k">return</span> <span class="kc">False</span>
|
||
<a id="__codelineno-8-86" name="__codelineno-8-86" href="#__codelineno-8-86"></a> <span class="k">finally</span><span class="p">:</span>
|
||
<a id="__codelineno-8-87" name="__codelineno-8-87" href="#__codelineno-8-87"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
|
||
<a id="__codelineno-8-88" name="__codelineno-8-88" href="#__codelineno-8-88"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"starting"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<a id="__codelineno-8-89" name="__codelineno-8-89" href="#__codelineno-8-89"></a>
|
||
<a id="__codelineno-8-90" name="__codelineno-8-90" href="#__codelineno-8-90"></a>
|
||
<a id="__codelineno-8-91" name="__codelineno-8-91" href="#__codelineno-8-91"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">idle_watchdog</span><span class="p">():</span>
|
||
<a id="__codelineno-8-92" name="__codelineno-8-92" href="#__codelineno-8-92"></a> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||
<a id="__codelineno-8-93" name="__codelineno-8-93" href="#__codelineno-8-93"></a> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
|
||
<a id="__codelineno-8-94" name="__codelineno-8-94" href="#__codelineno-8-94"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
|
||
<a id="__codelineno-8-95" name="__codelineno-8-95" href="#__codelineno-8-95"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]:</span>
|
||
<a id="__codelineno-8-96" name="__codelineno-8-96" href="#__codelineno-8-96"></a> <span class="k">continue</span>
|
||
<a id="__codelineno-8-97" name="__codelineno-8-97" href="#__codelineno-8-97"></a> <span class="n">idle</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">]</span>
|
||
<a id="__codelineno-8-98" name="__codelineno-8-98" href="#__codelineno-8-98"></a> <span class="k">if</span> <span class="n">idle</span> <span class="o">></span> <span class="n">IDLE_TIMEOUT</span><span class="p">:</span>
|
||
<a id="__codelineno-8-99" name="__codelineno-8-99" href="#__codelineno-8-99"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"[gpu-proxy] idle </span><span class="si">{</span><span class="n">idle</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s → stopping instance"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-100" name="__codelineno-8-100" href="#__codelineno-8-100"></a> <span class="k">try</span><span class="p">:</span>
|
||
<a id="__codelineno-8-101" name="__codelineno-8-101" href="#__codelineno-8-101"></a> <span class="k">await</span> <span class="n">_stop_instance</span><span class="p">()</span>
|
||
<a id="__codelineno-8-102" name="__codelineno-8-102" href="#__codelineno-8-102"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
|
||
<a id="__codelineno-8-103" name="__codelineno-8-103" href="#__codelineno-8-103"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<a id="__codelineno-8-104" name="__codelineno-8-104" href="#__codelineno-8-104"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||
<a id="__codelineno-8-105" name="__codelineno-8-105" href="#__codelineno-8-105"></a> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||
<a id="__codelineno-8-106" name="__codelineno-8-106" href="#__codelineno-8-106"></a> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"[gpu-proxy] stop error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-107" name="__codelineno-8-107" href="#__codelineno-8-107"></a>
|
||
<a id="__codelineno-8-108" name="__codelineno-8-108" href="#__codelineno-8-108"></a>
|
||
<a id="__codelineno-8-109" name="__codelineno-8-109" href="#__codelineno-8-109"></a><span class="nd">@app</span><span class="o">.</span><span class="n">on_event</span><span class="p">(</span><span class="s2">"startup"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-110" name="__codelineno-8-110" href="#__codelineno-8-110"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">startup</span><span class="p">():</span>
|
||
<a id="__codelineno-8-111" name="__codelineno-8-111" href="#__codelineno-8-111"></a> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">idle_watchdog</span><span class="p">())</span>
|
||
<a id="__codelineno-8-112" name="__codelineno-8-112" href="#__codelineno-8-112"></a> <span class="c1"># Probe: is the instance already running from a previous session?</span>
|
||
<a id="__codelineno-8-113" name="__codelineno-8-113" href="#__codelineno-8-113"></a> <span class="k">try</span><span class="p">:</span>
|
||
<a id="__codelineno-8-114" name="__codelineno-8-114" href="#__codelineno-8-114"></a> <span class="k">if</span> <span class="k">await</span> <span class="n">_instance_state</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"running"</span><span class="p">:</span>
|
||
<a id="__codelineno-8-115" name="__codelineno-8-115" href="#__codelineno-8-115"></a> <span class="k">if</span> <span class="k">await</span> <span class="n">_wait_ready</span><span class="p">(</span><span class="n">GPU_HOST</span><span class="p">,</span> <span class="n">COMFYUI_PORT</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">10</span><span class="p">):</span>
|
||
<a id="__codelineno-8-116" name="__codelineno-8-116" href="#__codelineno-8-116"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
|
||
<a id="__codelineno-8-117" name="__codelineno-8-117" href="#__codelineno-8-117"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<a id="__codelineno-8-118" name="__codelineno-8-118" href="#__codelineno-8-118"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">]</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
|
||
<a id="__codelineno-8-119" name="__codelineno-8-119" href="#__codelineno-8-119"></a> <span class="nb">print</span><span class="p">(</span><span class="s2">"[gpu-proxy] GPU already up on startup"</span><span class="p">)</span>
|
||
<a id="__codelineno-8-120" name="__codelineno-8-120" href="#__codelineno-8-120"></a> <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||
<a id="__codelineno-8-121" name="__codelineno-8-121" href="#__codelineno-8-121"></a> <span class="k">pass</span>
|
||
<a id="__codelineno-8-122" name="__codelineno-8-122" href="#__codelineno-8-122"></a>
|
||
<a id="__codelineno-8-123" name="__codelineno-8-123" href="#__codelineno-8-123"></a>
|
||
<a id="__codelineno-8-124" name="__codelineno-8-124" href="#__codelineno-8-124"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_proxy</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">host</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">port</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
|
||
<a id="__codelineno-8-125" name="__codelineno-8-125" href="#__codelineno-8-125"></a> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">]</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
|
||
<a id="__codelineno-8-126" name="__codelineno-8-126" href="#__codelineno-8-126"></a> <span class="n">ready</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ensure_up</span><span class="p">(</span><span class="n">port</span><span class="p">)</span>
|
||
<a id="__codelineno-8-127" name="__codelineno-8-127" href="#__codelineno-8-127"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">ready</span><span class="p">:</span>
|
||
<a id="__codelineno-8-128" name="__codelineno-8-128" href="#__codelineno-8-128"></a> <span class="c1"># Starting up — keep trying for up to 3 min</span>
|
||
<a id="__codelineno-8-129" name="__codelineno-8-129" href="#__codelineno-8-129"></a> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">36</span><span class="p">):</span>
|
||
<a id="__codelineno-8-130" name="__codelineno-8-130" href="#__codelineno-8-130"></a> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||
<a id="__codelineno-8-131" name="__codelineno-8-131" href="#__codelineno-8-131"></a> <span class="k">if</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]:</span>
|
||
<a id="__codelineno-8-132" name="__codelineno-8-132" href="#__codelineno-8-132"></a> <span class="k">break</span>
|
||
<a id="__codelineno-8-133" name="__codelineno-8-133" href="#__codelineno-8-133"></a> <span class="k">else</span><span class="p">:</span>
|
||
<a id="__codelineno-8-134" name="__codelineno-8-134" href="#__codelineno-8-134"></a> <span class="k">return</span> <span class="n">JSONResponse</span><span class="p">({</span><span class="s2">"error"</span><span class="p">:</span> <span class="s2">"GPU instance failed to start"</span><span class="p">},</span> <span class="mi">503</span><span class="p">)</span>
|
||
<a id="__codelineno-8-135" name="__codelineno-8-135" href="#__codelineno-8-135"></a>
|
||
<a id="__codelineno-8-136" name="__codelineno-8-136" href="#__codelineno-8-136"></a> <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"http://</span><span class="si">{</span><span class="n">host</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">port</span><span class="si">}{</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">path</span><span class="si">}</span><span class="s2">"</span>
|
||
<a id="__codelineno-8-137" name="__codelineno-8-137" href="#__codelineno-8-137"></a> <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">query</span><span class="p">:</span>
|
||
<a id="__codelineno-8-138" name="__codelineno-8-138" href="#__codelineno-8-138"></a> <span class="n">url</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">"?</span><span class="si">{</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">query</span><span class="si">}</span><span class="s2">"</span>
|
||
<a id="__codelineno-8-139" name="__codelineno-8-139" href="#__codelineno-8-139"></a> <span class="n">body</span> <span class="o">=</span> <span class="k">await</span> <span class="n">request</span><span class="o">.</span><span class="n">body</span><span class="p">()</span>
|
||
<a id="__codelineno-8-140" name="__codelineno-8-140" href="#__codelineno-8-140"></a> <span class="n">client</span> <span class="o">=</span> <span class="n">httpx</span><span class="o">.</span><span class="n">AsyncClient</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="n">httpx</span><span class="o">.</span><span class="n">Timeout</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">connect</span><span class="o">=</span><span class="mi">10</span><span class="p">))</span>
|
||
<a id="__codelineno-8-141" name="__codelineno-8-141" href="#__codelineno-8-141"></a> <span class="n">req</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">build_request</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">method</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span>
|
||
<a id="__codelineno-8-142" name="__codelineno-8-142" href="#__codelineno-8-142"></a> <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
|
||
<a id="__codelineno-8-143" name="__codelineno-8-143" href="#__codelineno-8-143"></a> <span class="k">if</span> <span class="n">k</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">{</span><span class="s2">"host"</span><span class="p">,</span> <span class="s2">"content-length"</span><span class="p">}},</span>
|
||
<a id="__codelineno-8-144" name="__codelineno-8-144" href="#__codelineno-8-144"></a> <span class="n">content</span><span class="o">=</span><span class="n">body</span><span class="p">)</span>
|
||
<a id="__codelineno-8-145" name="__codelineno-8-145" href="#__codelineno-8-145"></a> <span class="k">try</span><span class="p">:</span>
|
||
<a id="__codelineno-8-146" name="__codelineno-8-146" href="#__codelineno-8-146"></a> <span class="n">resp</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">stream</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
<a id="__codelineno-8-147" name="__codelineno-8-147" href="#__codelineno-8-147"></a> <span class="k">except</span> <span class="n">httpx</span><span class="o">.</span><span class="n">ConnectError</span><span class="p">:</span>
|
||
<a id="__codelineno-8-148" name="__codelineno-8-148" href="#__codelineno-8-148"></a> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">aclose</span><span class="p">()</span>
|
||
<a id="__codelineno-8-149" name="__codelineno-8-149" href="#__codelineno-8-149"></a> <span class="k">return</span> <span class="n">JSONResponse</span><span class="p">({</span><span class="s2">"error"</span><span class="p">:</span> <span class="s2">"GPU not reachable"</span><span class="p">},</span> <span class="mi">502</span><span class="p">)</span>
|
||
<a id="__codelineno-8-150" name="__codelineno-8-150" href="#__codelineno-8-150"></a>
|
||
<a id="__codelineno-8-151" name="__codelineno-8-151" href="#__codelineno-8-151"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">stream</span><span class="p">():</span>
|
||
<a id="__codelineno-8-152" name="__codelineno-8-152" href="#__codelineno-8-152"></a> <span class="k">async</span> <span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">aiter_raw</span><span class="p">():</span>
|
||
<a id="__codelineno-8-153" name="__codelineno-8-153" href="#__codelineno-8-153"></a> <span class="k">yield</span> <span class="n">chunk</span>
|
||
<a id="__codelineno-8-154" name="__codelineno-8-154" href="#__codelineno-8-154"></a> <span class="k">await</span> <span class="n">resp</span><span class="o">.</span><span class="n">aclose</span><span class="p">()</span>
|
||
<a id="__codelineno-8-155" name="__codelineno-8-155" href="#__codelineno-8-155"></a> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">aclose</span><span class="p">()</span>
|
||
<a id="__codelineno-8-156" name="__codelineno-8-156" href="#__codelineno-8-156"></a>
|
||
<a id="__codelineno-8-157" name="__codelineno-8-157" href="#__codelineno-8-157"></a> <span class="k">return</span> <span class="n">StreamingResponse</span><span class="p">(</span><span class="n">stream</span><span class="p">(),</span> <span class="n">status_code</span><span class="o">=</span><span class="n">resp</span><span class="o">.</span><span class="n">status_code</span><span class="p">,</span>
|
||
<a id="__codelineno-8-158" name="__codelineno-8-158" href="#__codelineno-8-158"></a> <span class="n">headers</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">headers</span><span class="p">),</span>
|
||
<a id="__codelineno-8-159" name="__codelineno-8-159" href="#__codelineno-8-159"></a> <span class="n">media_type</span><span class="o">=</span><span class="n">resp</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"content-type"</span><span class="p">))</span>
|
||
<a id="__codelineno-8-160" name="__codelineno-8-160" href="#__codelineno-8-160"></a>
|
||
<a id="__codelineno-8-161" name="__codelineno-8-161" href="#__codelineno-8-161"></a>
|
||
<a id="__codelineno-8-162" name="__codelineno-8-162" href="#__codelineno-8-162"></a><span class="nd">@app</span><span class="o">.</span><span class="n">api_route</span><span class="p">(</span><span class="s2">"/status"</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">"GET"</span><span class="p">])</span>
|
||
<a id="__codelineno-8-163" name="__codelineno-8-163" href="#__codelineno-8-163"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">status</span><span class="p">():</span>
|
||
<a id="__codelineno-8-164" name="__codelineno-8-164" href="#__codelineno-8-164"></a> <span class="k">try</span><span class="p">:</span>
|
||
<a id="__codelineno-8-165" name="__codelineno-8-165" href="#__codelineno-8-165"></a> <span class="n">scw_state</span> <span class="o">=</span> <span class="k">await</span> <span class="n">_instance_state</span><span class="p">()</span>
|
||
<a id="__codelineno-8-166" name="__codelineno-8-166" href="#__codelineno-8-166"></a> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||
<a id="__codelineno-8-167" name="__codelineno-8-167" href="#__codelineno-8-167"></a> <span class="n">scw_state</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span>
|
||
<a id="__codelineno-8-168" name="__codelineno-8-168" href="#__codelineno-8-168"></a> <span class="k">return</span> <span class="p">{</span><span class="s2">"instance"</span><span class="p">:</span> <span class="n">scw_state</span><span class="p">,</span> <span class="s2">"proxy_up"</span><span class="p">:</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">],</span>
|
||
<a id="__codelineno-8-169" name="__codelineno-8-169" href="#__codelineno-8-169"></a> <span class="s2">"idle_s"</span><span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"last_activity"</span><span class="p">])</span> <span class="k">if</span> <span class="n">_state</span><span class="p">[</span><span class="s2">"up"</span><span class="p">]</span> <span class="k">else</span> <span class="kc">None</span><span class="p">}</span>
|
||
<a id="__codelineno-8-170" name="__codelineno-8-170" href="#__codelineno-8-170"></a>
|
||
<a id="__codelineno-8-171" name="__codelineno-8-171" href="#__codelineno-8-171"></a>
|
||
<a id="__codelineno-8-172" name="__codelineno-8-172" href="#__codelineno-8-172"></a><span class="nd">@app</span><span class="o">.</span><span class="n">api_route</span><span class="p">(</span><span class="s2">"/{path:path}"</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">"GET"</span><span class="p">,</span><span class="s2">"POST"</span><span class="p">,</span><span class="s2">"PUT"</span><span class="p">,</span><span class="s2">"DELETE"</span><span class="p">,</span><span class="s2">"OPTIONS"</span><span class="p">,</span><span class="s2">"PATCH"</span><span class="p">])</span>
|
||
<a id="__codelineno-8-173" name="__codelineno-8-173" href="#__codelineno-8-173"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">comfyui_proxy</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
|
||
<a id="__codelineno-8-174" name="__codelineno-8-174" href="#__codelineno-8-174"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">_proxy</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">GPU_HOST</span><span class="p">,</span> <span class="n">COMFYUI_PORT</span><span class="p">)</span>
|
||
</code></pre></div>
|
||
<h3 id="aigpu-proxydockerfile"><code>ai/gpu-proxy/Dockerfile</code><a class="headerlink" href="#aigpu-proxydockerfile" title="Permanent link">¶</a></h3>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="k">FROM</span><span class="w"> </span><span class="s">python:3.12-slim</span>
|
||
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">RUN</span><span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>fastapi<span class="w"> </span>uvicorn<span class="w"> </span>httpx
|
||
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="k">COPY</span><span class="w"> </span>proxy.py<span class="w"> </span>/app/proxy.py
|
||
<a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/app</span>
|
||
<a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="k">EXPOSE</span><span class="w"> </span><span class="s">8190 8191</span>
|
||
<a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="k">CMD</span><span class="w"> </span><span class="p">[</span><span class="s2">"uvicorn"</span><span class="p">,</span><span class="w"> </span><span class="s2">"proxy:app"</span><span class="p">,</span><span class="w"> </span><span class="s2">"--host"</span><span class="p">,</span><span class="w"> </span><span class="s2">"0.0.0.0"</span><span class="p">,</span><span class="w"> </span><span class="s2">"--port"</span><span class="p">,</span><span class="w"> </span><span class="s2">"8190"</span><span class="p">]</span>
|
||
</code></pre></div>
|
||
<hr />
|
||
<h2 id="step-5-wire-up-nuc-services">Step 5 — Wire up NUC services<a class="headerlink" href="#step-5-wire-up-nuc-services" title="Permanent link">¶</a></h2>
|
||
<p>Add to <code>ai/.env</code>:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="nv">SCW_SECRET_KEY</span><span class="o">=</span><your-scaleway-api-key>
|
||
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="nv">SCW_PROJECT_ID</span><span class="o">=</span><your-project-id>
|
||
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="nv">SCW_INSTANCE_ID</span><span class="o">=</span><instance-id-from-step-2>
|
||
</code></pre></div></p>
|
||
<p>In <code>ai/lobehub.yml</code>:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">'COMFYUI_BASE_URL=http://gpu-proxy:8190'</span>
|
||
</code></pre></div></p>
|
||
<p>In <code>ai/mcp-gateway/server.py</code> (SERVERS dict):
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="s2">"comfyui"</span><span class="p">:</span> <span class="p">{</span>
|
||
<a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a> <span class="s2">"static"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
|
||
<a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a> <span class="s2">"upstream"</span><span class="p">:</span> <span class="s2">"http://gpu-proxy:8190"</span><span class="p">,</span>
|
||
<a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a> <span class="s2">"group"</span><span class="p">:</span> <span class="s2">"image"</span><span class="p">,</span>
|
||
<a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a><span class="p">},</span>
|
||
</code></pre></div></p>
|
||
<p>For Immich ML (optional), add to <code>immich/docker-compose.yml</code>:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="nt">environment</span><span class="p">:</span>
|
||
<a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">IMMICH_MACHINE_LEARNING_URL=http://gpu-proxy:8192</span><span class="w"> </span><span class="c1"># add a third port for ML</span>
|
||
</code></pre></div></p>
|
||
<hr />
|
||
<h2 id="step-6-deploy">Step 6 — Deploy<a class="headerlink" href="#step-6-deploy" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="c1"># Deploy the proxy</span>
|
||
<a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a><span class="nb">cd</span><span class="w"> </span>/opt/stacks/ai/gpu-proxy
|
||
<a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a>docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>-d
|
||
<a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a>
|
||
<a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a><span class="c1"># Restart LobeChat and MCP gateway to pick up new env</span>
|
||
<a id="__codelineno-14-6" name="__codelineno-14-6" href="#__codelineno-14-6"></a><span class="nb">cd</span><span class="w"> </span>/opt/stacks/ai
|
||
<a id="__codelineno-14-7" name="__codelineno-14-7" href="#__codelineno-14-7"></a>docker<span class="w"> </span>compose<span class="w"> </span>-f<span class="w"> </span>lobehub.yml<span class="w"> </span>up<span class="w"> </span>-d<span class="w"> </span>--force-recreate<span class="w"> </span>lobe
|
||
<a id="__codelineno-14-8" name="__codelineno-14-8" href="#__codelineno-14-8"></a><span class="nb">cd</span><span class="w"> </span>mcp-gateway<span class="w"> </span><span class="o">&&</span><span class="w"> </span>docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>-d<span class="w"> </span>--force-recreate<span class="w"> </span>mcp-gateway
|
||
</code></pre></div>
|
||
<h3 id="what-the-user-experience-looks-like">What the user experience looks like<a class="headerlink" href="#what-the-user-experience-looks-like" title="Permanent link">¶</a></h3>
|
||
<ol>
|
||
<li>Open LobeChat, generate an image → first request triggers auto-start</li>
|
||
<li>"Starting GPU…" — ComfyUI returns a brief wait (up to 90 s cold start)</li>
|
||
<li>Images generate normally; the proxy keeps the instance alive</li>
|
||
<li>After 45 min with no requests → instance stops automatically</li>
|
||
<li><code>/status</code> endpoint on port 8190: <code>{"instance":"stopped","proxy_up":false}</code></li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="quick-start-stop-scripts">Quick-start / stop scripts<a class="headerlink" href="#quick-start-stop-scripts" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="c1"># /usr/local/bin/nuclide-gpu (NUC helper)</span>
|
||
<a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="c1">#!/bin/bash</span>
|
||
<a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a><span class="nv">ZONE</span><span class="o">=</span>fr-par-2
|
||
<a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a><span class="nv">ID</span><span class="o">=</span><span class="k">$(</span>docker<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>gpu-proxy<span class="w"> </span>env<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>SCW_INSTANCE_ID<span class="w"> </span><span class="p">|</span><span class="w"> </span>cut<span class="w"> </span>-d<span class="o">=</span><span class="w"> </span>-f2<span class="k">)</span>
|
||
<a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a><span class="k">case</span><span class="w"> </span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span><span class="w"> </span><span class="k">in</span>
|
||
<a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a><span class="w"> </span>start<span class="o">)</span><span class="w"> </span>scw<span class="w"> </span>instance<span class="w"> </span>server<span class="w"> </span>action<span class="w"> </span><span class="nv">action</span><span class="o">=</span>poweron<span class="w"> </span>server-id<span class="o">=</span><span class="nv">$ID</span><span class="w"> </span><span class="nv">zone</span><span class="o">=</span><span class="nv">$ZONE</span><span class="w"> </span><span class="p">;;</span>
|
||
<a id="__codelineno-15-7" name="__codelineno-15-7" href="#__codelineno-15-7"></a><span class="w"> </span>stop<span class="o">)</span><span class="w"> </span>scw<span class="w"> </span>instance<span class="w"> </span>server<span class="w"> </span>action<span class="w"> </span><span class="nv">action</span><span class="o">=</span>poweroff<span class="w"> </span>server-id<span class="o">=</span><span class="nv">$ID</span><span class="w"> </span><span class="nv">zone</span><span class="o">=</span><span class="nv">$ZONE</span><span class="w"> </span><span class="p">;;</span>
|
||
<a id="__codelineno-15-8" name="__codelineno-15-8" href="#__codelineno-15-8"></a><span class="w"> </span>status<span class="o">)</span><span class="w"> </span>curl<span class="w"> </span>-s<span class="w"> </span>http://localhost:8190/status<span class="w"> </span><span class="p">|</span><span class="w"> </span>python3<span class="w"> </span>-m<span class="w"> </span>json.tool<span class="w"> </span><span class="p">;;</span>
|
||
<a id="__codelineno-15-9" name="__codelineno-15-9" href="#__codelineno-15-9"></a><span class="w"> </span>*<span class="o">)</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Usage: nuclide-gpu start|stop|status"</span><span class="w"> </span><span class="p">;;</span>
|
||
<a id="__codelineno-15-10" name="__codelineno-15-10" href="#__codelineno-15-10"></a><span class="k">esac</span>
|
||
</code></pre></div>
|
||
<hr />
|
||
<h2 id="scaleway-firewall-security-groups">Scaleway firewall (security groups)<a class="headerlink" href="#scaleway-firewall-security-groups" title="Permanent link">¶</a></h2>
|
||
<p>On the Scaleway instance, only expose WireGuard. All services bind to <code>10.200.0.1</code> (WireGuard IP):</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a>ufw<span class="w"> </span>default<span class="w"> </span>deny<span class="w"> </span>incoming
|
||
<a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>ufw<span class="w"> </span>allow<span class="w"> </span><span class="m">51820</span>/udp<span class="w"> </span><span class="c1"># WireGuard from anywhere</span>
|
||
<a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a>ufw<span class="w"> </span>allow<span class="w"> </span>from<span class="w"> </span><span class="m">10</span>.200.0.0/24<span class="w"> </span><span class="c1"># full access over tunnel</span>
|
||
<a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a>ufw<span class="w"> </span><span class="nb">enable</span>
|
||
</code></pre></div>
|
||
<hr />
|
||
<h2 id="model-storage-layout-on-the-200-gb-volume">Model storage layout (on the 200 GB volume)<a class="headerlink" href="#model-storage-layout-on-the-200-gb-volume" title="Permanent link">¶</a></h2>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a>/mnt/models/
|
||
<a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a>├── checkpoints/ # FLUX.1-dev, SDXL, etc.
|
||
<a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a>├── vae/
|
||
<a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a>├── loras/
|
||
<a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a>├── controlnet/
|
||
<a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a>├── ollama/ # Ollama model blobs
|
||
<a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a>└── upscale_models/
|
||
</code></pre></div>
|
||
<p>FLUX.1-dev (FP16): ~24 GB<br />
|
||
FLUX.1-schnell (NF4): ~8 GB<br />
|
||
Ollama llama3:70b (Q4): ~40 GB — fits alongside FLUX on 200 GB with room for LoRAs.</p>
|
||
<p>To pre-download models after first boot:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>ssh<span class="w"> </span>root@10.200.0.1<span class="w"> </span><span class="c1"># via WireGuard</span>
|
||
<a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>docker<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>comfyui<span class="w"> </span>python3<span class="w"> </span>-c<span class="w"> </span><span class="s2">"</span>
|
||
<a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="s2">from huggingface_hub import hf_hub_download</span>
|
||
<a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a><span class="s2">hf_hub_download('black-forest-labs/FLUX.1-dev', 'flux1-dev.safetensors',</span>
|
||
<a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a><span class="s2"> local_dir='/root/ComfyUI/models/checkpoints')</span>
|
||
<a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a><span class="s2">"</span>
|
||
</code></pre></div></p>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</article>
|
||
</div>
|
||
|
||
|
||
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
||
</div>
|
||
|
||
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
|
||
Back to top
|
||
</button>
|
||
|
||
</main>
|
||
|
||
<footer class="md-footer">
|
||
|
||
<div class="md-footer-meta md-typeset">
|
||
<div class="md-footer-meta__inner md-grid">
|
||
<div class="md-copyright">
|
||
|
||
|
||
Made with
|
||
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
||
Material for MkDocs
|
||
</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
</div>
|
||
<div class="md-dialog" data-md-component="dialog">
|
||
<div class="md-dialog__inner md-typeset"></div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["navigation.tabs", "navigation.sections", "navigation.expand", "navigation.top", "search.highlight", "search.suggest", "content.code.copy"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
|
||
|
||
|
||
<script src="../../assets/javascripts/bundle.79ae519e.min.js"></script>
|
||
|
||
|
||
</body>
|
||
</html> |