Deploy su Fly.io
Obiettivo: Gateway OpenClaw in esecuzione su una macchina Fly.io con storage persistente, HTTPS automatico e accesso ai canali Discord e altri.
Cosa ti serve
- flyctl CLI installato
- Account Fly.io (il piano gratuito funziona)
- Autenticazione modello: chiave API per il provider di modelli scelto
- Credenziali canale: token bot Discord, token Telegram, ecc.
Percorso rapido per principianti
- Clona il repo → personalizza
fly.toml - Crea app + volume → imposta i segreti
- Deploy con
fly deploy - Entra via SSH per creare la configurazione o usa la Control UI
1) Crea l’app Fly
# Clona il repository
git clone https://github.com/openclaw/openclaw.git
cd openclaw
# Crea una nuova app Fly (scegli il tuo nome)
fly apps create my-openclaw
# Crea un volume persistente (1GB di solito basta)
fly volumes create openclaw_data --size 1 --region iad
Suggerimento: Scegli una regione vicina a te. Opzioni comuni:
lhr(Londra),iad(Virginia),sjc(San Jose).
2) Configura fly.toml
Modifica fly.toml per farlo corrispondere al nome della tua app e ai tuoi requisiti.
Nota sulla sicurezza: La configurazione predefinita espone un URL pubblico. Per un deploy blindato senza IP pubblico, vedi Deploy privato o usa fly.private.toml.
app = "my-openclaw" # Il nome della tua app
primary_region = "iad"
[build]
dockerfile = "Dockerfile"
[env]
NODE_ENV = "production"
OPENCLAW_PREFER_PNPM = "1"
OPENCLAW_STATE_DIR = "/data"
NODE_OPTIONS = "--max-old-space-size=1536"
[processes]
app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = false
auto_start_machines = true
min_machines_running = 1
processes = ["app"]
[[vm]]
size = "shared-cpu-2x"
memory = "2048mb"
[mounts]
source = "openclaw_data"
destination = "/data"
Impostazioni chiave:
| Impostazione | Perche |
|---|---|
--bind lan | Fa il bind su 0.0.0.0 cosi il proxy Fly puo raggiungere il gateway |
--allow-unconfigured | Avvia senza file di configurazione (lo creerai dopo) |
internal_port = 3000 | Deve corrispondere a --port 3000 (o OPENCLAW_GATEWAY_PORT) per gli health check di Fly |
memory = "2048mb" | 512MB sono troppo pochi; consigliati 2GB |
OPENCLAW_STATE_DIR = "/data" | Persiste lo stato sul volume |
3) Imposta i segreti
# Obbligatorio: token del gateway (per il binding non-loopback)
fly secrets set OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
# Chiavi API del provider di modelli
fly secrets set ANTHROPIC_API_KEY=sk-ant-...
# Opzionale: altri provider
fly secrets set OPENAI_API_KEY=sk-...
fly secrets set GOOGLE_API_KEY=...
# Token dei canali
fly secrets set DISCORD_BOT_TOKEN=MTQ...
Note:
- I binding non-loopback (
--bind lan) richiedonoOPENCLAW_GATEWAY_TOKENper sicurezza. - Tratta questi token come password.
- Preferisci le variabili d’ambiente al file di configurazione per tutte le chiavi API e i token. Questo tiene i segreti fuori da
openclaw.jsondove potrebbero essere esposti o registrati nei log accidentalmente.
4) Deploy
fly deploy
Il primo deploy compila l’immagine Docker (~2-3 minuti). I successivi sono piu rapidi.
Dopo il deploy, verifica:
fly status
fly logs
Dovresti vedere:
[gateway] listening on ws://0.0.0.0:3000 (PID xxx)
[discord] logged in to discord as xxx
5) Crea il file di configurazione
Entra nella macchina via SSH:
fly ssh console
Crea la directory e il file di configurazione:
mkdir -p /data
cat > /data/openclaw.json << 'EOF'
{
"agents": {
"defaults": {
"model": {
"primary": "anthropic/claude-opus-4-6",
"fallbacks": ["anthropic/claude-sonnet-4-5", "openai/gpt-4o"]
},
"maxConcurrent": 4
},
"list": [
{
"id": "main",
"default": true
}
]
},
"auth": {
"profiles": {
"anthropic:default": { "mode": "token", "provider": "anthropic" },
"openai:default": { "mode": "token", "provider": "openai" }
}
},
"bindings": [
{
"agentId": "main",
"match": { "channel": "discord" }
}
],
"channels": {
"discord": {
"enabled": true,
"groupPolicy": "allowlist",
"guilds": {
"YOUR_GUILD_ID": {
"channels": { "general": { "allow": true } },
"requireMention": false
}
}
}
},
"gateway": {
"mode": "local",
"bind": "auto"
},
"meta": {
"lastTouchedVersion": "2026.1.29"
}
}
EOF
Nota: Con OPENCLAW_STATE_DIR=/data, il percorso della configurazione e /data/openclaw.json.
Nota: Il token Discord puo provenire da:
- Variabile d’ambiente:
DISCORD_BOT_TOKEN(consigliato per i segreti) - File di configurazione:
channels.discord.token
Se usi la variabile d’ambiente, non serve aggiungere il token alla configurazione. Il gateway legge DISCORD_BOT_TOKEN automaticamente.
Riavvia per applicare:
exit
fly machine restart <machine-id>
6) Accedi al Gateway
Control UI
Apri nel browser:
fly open
Oppure visita https://my-openclaw.fly.dev/
Incolla il token del gateway (quello di OPENCLAW_GATEWAY_TOKEN) per autenticarti.
Log
fly logs # Log in tempo reale
fly logs --no-tail # Log recenti
Console SSH
fly ssh console
Risoluzione problemi
”App is not listening on expected address”
Il gateway sta facendo il bind su 127.0.0.1 invece che su 0.0.0.0.
Soluzione: Aggiungi --bind lan al comando del processo in fly.toml.
Health check falliti / connessione rifiutata
Fly non riesce a raggiungere il gateway sulla porta configurata.
Soluzione: Assicurati che internal_port corrisponda alla porta del gateway (imposta --port 3000 o OPENCLAW_GATEWAY_PORT=3000).
OOM / Problemi di memoria
Il container continua a riavviarsi o viene terminato. Segnali: SIGABRT, v8::internal::Runtime_AllocateInYoungGeneration, o riavvii silenziosi.
Soluzione: Aumenta la memoria in fly.toml:
[[vm]]
memory = "2048mb"
Oppure aggiorna una macchina esistente:
fly machine update <machine-id> --vm-memory 2048 -y
Nota: 512MB sono troppo pochi. 1GB puo funzionare ma rischia OOM sotto carico o con logging verboso. Si consigliano 2GB.
Problemi con il lock del Gateway
Il gateway rifiuta di avviarsi con errori “already running”.
Succede quando il container si riavvia ma il file di lock PID persiste sul volume.
Soluzione: Elimina il file di lock:
fly ssh console --command "rm -f /data/gateway.*.lock"
fly machine restart <machine-id>
Il file di lock si trova in /data/gateway.*.lock (non in una sottodirectory).
La configurazione non viene letta
Se usi --allow-unconfigured, il gateway crea una configurazione minimale. La tua configurazione personalizzata in /data/openclaw.json dovrebbe essere letta al riavvio.
Verifica che la configurazione esista:
fly ssh console --command "cat /data/openclaw.json"
Scrittura della configurazione via SSH
Il comando fly ssh console -C non supporta la redirezione della shell. Per scrivere un file di configurazione:
# Usa echo + tee (pipe dal locale al remoto)
echo '{"your":"config"}' | fly ssh console -C "tee /data/openclaw.json"
# Oppure usa sftp
fly sftp shell
> put /local/path/config.json /data/openclaw.json
Nota: fly sftp potrebbe fallire se il file esiste gia. Eliminalo prima:
fly ssh console --command "rm /data/openclaw.json"
Lo stato non persiste
Se perdi credenziali o sessioni dopo un riavvio, la directory di stato sta scrivendo sul filesystem del container.
Soluzione: Assicurati che OPENCLAW_STATE_DIR=/data sia impostato in fly.toml e rideploya.
Aggiornamenti
# Scarica le ultime modifiche
git pull
# Rideploya
fly deploy
# Verifica lo stato
fly status
fly logs
Aggiornamento del comando della macchina
Se devi cambiare il comando di avvio senza un redeploy completo:
# Ottieni l'ID della macchina
fly machines list
# Aggiorna il comando
fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y
# Oppure con aumento di memoria
fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
Nota: Dopo fly deploy, il comando della macchina potrebbe resettarsi a quanto specificato in fly.toml. Se hai fatto modifiche manuali, riapplicale dopo il deploy.
Deploy privato (blindato)
Per impostazione predefinita, Fly assegna IP pubblici, rendendo il tuo gateway accessibile a https://your-app.fly.dev. Comodo, ma il deploy diventa individuabile da scanner Internet (Shodan, Censys, ecc.).
Per un deploy blindato senza esposizione pubblica, usa il template privato.
Quando usare il deploy privato
- Fai solo chiamate/messaggi in uscita (nessun webhook in ingresso)
- Usi tunnel ngrok o Tailscale per i callback dei webhook
- Accedi al gateway via SSH, proxy o WireGuard invece che dal browser
- Vuoi che il deploy sia nascosto dagli scanner Internet
Setup
Usa fly.private.toml al posto della configurazione standard:
# Deploy con configurazione privata
fly deploy -c fly.private.toml
Oppure converti un deploy esistente:
# Elenca gli IP attuali
fly ips list -a my-openclaw
# Rilascia gli IP pubblici
fly ips release <public-ipv4> -a my-openclaw
fly ips release <public-ipv6> -a my-openclaw
# Passa alla configurazione privata cosi i deploy futuri non riallocano IP pubblici
# (rimuovi [http_service] o deploya con il template privato)
fly deploy -c fly.private.toml
# Assegna un IPv6 solo privato
fly ips allocate-v6 --private -a my-openclaw
Dopo, fly ips list dovrebbe mostrare solo un IP di tipo private:
VERSION IP TYPE REGION
v6 fdaa:x:x:x:x::x private global
Accedere a un deploy privato
Senza URL pubblico, usa uno di questi metodi:
Opzione 1: Proxy locale (il piu semplice)
# Inoltra la porta locale 3000 all'app
fly proxy 3000:3000 -a my-openclaw
# Poi apri http://localhost:3000 nel browser
Opzione 2: VPN WireGuard
# Crea la configurazione WireGuard (una tantum)
fly wireguard create
# Importa nel client WireGuard, poi accedi tramite IPv6 interno
# Esempio: http://[fdaa:x:x:x:x::x]:3000
Opzione 3: Solo SSH
fly ssh console -a my-openclaw
Webhook con deploy privato
Se hai bisogno di callback webhook (Twilio, Telnyx, ecc.) senza esposizione pubblica:
- Tunnel ngrok - Esegui ngrok dentro il container o come sidecar
- Tailscale Funnel - Esponi percorsi specifici tramite Tailscale
- Solo in uscita - Alcuni provider (Twilio) funzionano bene per chiamate in uscita senza webhook
Esempio di configurazione voice-call con ngrok:
{
"plugins": {
"entries": {
"voice-call": {
"enabled": true,
"config": {
"provider": "twilio",
"tunnel": { "provider": "ngrok" },
"webhookSecurity": {
"allowedHosts": ["example.ngrok.app"]
}
}
}
}
}
}
Il tunnel ngrok gira dentro il container e fornisce un URL webhook pubblico senza esporre l’app Fly stessa. Imposta webhookSecurity.allowedHosts sull’hostname del tunnel pubblico affinche gli header host inoltrati vengano accettati.
Vantaggi di sicurezza
| Aspetto | Pubblico | Privato |
|---|---|---|
| Scanner Internet | Individuabile | Nascosto |
| Attacchi diretti | Possibili | Bloccati |
| Accesso Control UI | Browser | Proxy/VPN |
| Consegna webhook | Diretta | Via tunnel |
Note
- Fly.io usa architettura x86 (non ARM)
- Il Dockerfile e compatibile con entrambe le architetture
- Per l’onboarding WhatsApp/Telegram, usa
fly ssh console - I dati persistenti risiedono sul volume in
/data - Signal richiede Java + signal-cli; usa un’immagine personalizzata e mantieni la memoria a 2GB+.
Costi
Con la configurazione consigliata (shared-cpu-2x, 2GB RAM):
- ~$10-15/mese a seconda dell’uso
- Il piano gratuito include una certa quantita
Vedi Prezzi Fly.io per i dettagli.