Telepítsen egy Privát Hermes Ügynököt a Render-en biztonságosan Pulumi, Modal és Tailscale segítségével.
Megosztás
Összefoglalót olvas. A teljes tartalom itt érhető el: pulumi.com.
A személyes AI ügynökök ebben az évben robbantak be. Az OpenClaw néhány hónap alatt átlépte a 100 000 GitHub csillagos szintet, és a saját asszisztens önálló hosztolása a hobbi trükktől sok fejlesztő által használt módszerré vált. Írtam arról, hogyan lehet azokat az "ételeket" az AWS-en vagy Hetzneren telepíteni, amikor mindenhol jelen voltak. Az, amire most váltanak az emberek, a Hermes, a Nous Research nyílt forráskódú futtatási környezete, és ez is gyorsan elterjedt. Az ok minden "Nyugtalankodtam az OpenClaw-t a Hermes-re" szálban megjelenik: tényleg tanul, memória összegyűjtésével és saját készségeinek írásával halad előre, nem pedig egy statikus, ember által írt listához képest. Itt van az a rész, amit a bemutató videók kihagynak. A Hermes saját kódot ír és futtat, emberi jóváhagyás nélkül. Az a modell, amely képes kódot írni, végül egy rossz kódot is ír, és az egyetlen dolog a parancs és a hitelesítő adatai között a homokozó, amelyben működik. Ez az a doboz, amit nem akarunk a nyilvános interneten. A kutatók 175 000 nyitott Ollama szervert találtak 2026 elején, és a támadók a számításokhoz meghekkelték azokat, amiket találtak. A megoldás nem a jobb zár az ajtón. Hanem hogy ne legyen egyáltalán ajtó. Tehát ez a bejegyzés egy privát Hermes ügynököt telepít, mint egy Pulumi programot a Render, Modal és Tailscale rendszerekre. Az ügynök és a csevegő UI Render privát szolgáltatásként működik, nyilvános URL nélkül, a Tailscale a UI-t a tailneten helyezi el, és a Modal végrehajtja az ügynök kódját ideiglenes homokozókban. Egy pulumi felhasználás a telepítéshez, egy pulumi törlés az eltávolításhoz, körülbelül 50 dollár havonta. Nincs Makefile, nincsenek CLI menekülőutak, és őszinte rálátás a "nyilvános interneten semmi" néhány helyére, ahol még mindig szivárog. Mi a Hermes? A Hermes a Nous Research nyílt forráskódú, MIT-licencelt ügynök futtatási környezete. Folyamatosan fut egy szerveren, nem pedig egy böngésző fülben, és egy csevegő UI-n vagy egy üzenetküldő platformon, mint a Telegram, Discord, Slack vagy Signal keresztül beszélgethetsz vele. Néhány dolog miatt több mint egy chatbottá vált: Modell-agnosztikus. Bármely szolgáltatóra irányíthatod. Ez a telepítés OpenRouter-t használ, egy kulcs, ami több mint 400 modellt kezel a szolgáltatók között, automatikus átkapcsolással, ha az egyik leáll. Emlékezik az újraindítások között. A memória megmarad a lemezen, így idővel felhalmozza a kontextust, ahelyett, hogy minden ülést alaphelyzetbe állítana. Saját készségeit írja. Mikor egy feladaton dolgozik, elmentheti azt a megközelítést újrahasználható készségként, és legközelebb is használhatja. Önállóan ütemez. Egy beépített cron automatikusan végrehajtja az automatizálásokat időrend szerint, egyszerű nyelven megadva. Kódot homokozóban futtat. Amikor az ügynöknek kódot kell végrehajtania, azt egy izolált, ephemér tárolóra adja át, nem pedig a saját folyamata mellett futtatja. A felhőalapú asszisztenstől való eltérés a szokásos önálló hosztolási csere: a te infrastruktúrádon fut a te kulcsaiddal, és a beszélgetési előzmények és a memória a lemezedre marad. A "Hermes" itt a Nous Research ügynök futtatási környezete, nem a nevét megosztó Hermes nyelvi modellek családja. Az ügynök modell-agnosztikus, és a modell, amellyel beszél, egy külön választás, amit az OpenRouter-en keresztül végzel. Előfeltételek Mielőtt elkezdenéd, győződj meg arról, hogy: Pulumi CLI telepítve van és be van állítva Egy Pulumi Cloud fiók Egy Render fiók, egy API kulcs, és a munkaterület tulajdonosi azonosítója Egy Modal fiók és egy token pár (token azonosító és titkos) Egy OpenRouter API kulcs hitellel a fiókon Egy konténerregisztráció, ahova feltölthetsz; ez a bejegyzés a GitHub Container Registry-t (egy GHCR felhasználónév és token) használja Locális Docker (a kép építése helyi buildx motorral zajlik), vagy egy Docker-támogatott CI futtató Tailscale fiók HTTPS engedélyezve és újrafelhasználható hitelesítő kulcs Node.js 18+ (TypeScripthez) vagy Python 3.9+ (Pythonhoz), attól függően, hogy melyik nyelvet választod Ez a útmutató modelleket irányít az OpenRouter-en, de a Hermes más szolgáltatókkal is működik. A modell csak egy irányító karakterlánc, amit átadsz (itt gpt-5.5), tehát bármely modell, amit az OpenRouter támogat, működik, ha azt az egy értéket megváltoztatod. A Hermes architektúra megértése Távolítsuk el a műszerfal kattintásait, és az architektúra négy részből áll. Egy szabály irányít mindent: amit a nyilvános internet érinthet. ábra LR Felhasználó([Az eszközeid]) -->|"tailnet (WireGuard)"| TS["Tailscale<br/>privát mesh"] TS -->|"open-webui.<tailnet>.ts.net"| WebUI["Open WebUI<br/>(Render privát szolgáltatás,<br/>csatlakozott a tailnethez)"] WebUI -->|"privát hálózat<br/><hermes-slug>:8642"| Hermes["Hermes átjáró<br/>(Render privát szolgáltatás)"] Hermes -->|"Modal SDK futásidőben"| Modal["Modal homokozó<br/>izolált kód végrehajtás"] Hermes -->|modell hívások| OR["OpenRouter"] Komponens Port Leírás Hermes átjáró 8642 Titkokat és memóriát tárol, kommunikál a modellel, és Modal homokozókat hoz létre. A legveszélyesebb doboz, ezért nincs nyilvános URL. Open WebUI 8080 A csevegő előtér. Csatlakozik a tailnethez és eléri Hermest a Render privát hálózatán keresztül. Modal homokozó - Izolált, ephemér tároló az ügynök kódjának futtatásához. Tailscale - Egy privát WireGuard mesh, amely lehetővé teszi a UI elérhetőségét csak a saját eszközeid számára. Az ügynök, amely kódot tud futtatni és titkokat olvasni, soha nem érhető el az interneten, és a UI sem, amely előtte áll. Nincs bejövő forgalom bármely dobozban (a modellhez, a Modalhoz és a képtárhoz történő kimenő hívások még mindig átszelik az internetet, ahogyan kell). A "melyik doboz érheti el a melyiket" kódba történő kifejezés teszi a határt auditálhatóvá: a szabály a programban él, nem a műszerfalon. A négy rész tisztán kettéosztható: kettőt forrásként nyilvánítasz, és kettőt hitelesítéssel adsz át, és engeded őket működni. Réteg Hogyan biztosítod? Állapot Render szolgáltatások, lemezek, titkok hivatalos render-oss Terraform szolgáltató, összekötve Deklaratív, egy pulumi csomag hozzáadásával. Konténer képek @pulumi/docker-build Készült és feltöltve a pulumi felhasználás során. Nincs docker CLI. Modal homokozók semmi Nincs Terraform szolgáltató. Futási hitelesítő. Tailnet hozzáférés (Tailscale) semmi Nincs szolgáltató szükséges. Futási hitelesítő, mint a Modal. Két közül a négy réteg hitelesítő, nem forrás. Ezt a megkülönböztetést gyakran figyelmen kívül hagyják, és érdemes helyesen értelmezni: egy szolgáltató csak azt tudja kezelni, amit biztosít, és a Modal homokozó felállítása futásidőbeli tett, nem biztosított forrás. Minden rétegen visszatérünk rá. Az ESC beállítása a titkok kezelésére A Hermes telepítése sok hitelesítő kezelését jelenti: Render API kulcs, regisztrációs hitelesítők, az OpenRouter kulcs, a Modal token pár és a Tailscale hitelesítő kulcs. Nem akarod, hogy ezek keménykódoltak vagy szétszórva legyenek környezeti változók között. A Pulumi ESC (Környezetek, Titkok és Konfiguráció) biztonságosan tárolja őket, és közvetlenül továbbítja a Pulumi programodnak. Hozz létre egy új ESC környezetet: pulumi env init <your-org>/hermes-secrets Add meg a titkaidat a környezetbe: értékek: renderApiKey: fn::secret: "rnd_xxxxx" renderOwnerId: "tea-xxxxx" ghcrUser: "your-github-username" ghcrToken: fn::secret: "ghp_xxxxx" openrouterApiKey: fn::secret: "sk-or-xxxxx" modalTokenId: fn::secret: "ak-xxxxx" modalTokenSecret: fn::secret: "as-xxxxx" tailscaleAuthKey: fn::secret: "tskey-auth-xxxxx" tailnetDnsName: "tailxxxxx.ts.net" pulumiConfig: renderApiKey: ${renderApiKey} ownerId: ${renderOwnerId} ghcrUser: ${ghcrUser} ghcrToken: ${ghcrToken} openrouterApiKey: ${openrouterApiKey} modalTokenId: ${modalTokenId} modalTokenSecret: ${modalTokenSecret} tailscaleAuthKey: ${tailscaleAuthKey} tailnetDnsName: ${tailnetDnsName} A tailnet DNS neved megtalálásához lépj a Tailscale admin konzolra, nézd meg a DNS szakasz alatt, és találd meg a tailnet nevedet (pl. tailxxxxx.ts.net). Ez a domain utótag, amit a Tailscale hálózatod minden gépén használnak. Ezután hozz létre egy Pulumi.dev.yaml fájlt a projektedben a környezet hivatkozására: környezet: - <your-org>/hermes-secrets Ez távol tartja a titkaidat a kódalapból, és átadja őket a programnak a telepítéskor. A Modal token pár és a Tailscale hitelesítő kulcs sosem válik forrássá; közvetlenül, titkosított környezeti változókként haladnak át a szolgáltatásokon, amelyeknek szükségük van rájuk. A Render SDK generálása A Rendernek nincs elsődleges Pulumi szolgáltatója. Amit van, az egy hivatalos, karbantartott Terraform szolgáltató, és a Pulumi bármilyen Terraform szolgáltatót át tud alakítani egy típusos helyi SDK-vá, bármilyen Terraform szolgáltatóval: pulumi package add terraform-provider render-oss/render 1.8.0 Ez az egy parancs generál egy render SDK-t, amit úgy importálsz, mint bármely más csomagot, bármilyen nyelven, amelyikből a stacked van írva. Nincs közzétett @pulumi/render csomag és nincs beszállító, akire várni kell. Itt mutatkozik meg a szolgáltató térképének széle. A híd egy már létező Terraform szolgáltatót fed le, így működik a Renderhez. De a Modalnak nincs sehol Terraform szolgáltatója, így a pulumi package add terraform-provider modal-labs/modal semmit nem keres. Ez nem egy megkerülendő hiányosság. A Modal nem egy biztosított forrás itt; a Hermes a Modal SDK-n keresztül runtime üzemelés során hoz létre homokozókat, és a Pulumi egyetlen feladata a token pár tárolása és átadása. A Tailscale ugyanebbe a kategóriába tartozik: létezik egy Tailscale szolgáltató, de az a tailnet beállításait kezeli, nem pedig a konténer hálózatra helyezésének aktusát, ami egy futásidős feladat, ami a képben történik. Biztonság a Tailscale-lal A szokásos módja, hogy egy önálló hosztolt UI-t elérhetővé tegyél, hogy nyilvános hostnevet adsz neki, és egy identitáskaput helyezel előtte: egy SSO szolgáltató, egy hozzáférési politika, egy nyilvános DNS feljegyzés és egy tanúsítvány, amit folyamatosan meg kell újítani. A Tailscale mindent összeolvaszt semmiben, amit nyilvánossá tettél. Nincs kapu, amit be kellene zárni a nyilvános URL előtt, mivel nincs nyilvános URL. Az Open WebUI csatlakozik a tailnethez és csak a saját eszközeid válaszaira hallgat. Ez erősebb helyzet, mint egy nyilvános UI, amit egy bejelentkezés mögött helyezel el. Mivel nincs nyilvános URL, nincs is bejelentkezés, amit megerősíthetnél, és nincs tanúsítvány, amit megújíthatsz, és az Open WebUI csak a saját eszközeid válaszaira hallgat. A Tailscale az Open WebUI képen él, nem pedig a Pulumi programban. A kép hozzáadja a Tailscale-t és egy indítási pontot, amely elindítja a tailscaled-et felhasználói módban (a konténernek nincs /dev/net/tun), csatlakozik a tailnetedhez, és futtatja a tailscale serve-t, hogy elérhetővé tegye az Open WebUI-t. A serve HTTPS-zal publikál csak a tailnet hitelesített tagjainak, ahol a testvére tailscale funnel ugyanazt a portot tenné a nyilvános internetre, ami a lánc dizájnja elkerül. FROM ghcr.io/open-webui/open-webui:main-slim RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \ && curl -fsSL https://tailscale.com/install.sh | sh COPY entrypoint.sh /usr/local/bin/ts-entrypoint ENTRYPOINT ["/usr/local/bin/ts-entrypoint"] #!/usr/bin/env bash set -e PORT="${PORT:-8080}" mkdir -p /app/backend/data/tailscale # Felhasználói tér hálózat: egy konténernek nincs /dev/net/tun. Tartsd meg az állapotot a lemezen, hogy túlélje az újraindításokat, és accept-dns=false, hogy a Render DNS-e továbbra is megoldja a privát Hermes hostname-t. tailscaled --tun=userspace-networking --statedir=/app/backend/data/tailscale & n=0 until tailscale up --authkey="${TS_AUTHKEY}" --hostname="${TS_HOSTNAME}" --accept-dns=false; do n=$((n + 1)); [ "${n}" -ge 30 ] && { echo "tailnet join failed; check TS_AUTHKEY"; exit 1; } sleep 2 done tailscale serve --bg "${PORT}" # serve Open WebUI a tailneten HTTPS-en keresztül cd /app/backend && exec bash start.sh A TS_AUTHKEY környezeti változó a szolgáltatáson, amit az ESC-ből húzanak, az egyetlen dolog, amit a Pulumi hozzájárul; minden más a kép saját hálózatkezelését végzi. Van egy előfeltétel, ugyanaz, mint amit bármely Tailscale node szükséges a serve-hoz: engedélyezd a HTTPS-t a tailneted számára egyszer az admin konzolon, hogy tudjon tanúsítványt kapni. Használj újrafelhasználható hitelesítő kulcsot, mivel a szolgáltatás minden újratelepítéskor újra hitelesít, és a csatlakozási ciklusnak van egy határértéke, hogy egy halott kulcs 1 percen belül meghaljon, ne várakoztasson. Az újrafelhasználható hitelesítő kulcs generálásához: Lépj a Tailscale admin konzolra. Kattints az "Új hitelesítő kulcs generálása" gombra. Engedélyezd az Újrafelhasználható lehetőséget, mivel a szolgáltatás minden újratelepítéskor újra hitelesít. Másold a hitelesítőt az ESC környezetedbe mint tailscaleAuthKey. Az ügynök telepítése Ez az a rész, amit egy Makefile általában kezel. Két privát szolgáltatás, két lemez, minden titok egy titkos környezeti változó, és mindkét kép építve és feltöltve a pulumi felhasználása során, amely létrehozza a szolgáltatásokat. Nincsenek CLI hívások, bár az építés még mindig helyi Docker motorról történik a buildx-en keresztül: a docker hívás eltűnt, a démon, amivel beszél, nem, így a pulumi upnak szüksége van a Docker futására. Hozz létre egy új Pulumi projektet (válaszd ki a kedvenc nyelved; a kísérő repo mindhárom nyelvet tartalmaz): mkdir hermes-agent-pulumi && cd hermes-agent-pulumi pulumi new typescript Telepítsd a függőségeket és generáld a Render SDK-t: npm install @pulumi/docker-build @pulumi/random pulumi package add terraform-provider render-oss/render 1.8.0 Mindkét szolgáltatásnak a 2 GB Standard terv szükséges. Az átjáró és az Open WebUI mindkettő kimeríti a memóriát az 512 MB Starter-en és OOM induláskor. Két tény tisztán teszi ezt. A Render környezeti változói titkosítva maradnak pihenés közben, így egy titok csak egy környezeti változó, külön forrás nélkül. És a @pulumi/docker-build a pulumi felhasználás során épít és feltölt egy képet egy beágyazott buildx segítségével, így a képkibocsátási folyamat is deklaratív. A Render ezután a feltöltött képet az elágazott digest alapján húzza. A teljes program Először a Hermes: egy privát Render szolgáltatás, nyilvános URL nélkül, egy lemez a memória tárolására és minden titok titkos környezeti változóként. A megosztott viszonyítási kulcs állapotban generálódik random.RandomBytes segítségével, a tiszta helyettesítése az openssl rand -base64 32-nek; a Modal token pár és az OpenRouter kulcs a konfigurációból vagy Pulumi ESC-éből származik. A Rendernek nincs port mezője, tehát a Hermes 0.0.0.0:8642-re köt, és az Open WebUI az szolgáltatás írásvédett slugján keresztül éri el. Az Open WebUI szinte tükörkép, szintén privát, kivéve, hogy a képe csatlakozik a tailnetedhez (a taild-a indítási pontjából a korábbi részben) és az üzemeltetési környezeti változókat hordozza, amelyek karban tartják: nincsenek helyi beágyazott modellek, és az ENABLE_PERSISTENT_CONFIG=false, így a konfigurációd mindig nyer a régi másolatokkal szemben az adatbázisában. Egy render.Provider átviszi a renderApiKey-t és ownerId-t minden Render forrásba. Íme az egész program, másolásra kész, mint index.ts (vagy __main__.py, vagy Pulumi.yaml): import * as pulumi from "@pulumi/pulumi"; import * as dockerbuild from "@pulumi/docker-build"; import * as random from "@pulumi/random"; // Helyi SDK generálva: pulumi package add terraform-provider render-oss/render 1.8.0 // (nincs @pulumi/render publikálva; az SDK az hivatalos Render szolgáltatóból van átkonvertálva). import * as render from "@pulumi/render"; const cfg = new pulumi.Config(); // --------------------------------------------------------------------------- // Konfiguráció. Nem titkos értékek `pulumi config set`, titkok `pulumi config set --secret` vagy egy Pulumi ESC környezet segítségével (lásd README). // A Render szolgáltató olvassa a renderApiKey/renderOwnerId (vagy RENDER_API_KEY/RENDER_OWNER_ID). // --------------------------------------------------------------------------- const region = cfg.get("renderRegion") ?? "oregon"; const modelDefault = cfg.get("modelDefault") ?? "gpt-5.5"; // Konténer regisztráció, ahova a képeket feltöltjük és ahonnan a Render húz (itt GHCR). const ghcrUser = cfg.require("ghcrUser"); const ghcrToken = cfg.requireSecret("ghcrToken"); // GHCR PAT írás:csomagok // Hosszú élettartamú titkok, amiket te szolgáltatsz (irányítószerződés által kiadva). Tartsd a konfigurációban vagy ESC-ben. const modalTokenId = cfg.requireSecret("modalTokenId"); const modalTokenSecret = cfg.requireSecret("modalTokenSecret"); const openrouterApiKey = cfg.requireSecret("openrouterApiKey"); // Tailscale: az egyetlen "kapu". Az Open WebUI csatlakozik a tailnetedhez és elérhető // https://<hostname>.<tailnet>.ts.net a saját eszközeid számára csak — soha nem nyilvános. // Engedélyezd egyszer a HTTPS-t a Tailscale admin konzolon, hogy a `tailscale serve` kapjon egy tanúsítványt. const tailscaleAuthKey = cfg.requireSecret("tailscaleAuthKey"); const tailnetDnsName = cfg.require("tailnetDnsName"); // pl. tailc6fb4e.ts.net const webuiHostname = "open-webui"; const webuiTailnetUrl = `https://${webuiHostname}.${tailnetDnsName}`; // Render szolgáltató hitelesítés (az ESC-ből: pulumiConfig.renderApiKey / pulumiConfig.renderOwnerId). const renderProvider = new render.Provider("render", { apiKey: cfg.requireSecret("renderApiKey"), ownerId: cfg.require("renderOwnerId"), }); // --------------------------------------------------------------------------- // Titkok generálva állapotban (az in-IaC helyettesítés az `openssl rand -base64 32`). // A megosztott viszonyítási kulcs hitelesíti az Open WebUI -> Hermest; mindkét szolgáltatásban szerepel. // --------------------------------------------------------------------------- const sharedKey = new random.RandomBytes("hermes-shared-key", { length: 32 }); const webuiSecretKey = new random.RandomBytes("webui-secret-key", { length: 32 }); // --------------------------------------------------------------------------- // Építsd és töltsd fel a két képet a `pulumi up` során (nincs docker CLI; a szolgáltató // beágyazza a buildx-et). A Render ezután a digest-alapján húzza őket. // --------------------------------------------------------------------------- const registryAuth = [{ address: "ghcr.io", username: ghcrUser, password: ghcrToken }]; const hermesImage = new dockerbuild.Image("hermes-image", { context: { location: "./hermes" }, dockerfile: { location: "./hermes/Dockerfile" }, platforms: ["linux/amd64"], tags: [pulumi.interpolate`ghcr.io/${ghcrUser}/hermes-agent:latest`], push: true, registries: registryAuth, }); const webuiImage = new dockerbuild.Image("webui-image", { context: { location: "./openwebui" }, dockerfile: { location: "./openwebui/Dockerfile" }, platforms: ["linux/amd64"], tags: [pulumi.interpolate`ghcr.io/${ghcrUser}/open-webui:latest`], push: true, registries: registryAuth, }); // Hitelesítő, amit a Render használ a privát GHCR képek húzásához. const ghcrCredential = new render.RegistryCredential("ghcr", { name: "ghcr", registry: "GITHUB", username: ghcrUser, authToken: ghcrToken, }, { provider: renderProvider }); // --------------------------------------------------------------------------- // Hermes: egy PRIVÁT Render szolgáltatás. Nincs nyilvános URL; elérhető kizárólag Render privát hálózatán. // Egy lemez tárolja a memóriáját és a munkaterületét. A környezeti értékek // titkosítva vannak pihenés közben, ami az, ahogy a titkok a Renderen futnak (nincs külön zászló). // --------------------------------------------------------------------------- const hermes = new render.PrivateService("hermes-agent", { name: "hermes-agent", plan: "standard", // 2 GB; az átjáró OOM-ra áll a starter 512 MB-ján region: region, runtimeSource: { // A Render a nyers tárolót szeretné az imageUrl-ben; a tag/digest a saját mezőikbe kerülnek. image: { imageUrl: pulumi.interpolate`ghcr.io/${ghcrUser}/hermes-agent`, digest: hermesImage.digest, registryCredentialId: ghcrCredential.id, }, }, disk: { name: "hermes-data", mountPath: "/opt/data", sizeGb: 5 }, envVars: { PORT: { value: "8642" }, API_SERVER_ENABLED: { value: "true" }, API_SERVER_HOST: { value: "0.0.0.0" }, API_SERVER_PORT: { value: "8642" }, API_SERVER_MODEL_NAME: { value: modelDefault }, // Automatikusan jóváhagyja az ügynök shell/terminál horgait (nincs TTY egy konténerben), // így kódot tud futtatni a Modal homokozóban interaktív prompt nélkül. HERMES_ACCEPT_HOOKS: { value: "1" }, // Titkok (titkosítva pihenés közben a Render-en): API_SERVER_KEY: { value: sharedKey.base64 }, OPENROUTER_API_KEY: { value: openrouterApiKey }, // A Modal egy futási hitelesítő, nem egy biztosított forrás: a Hermes // homokozókat hoz létre futásidőben ezzel a token párral. A Modal szolgáltató, nincs Modal CLI. MODAL_TOKEN_ID: { value: modalTokenId }, MODAL_TOKEN_SECRET: { value: modalTokenSecret }, }, }, { provider: renderProvider }); // Az Open WebUI eléri Hermest a Render által hozzárendelt belső hostname-jén (az írásvédett slug), nem a puszta szolgáltatásnevével. // Ugyanaz a régió + ugyanaz a munkaterület megosztja a hálózatot. const hermesApiBaseUrl = pulumi.interpolate`http://${hermes.slug}:8642/v1`; // --------------------------------------------------------------------------- // Open WebUI: szintén egy PRIVÁT Render szolgáltatás, de a konténer csatlakozik a tailnetedhez // (tailscaled felhasználói módban + `tailscale serve`), így elérheted // https://open-webui.<tailnet>.ts.net eszközeidről. Soha nem nyilvános; a kapu // a tailnet tagság. A hálózaton keresztül még mindig eléri Hermest Render privát hálózatán. // --------------------------------------------------------------------------- const webui = new render.PrivateService("open-webui", { name: "open-webui", plan: "standard", // 2 GB; Open WebUI OOM-ra áll a starter 512 MB-ján region: region, // meg kell egyeznie Hermessel a privát hálózati üzemeléshez runtimeSource: { image: { imageUrl: pulumi.interpolate`ghcr.io/${ghcrUser}/open-webui`, digest: webuiImage.digest, registryCredentialId: ghcrCredential.id, }, }, disk: { name: "openwebui-data", mountPath: "/app/backend/data", sizeGb: 5 }, envVars: { PORT: { value: "8080" }, // tailscale serve erre mutat; Open WebUI ehhez köti OPENAI_API_BASE_URL: { value: hermesApiBaseUrl }, ENABLE_OPENAI_API: { value: "true" }, ENABLE_OLLAMA_API: { value: "false" }, DEFAULT_MODELS: { value: modelDefault }, WEBUI_AUTH: { value: "true" }, WEBUI_URL: { value: webuiTailnetUrl }, // Csak a tailneten elérhető, így az első regisztráció admin lesz. ENABLE_LOGIN_FORM: { value: "true" }, ENABLE_SIGNUP: { value: "true" }, DEFAULT_USER_ROLE: { value: "admin" }, // Mindig alkalmazd a környezeti konfigurációt; különben az Open WebUI az első futás konfigurációt // tárolja az adatbázisában és figyelmen kívül hagyja a későbbi módosításokat. ENABLE_PERSISTENT_CONFIG: { value: "false" }, // Ne töltsön be helyi beágyazott/RAG modelleket (jelentős memória-megtakarítás; az ügynök a fejlődés). RAG_EMBEDDING_ENGINE: { value: "openai" }, BYPASS_EMBEDDING_AND_RETRIEVAL: { value: "true" }, OFFLINE_MODE: { value: "true" }, HF_HUB_OFFLINE: { value: "1" }, // Titkok (titkosítva pihenés közben): OPENAI_API_KEY: { value: sharedKey.base64 }, // megosztott viszony, hogy Hermest hívjuk WEBUI_SECRET_KEY: { value: webuiSecretKey.base64 }, // A Tailscale a konténert csatlakoztatja a tailnetedhez és az Open WebUI-t szolgáltatja rajta. TS_AUTHKEY: { value: tailscaleAuthKey }, TS_HOSTNAME: { value: webuiHostname }, }, }, { dependsOn: hermes, provider: renderProvider }); export const hermesInternalUrl = hermesApiBaseUrl; // Nyisd meg ezt bármely eszközön a tailneteden: export const openWebUiTailnetUrl = webuiTailnetUrl; import pulumi import pulumi_docker_build as docker_build import pulumi_random as random # Helyi SDK generálva: pulumi package add terraform-provider render-oss/render 1.8.0 # (nincs pulumi_render publikálva; az SDK az hivatalos Render szolgáltatóból van átkonvertálva). import pulumi_render as render cfg = pulumi.Config() # --------------------------------------------------------------------------- # Konfiguráció. Nem titkos értékek `pulumi config set`, titkok `pulumi config set --secret` vagy egy Pulumi ESC környezete segítségével (lásd README). # A Render szolgáltató olvassa a renderApiKey/renderOwnerId (vagy RENDER_API_KEY/RENDER_OWNER_ID). # --------------------------------------------------------------------------- region = cfg.get("renderRegion") or "oregon" model_default = cfg.get("modelDefault") or "gpt-5.5" # Konténer regisztráció, ahova a képeket feltöltjük és ahonnan a Render húz (itt GHCR). ghcr_user = cfg.require("ghcrUser") ghcr_token = cfg.require_secret("ghcrToken") # GHCR PAT írás:csomagok # Hosszú élettartamú titkok, amiket te szolgáltatsz (irányítószerződés által kiadva). Tartsd a konfigurációban vagy ESC-ben. modal_token_id = cfg.require_secret("modalTokenId") modal_token_secret = cfg.require_secret("modalTokenSecret") openrouter_api_key = cfg.require_secret("openrouterApiKey") # Tailscale: az egyetlen "kapu". Az Open WebUI csatlakozik a tailnetedhez és elérhető # https://<hostname>.<tailnet>.ts.net a saját eszközeid számára csak — soha nem nyilvános. # Engedélyezd egyszer a HTTPS-t a Tailscale admin konzolon, hogy a `tailscale serve` kapjon egy tanúsítványt. tailscale_auth_key = cfg.require_secret("tailscaleAuthKey") tailnet_dns_name = cfg.require("tailnetDnsName") # pl. tailc6fb4e.ts.net webui_hostname = "open-webui" webui_tailnet_url = f"https://{webui_hostname}.{tailnet_dns_name}" # Render szolgáltató hitelesítés (az ESC-ből: pulumiConfig.renderApiKey / pulumiConfig.renderOwnerId). render_provider = render.Provider( "render", api_key=cfg.require_secret("renderApiKey"), owner_id=cfg.require("renderOwnerId"), ) # --------------------------------------------------------------------------- # Titkok generálva állapotban (az in-IaC helyettesítés az `openssl rand -base64 32`). # A megosztott viszonyítási kulcs hitelesíti az Open WebUI -> Hermest; mindkét szolgáltatásban szerepel. # --------------------------------------------------------------------------- shared_key = random.RandomBytes("hermes-shared-key", length=32) webui_secret_key = random.RandomBytes("webui-secret-key", length=32) # --------------------------------------------------------------------------- # Építsd és töltsd fel a két képet a `pulumi up` során (nincs docker CLI; a szolgáltató # beágyazza a buildx-et). A Render ezután a digest-alapján húzza őket. # --------------------------------------------------------------------------- registry_auth = [{"address": "ghcr.io", "username": ghcr_user, "password": ghcr_token}] hermes_image = docker_build.Image( "hermes-image", context={"location": "./hermes"}, dockerfile={"location": "./hermes/Dockerfile"}, platforms=["linux/amd64"], tags=[pulumi.Output.concat("ghcr.io/", ghcr_user, "/hermes-agent:latest")], push=True, registries=registry_auth, ) webui_image = docker_build.Image( "webui-image", context={"location": "./openwebui"}, dockerfile={"location": "./openwebui/Dockerfile"}, platforms=["linux/amd64"], tags=[pulumi.Output.concat("ghcr.io/", ghcr_user, "/open-webui:latest")], push=True, registries=registry_auth, ) # Hitelesítő, amit a Render használ a privát GHCR képek húzásához. ghcr_credential = render.RegistryCredential( "ghcr", name="ghcr", registry="GITHUB", username=ghcr_user, auth_token=ghcr_token, opts=pulumi.ResourceOptions(provider=render_provider), ) # --------------------------------------------------------------------------- # Hermes: egy PRIVÁT Render szolgáltatás. Nincs nyilvános URL; elérhető kizárólag Render privát hálózatán. // Egy lemez tárolja a memóriáját és a munkaterületét. A környezeti változók // titkosítva vannak pihenés közben, ami az, ahogy a titkok a Renderen futnak (nincs külön zászló). # --------------------------------------------------------------------------- hermes = render.PrivateService( "hermes-agent", name="hermes-agent", plan="standard", // 2 GB; az átjáró OOM-ra áll a starter 512 MB-ján region=region, runtime_source={ "image": { "image_url": pulumi.Output.concat("ghcr.io/", ghcr_user, "/hermes-agent"), "digest": hermes_image.digest, "registry_credential_id": ghcr_credential.id, }, }, disk={"name": "hermes-data", "mount_path": "/opt/data", "size_gb": 5}, env_vars={ "PORT": {"value": "8642"}, "API_SERVER_ENABLED": {"value": "true"}, "API_SERVER_HOST": {"value": "0.0.0.0"}, "API_SERVER_PORT": {"value": "8642"}, "API_SERVER_MODEL_NAME": {"value": model_default}, // Automatikusan jóváhagyja az ügynök shell/terminál horgait (nincs TTY egy konténerben). // "HERMES_ACCEPT_HOOKS": {"value": "1"}, // Titkok (titkosítva pihenés közben a Render-en): // "API_SERVER_KEY": {"value": shared_key.base64}, // "OPENROUTER_API_KEY": {"value": openrouter_api_key}, // A Modal egy futási hitelesítő: Hermes // homokozókat hoz létre futásidőben ezzel a párral. // "MODAL_TOKEN_ID": {"value": modal_token_id}, // "MODAL_TOKEN_SECRET": {"value": modal_token_secret}, //}, opts=pulumi.ResourceOptions(provider=render_provider), // ) // Az Open WebUI eléri Hermest a Render által hozzárendelt belső hostname-n (az írásvédett slug). // hermes_api_base_url = pulumi.Output.concat("http://", hermes.slug, ":8642/v1") // --------------------------------------------------------------------------- // Open WebUI: szintén egy PRIVÁT Render szolgáltatás, // de a konténer csatlakozik a tailnetedhez // (tailscaled felhasználói módban + `tailscale serve`), így elérheted // https://open-webui.<tailnet>.ts.net eszközeidről. // A megoldás: // cosinting. // --------------------------------------------------------------------------- webui = render.PrivateService( "open-webui", name="open-webui", plan="standard", // 2 GB; Open WebUI OOM-ra áll a starter 512 MB-ján region=region, // meg kell egyeznie Hermessel a privát hálózati üzemeléshez runtime_source={ "image": { "image_url": pulumi.Output.concat("ghcr.io/", ghcr_user, "/open-webui"), "digest": webui_image.digest, "registry_credential_id": ghcr_credential.id, }, }, disk={"name": "openwebui-data", "mount_path": "/app/backend/data", "size_gb": 5}, env_vars={ "PORT": {"value": "8080"}, // tailscale serve erre mutat; Open WebUI ehhez köti "OPENAI_API_BASE_URL": {"value": hermes_api_base_url}, // Engedélyezd az admin szolgáltatásokat, mivel増l nehezen kezelhetők a Tailscale osztályosságain. // "ENABLE_OPENAI_API": {"value": "true"}, // "ENABLE_OLLAMA_API": {"value": "false"}, // "DEFAULT_MODELS": {"value": model_default}, // ha és ha nem // "WEBUI_AUTH": {"value": "true"}, // "WEBUI_URL": {"value": webui_tailnet_url}, // "ENABLE_LOGIN_FORM": {"value": "true"}, // "ENABLE_SIGNUP": {"value": "true"}, // "DEFAULT_USER_ROLE": {"value": "admin"}, // "ENABLE_PERSISTENT_CONFIG": {"value": "false"}, // "RAG_EMBEDDING_ENGINE": {"value": "openai"}, // "BYPASS_EMBEDDING_AND_RETRIEVAL": {"value": "true"}, // "OFFLINE_MODE": {"value": "true"}, // "HF_HUB_OFFLINE": {"value": "1"}, // "OPENAI_API_KEY": {"value": shared_key.base64}, // "WEBUI_SECRET_KEY": {"value": webui_secret_key.base64}, // "TS_AUTHKEY": {"value": tailscale_auth_key}, // "TS_HOSTNAME": {"value": webui_hostname}, // }, opts=pulumi.ResourceOptions(depends_on=[hermes], provider=render_provider), // ) // export hermes_internal_url = hermes_api_base_url // export open_web_ui_tailnet_url = webui_tailnet_url resources: # Render provider auth (from config). render: type: pulumi:providers:render properties: api_key: ${renderApiKey} owner_id: ${renderOwnerId} # Titkok generálva állapotban. hermes_shared_key: type: random:RandomBytes properties: length: 32 webui_secret_key: type: random:RandomBytes properties: length: 32 # Build + push both images during `pulumi up` (no docker CLI). hermes-image: type: docker-build:Image properties: context: location: ./hermes dockerfile: location: ./hermes/Dockerfile platforms: [linux/amd64] tags: - ghcr.io/${ghcrUser}/hermes-agent:latest push: true registries: ${registryAuth} webui-image: type: docker-build:Image properties: context: location: ./openwebui dockerfile: location: ./openwebui/Dockerfile platforms: [linux/amd64] tags: - ghcr.io/${ghcrUser}/open-webui:latest push: true registries: ${registryAuth} # Credential Render uses to pull the private GHCR images. ghcr: type: render:RegistryCredential properties: name: ghcr registry: GITHUB username: ${ghcrUser} authToken: ${ghcrToken} options: provider: ${render} # Hermes: egy PRIVÁT Render szolgáltatás. Nincs nyilvános URL; titkos környezeti változók, amelyeket a titkos mechanizmus. hermes-agent: type: render:PrivateService properties: name: hermes-agent plan: standard # 2 GB; az átjáró OOM-ra áll a starter 512 MB region: ${renderRegion} runtimeSource: image: imageUrl: ghcr.io/${ghcrUser}/hermes-agent digest: ${hermes-image.digest} registryCredentialId: ${ghcr.id} disk: name: hermes-data mountPath: /opt/data sizeGb: 5 envVars: PORT: { value: "8642" } API_SERVER_ENABLED: { value: "true" } API_SERVER_HOST: { value: "0.0.0.0" } API_SERVER_PORT: { value: "8642" } API_SERVER_MODEL_NAME: { value: "${modelDefault}" } HERMES_ACCEPT_HOOKS: { value: "1" } API_SERVER_KEY: { value: "${hermes-shared-key.base64}" } OPENROUTER_API_KEY: { value: "${openrouterApiKey}" } MODAL_TOKEN_ID: { value: "${modalTokenId}" } MODAL_TOKEN_SECRET: { value: "${modalTokenSecret}" } options: provider: ${render} # Open WebUI: is a PRIVATE Render service, joined to your tailnet by its frozen. open-webui: type: render:PrivateService properties: name: open-webui plan: standard # 2 GB; Open WebUI OOM-ra áll a starter 512 MB region: ${renderRegion} # must match Hermes for private networking runtimeSource: image: imageUrl: ghcr.io/${ghcrUser}/open-webui digest: ${webui-image.digest} registryCredentialId: ${ghcr.id} disk: name: openwebui-data mountPath: /app/backend/data sizeGb: 5 envVars: PORT: { value: "8080" } OPENAI_API_BASE_URL: { value: "${hermesApiBaseUrl}" } ENABLE_OPENAI_API: { value: "true" } ENABLE_OLLAMA_API: { value: "false" } DEFAULT_MODELS: { value: "${modelDefault}" } WEBUI_AUTH: { value: "true" } WEBUI_URL: { value: "${webuiTailnetUrl}" } ENABLE_LOGIN_FORM: { value: "true" } ENABLE_SIGNUP: { value: "true" } DEFAULT_USER_ROLE: { value: "admin" } ENABLE_PERSISTENT_CONFIG: { value: "false" } RAG_EMBEDDING_ENGINE: { value: "openai" } BYPASS_EMBEDDING_AND_RETRIEVAL: { value: "true" } OFFLINE_MODE: { value: "true" } HF_HUB_OFFLINE: { value: "1" } OPENAI_API_KEY: { value: "${hermes-shared-key.base64}" } WEBUI_SECRET_KEY: { value: "${webui-secret-key.base64}" } TS_AUTHKEY: { value: "${tailscaleAuthKey}" } TS_HOSTNAME: { value: "open-webui" } options: provider: ${render} dependsOn: - ${hermes-agent} outputs: hermesInternalUrl: ${hermesApiBaseUrl} # Nyisd meg ezt bármilyen eszközről a tailneteden: openWebUiTailnetUrl: ${webuiTailnetUrl} A dobozok nem lettek kiadva az internetre. Ugyanaz a kód, plusz a Dockerfile-ok és a Tailscale belépési pontja a kísérő repo-ban található: github.com/dirien/hermes-agent-pulumi Költség Két részlet formálja a számlát. A gazdagép a Render ingyenes Hobby munkatérben indul, de egy privát szolgáltatás tartós lemezzel futó fizetős számításon működik, így egy kártya szükséges, amint hozzáadod őket. Nincs ingyenes szintű változata ennek az architekturának. Mindkét szolgáltatás a 2 GB Standard tervet igényli, mivel az átjáró és az Open WebUI mindkét esetben OOM-ra áll az 512 MB Starter-en. Hermes átjáró Open WebUI Terv Standard (2 GB) Standard (2 GB) Számítás ~$25/hó ~$25/hó Lemez 5 GB 5 GB Nyilvános URL nincsenek nincsenek (csak tailnet) Ez a gazdagép körülbelül 50 dollár/hónap, összenőve a hasonlóan kezelt beállításokkal. A Modal és az OpenRouter használat alapján merülnek fel, tehát a teljes költség a ügynök munkája alapján _nyomon követhető, nem pedig egy lapos összeg. A Tailscale ingyenes egy személyes tailnethez, tehát a privát átjáró ehhez nem ad semmit. A tartós lemez minden szolgáltatást egyetlen példányhoz köt, így nincs automatikus skálázás, és egy újratelepítés néhány másodpercnyi érzékelési kiesést hoz létre, míg a régi példány elengedi a lemezt. Egyetlen felhasználós ügynöknél ez egy megfelelő kompromisszum, és ez az oka annak, hogy "állítsd fel egy második régióban" egy konfigurációmásolás lépés, nem pedig élő átváltás. Az OpenRouter aktivitási kezelőfelület: 56 kérelem és 738K token a gpt-5.5 használatból, mind egy kulcson keresztül irányítva. A telepítés futtatása A Pulumi.dev.yaml-ban hivatkozott ESC környezettel telepítheted: pulumi up Ez generálja a Render SDK erőforrásait, felépít és feltölt mindkét képet a buildx-en keresztül, és létrehozza a két privát szolgáltatást a diszkjeikkel és titkosított környezeti változóikkal, mindezt egy lépésben, Docker CLI nélkül és minden titkos importálás nélkül, amely egy szkriptben el van rejtve. Amikor befejeződik, mindkét szolgáltatás megjelenik a Render műszerfalán, nyilvános URL nélkül. A hermes-agent és open-webui privát szolgáltatások megjelennek a Render műszerfalon, mindkettő nyilvános URL nélkül. A hozzáférés az ügynökhöz Adj neki néhány percet, miután a pulumi up befejeződik. A képeket még mindig le kell húzni és a konténereknek el kell indulniuk, és az Open WebUI-nak csatlakoznia kell a tailnetedhez, mielőtt a URL megoldódik. Frissíts, amíg be nem tölt. Az Open WebUI csak a tailneteden elérhető, a következő URL-en: https://open-webui.<your-tailnet>.ts.net, nincs domain megvásárlás, nincs DNS irányítás, és nincs tanúsítványkezelés. Nyisd meg, regisztrálj, hogy az első fiók adminisztrátor legyen, és kérd meg az ügynököt, hogy futtasson egy Python parancsot. Ennek fel kell állítania egy Modal homokozót, és vissza kell adnia az eredményt, úgy, hogy semmi nem legyen kitéve a nyilvános internetnek. Open WebUI a tailnet URL-en: a gpt-5.5 ügynök sum(i*i for i in range(1, 1001))-t futtat egy Modal homokozóban és visszaadja 333833500-t. Amikor az ügynök futtatja ezt a kódot, a Modal kifejezetten erre a célra épít egy ideiglenes homokozót. Nincs Modal forrás, amit deklarálni kell, nincs Modal CLI, és nincs Modal szolgáltató a hídhoz. A Hermes szolgáltatás a MODAL_TOKEN_ID-t és a MODAL_TOKEN_SECRET-et mint két titkos környezeti változót hordoz, és ez az egész lábnyoma. A Modal irányítópult: a feladatonként a Hermes ügynök futásidőben létrehozott homokozói a kód végrehajtásához. A telepítés ellenőrzése (opcionális) Ha a csevegő UI nem tölt be, adj néhány percet a szolgáltatásoknak, hogy befejezzék az első indításukat, majd ellenőrizd két dolgot: A Render műszerfal naplóit a hermes-agent és open-webui szolgáltatások számára, hogy megerősítsd, hogy mindkettő elindult és letöltötte a képeiket. Tailscale admin konzol (Gépek), hogy megerősítsd, hogy az open-webui node csatlakozott a tailnetedhez. Ha nem, a TS_AUTHKEY valószínűleg lejárt vagy nem újrafelhasználható. Biztonsági megfontolások Az önálló hosztolt AI szerverek gyorsan felfedezhetők: az olyan szkennerek, mint a Shodan és Censys, néhány órán belül vagy nap alatt felsorolják a frissen kitetett egyet, és a kód képesek már aktív támadás alatt állnak. Egy mindig aktív ügynök futtatása egy olyan gépen, amelyet egyéb dolgokra is használsz, még gyorsabb prompt injekciót is vonz. A válasz itt az, hogy az ügynök ne legyen elérhető az internetről, és hogy elkülönítse a kódot, amelyet futtat. Ez megakadályozza a szkennert: senki sem talál nyitott portot, hogy megtámadja. Ez kevésbé segít, ha az ügynök ellened fordul, ami a nehezebb probléma. Egy részlet miatt ez az elkülönítés alapvető jelentőségű. Fej nélküli konténerben senki sincs a terminálnál, hogy bármire is jóváhagyjon, és ez igaz a cron és CI futásokra is, így a telepítés így futtatja a Hermest HERMES_ACCEPT_HOOKS=1 beállítással, hogy automatikusan jóváhagyja a shell horgokat, amelyeket különben szüneteltetne. A gyakorlati eredmény az, hogy az ügynök kódja emberi beavatkozás nélkül működik, és pontosan ezért a Modal homokozónak kell betöltenie a súlyt: amikor a modell rossz parancsot ír, a doboz, amelyben futtatja, áll között a parancs és a kapu hitelesítő adatai, nem egy megerősítő kérdés. Aggodalom Tipikus önálló hosztolt Ez az ügynök, ami valósággá válik Nyilvános port, vagy bejelentkezés mögött A nyilvános szolgáltatás, nincs nyilvános URL Csevegő UI elérhetőség Nyilvános hostnév + auth Csak a tailnet (tailscale serve) Kód végrehajtás Futtatás az átjáró mellett Izolált Modal homokozó, lebontva után Parancs jóváhagyása Ember jóváhagyja a veszélyes parancsokat Fej nélküli: az elkülönítés helyettesíti a promptokat Titkok átvitele Nyilvános port, ha HTTP-n keresztül elérhető Titkosított környezeti változók; a tailnet-elengedett hozzáférés Ez privát, ami nem ugyanaz, mint a teljesen megbízható. Néhány hely, ahol a határ még mindig szivárog: A megosztott viszonyítási kulcs soha nem váltakozik. A Hermes az internetről elérhetetlen, de nyitva áll az Open WebUI előtt, és a kettő megoszt egy statikus viszonyító kulcsot. Aki birtokolja az elsődleges felületet, birtokolja a mögötte lévő átjárót. Rotálja időszakonként. A tailnet-politika kattintásos műveletekkel rendelkezik. Az ACL-ek, a csomópont címkéi és az egyszeri HTTPS kapcsoló a Tailscale admin konzolban találhatók, nem a pulumi up során, és az újrafelhasználható kulcsnak nincs címke, amely meghatározná a robbanási sugarát. A Tailscale szolgáltató kezelheti ezt a politikát deklaratívan, ha szeretnéd, hogy a kódban benne legyen. A regisztráció alapból admin. Megfelelő egy egyfelhasználós tailnet számára, az első dolog, amit lezárni kell (ENABLE_SIGNUP, DEFAULT_USER_ROLE), amint több mint egy ember elérheti az URL-t. Minden üzenetküldő kliens egy új bejárat. Minden platform, amit csatlakoztatsz, hozzáad egy újabb bejáratot, ezért a tailnet a legalsó réteg ehhez a biztonsághoz, nem a teljes körű védelméhez. Egy kompromittált ügynök még mindig elérheti a külvilágot. A privát mag megakadályozza a külső felfedezést, de nem tartalmazza magát az ügynököt. Az átjáró tartja magában a Modal és OpenRouter tokeneket környezeti változókként, és szabadon hívhat ki, tehát egy prompt-injectált ügynök olvashatja a saját környezetét, és elküldheti őket valahova; a Modal homokozó elkülöníti az ügynök által futtatott kódot, nem pedig a birtokolt hitelesítő adatokat. Korlátozza és forgassa el az OpenRouter kulcsot, tartsa távol a Modal tokent az átjárótól, és figyelje meg a kimenő forgalmat, ami Rendernél oldalproxies elágazást jelent (Render dedikált kimenő IP-ket és bejövő szabályokat biztosít, de nincs célzott kimeneti szűrő). Ajánlásaim: Tartsd mindkét szolgáltatást privát; soha ne adj nyilvános URL-t Hermestől Futtass kódot Modal homokozókban, mivel a HERMES_ACCEPT_HOOKS=1 azt jelenti, hogy senki sem jóváhagy parancsokat Rotálja a megosztott viszonyító kulcsot és a Tailscale hitelesítő kulcsot időszakonként Korlátozza és forgassa el az OpenRouter kulcsot; egy titok leak a valószínűbb kudarc, mint egy nyitott port használja a Pulumi ESC-t a titkokhoz, a keménykódolatlan helyett Zárja le az Open WebUI regisztrációt, amint több mint egy ember elérheti Kezelje fejlődést szándékosan, az admin konzolon vagy a Tailscale szolgáltató használatával Mi a következő lépés? A telepítés az alap, amire az ügynök épít. Egy privát ügynök akkor válik hasznossá, amikor emlékszik a korábbi kontextusra, kódot futtat emberi beavatkozás nélkül és saját kezdeményezésére lép kapcsolatba. A lemez az, ami megőrzi ezt: a memóriája és az ütemezése rajta él, így túlél minden újraindítást. Önállóan ütemez. A Hermes egy elsőrangú cron-t szállít, amit sima nyelven vezérelhetsz, akár a csevegőablakban kérve az ügynököt, akár annak CLI-jén. Az ütemezés intervallumokat, ötféli cron-t vagy egyszeri eseményeket vesz figyelembe: hermes cron create "minden 1h" \ "Scrape <listing-url> az árért, hasonlítsd össze a seen.json fájlban a homokozóban, és értesíts a Telegram-on, ha csökkent, különben csak válaszolj [CSOND]." \ --deliver telegram A [CSOND] válasz elnyomja az értesítést, amikor semmi nem változott, így a figyelő csak akkor lép kapcsolatba, ha van mondanivalója. Az ütemezett futások alapértelmezetten kihagyják a memóriát, így a megfigyelés nem szennyezi, amit az ügynök tanult. Az, ahol dolgozol, ugyanazon titkos mintázattal csatlakozik. Az üzenetküldő kliensek ugyanarra a kapura csatlakoznak, és tokenjeik titkos környezeti változókként állnak rendelkezésre a Hermes szolgáltatáson, pontosan olyan formában, ahogyan a Modal párnál: // a MODAL_TOKEN_ID mellett a hermes szolgáltatáson: TELEGRAM_BOT_TOKEN: { value: cfg.requireSecret("telegramBotToken") }, plusz egy platform blokkot, amit hozzáadsz a config.yaml-hez (a kép csak a modellt és a terminál blokkot szállítja; Hermes támogatja az üzenetküldő platformokat is, a dokumentációja szerint): gateway: platforms: telegram: require_mention: true Ezekkel a két darabbal néhány dolog valóban elérhető ma: Egy ár- vagy üzemidő figyelő, amely csak akkor beszél, amikor valami megváltozik, a fenti [CSOND] és tartós-homokozó dedup mintázat segítségével. Egy napi tájékoztató, ami értékeli és deduplikálja az információforrásaidat, és minden reggel a legjobb tételeket is kiosztja, a dokumentált napi tájékoztató bot. Ha azt szeretnéd, hogy az idő múlásával beilleszkedjen a ízlésedbe, az az opcionális Honcho memória szolgáltatás feladata; a beszélgetésből olvassa ki a preferenciáidat. A beépített fájlmemória ennek nincs verziója. Egy PR-ellenőrző társ, amely ellenőrzi a nyitott pull kérelmeket a repo AGENTS.md hagyományai ellen, és megőrzi az ismétlődő mintázatokat, mint egy készséget, így az ötödik áttekintés kevesebb irányítást igényel, mint az első. Néhány határértéket érdemes nyíltan megfogalmazni, mivel a bemutatók hajlamosak eltúlozni a képességeket. A Hermes nem szállít Gmail, Naptár vagy piaci integrációkat a dobozban; azokat MCP szerverek vagy készségek formájában építik be, ami több munkát igényel, mint amit egy induló videó sugall. Önállóan szerkeszti a memóriáját és fejleszti a készségeit, de nem képzi újra az alapmodellt, és nem változtatja meg önállóan a magas szintű stratégiáját, tehát az "önálló tanulás" itt azt jelenti, amit minden futáskor a memóriába és a készségekbe ír. Következtetés A Hermes ügynök infra kódként történő telepítése azt jelenti, hogy bármikor reprodukálhatod a beállítást, verziókontroll alatt tarthatod, és egyetlen pulumi törléssel lebontathatod. Ha mindkét szolgáltatást privátban tartod, nyilvános URL és kitetett portok nélkül, a kódot végrehajtó mag soha nem ül majd az interneten, hogy valaki felfedezze. Az a rész, amit érdemes átvinni a következő szolgáltatásodra: nem minden rétegnek van szolgáltatója, és ez rendben van. A feladat, hogy megkülönböztesse a valódi forrást egy futási függőségtől, amely jelmezként viselkedik. A Render és a képek azok a források, amelyeket nyilvánítasz; Modal és Tailscale hitelesítők, amelyeket átadsz. Rajzold meg azt a térképet először, és a program abból következik. Ahhoz, hogy a térképet generáld, a Pulumi Neo célozhat egy célarchitektúrára, mint ez is, és elkészít egy első vázlatot a programról. Az ügynök oldaláról szól a változás, amit a "Hogyan változott az AI ügynökök építése 2026-ban" című írás foglal össze, a platform oldaláról pedig az "Ügynök szétszórtság itt van". Az infrastruktúrád platformja a válasz... Ha bármilyen problémád vagy kérdésed van, látogass el a Pulumi közösségi Slack-be vagy a GitHub megbeszélésre. Új Pulumi felhasználó? Itt kezdj!
Külső link: pulumi.com
Kapcsolódó cikkek
devops
Hét stabil kernel szombatra, köztük két biztonsági javítással.
devops
Miért nem mentik meg az olcsóbb modellek az AI költségvetését?
devops
