Deploy OpenClaw na Oracle Cloud com Nginx e Telegram
Guia de instalação do OpenClaw em uma VM Oracle Cloud (4 oCPU Ampere, 24 GB RAM, 150 GB storage) com Nginx como proxy reverso, SSL via Certbot, Telegram como canal de comunicação, integração com Google Workspace via gog e modelo MiniMax M2.5 via OpenRouter.
Pré-requisitos
- VM Oracle Cloud provisionada e acessível via SSH
- Docker e Docker Compose instalados
- Entrada DNS tipo A apontando o subdomínio para o IP público da VM
- Portas 80 e 443 liberadas no Security List da Oracle Cloud e no firewall do SO
- Conta no OpenRouter com créditos ($5 mínimo)
Estrutura do Projeto
openclaw-docker/
├── docker-compose.yml
├── .env
├── nginx/
│ └── openclaw.conf
├── config/
│ └── openclaw.json
├── data/
│ ├── state/
│ └── gogcli/
└── workspace/
├── AGENTS.md
├── SOUL.md
└── memory/
Crie a estrutura:
mkdir -p openclaw-docker/{nginx,config,data/state,data/gogcli,workspace/memory}
cd openclaw-docker
Arquivos de Configuração
docker-compose.yml
services:
openclaw:
image: node:22-slim
container_name: openclaw-gateway
restart: unless-stopped
working_dir: /app/workspace
command: >
sh -c "
apt-get update -qq &&
apt-get install -y -qq git curl &&
rm -rf /usr/local/lib/node_modules/openclaw &&
npm install -g openclaw@latest &&
curl -L https://github.com/steipete/gogcli/releases/download/v0.12.0/gogcli_0.12.0_linux_arm64.tar.gz -o /tmp/gogcli.tar.gz &&
cd /tmp && tar -xzf gogcli.tar.gz &&
mv /tmp/gog /usr/local/bin/gog &&
chmod +x /usr/local/bin/gog &&
openclaw gateway --port 3000
"
env_file:
- .env
environment:
- NODE_ENV=production
- OPENCLAW_STATE_DIR=/app/state
- OPENCLAW_CONFIG=/app/config/openclaw.json
- GOG_KEYRING_PASSWORD=sua-senha-do-keyring
- GOG_KEYRING_BACKEND=file
- GOG_ACCOUNT=${GOG_ACCOUNT}
volumes:
- ./config:/app/config:ro
- ./data/state:/app/state
- ./workspace:/app/workspace
- ./data/gogcli:/root/.config/gogcli
expose:
- "3000"
ports:
- "4000:4000"
networks:
- openclaw-internal
healthcheck:
test: ["CMD-SHELL", "node -e \"const http = require('http'); http.get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 512M
nginx:
image: nginx:alpine
container_name: openclaw-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/openclaw.conf:/etc/nginx/conf.d/openclaw.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
- /var/www/certbot:/var/www/certbot:ro
networks:
- openclaw-internal
depends_on:
- openclaw
networks:
openclaw-internal:
driver: bridge
Nota: O
gogé instalado automaticamente a cada inicialização do container. As credenciais OAuth ficam persistidas em./data/gogcli, mapeado como volume.
.env
# NUNCA commite este arquivo!
# OpenRouter (modelo principal)
OPENROUTER_API_KEY=sua-chave-openrouter
# Canal Telegram
TELEGRAM_BOT_TOKEN=token-do-seu-bot-telegram
# Token do OpenClaw (gerado automaticamente pelo setup — veja seção Acesso ao Control UI)
OPENCLAW_TOKEN=seu-openclaw-token
# Google Workspace (gog)
GOG_KEYRING_PASSWORD=sua-senha-do-keyring
GOG_KEYRING_BACKEND=file
GOG_ACCOUNT=seu-email@gmail.com
# Otimizações para container/VPS
NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
OPENCLAW_NO_RESPAWN=1
# Configurações do gateway
OPENCLAW_LOG_LEVEL=info
OPENCLAW_HOST=0.0.0.0
OPENCLAW_PORT=3000
Proteja o arquivo:
echo ".env" >> .gitignore
chmod 600 .env
⚠️ Importante:
docker compose restartnão relê o.env. Para que alterações em variáveis de ambiente surtam efeito, sempre usedocker compose down && docker compose up -d.
config/openclaw.json
Este arquivo é usado como referência inicial, mas o OpenClaw persiste sua configuração ativa em /app/state/openclaw.json.
{
"models": {
"default": "openrouter/minimax/minimax-m2.5",
"providers": {
"openrouter": {
"apiKey": "${OPENROUTER_API_KEY}"
}
}
},
"gateway": {
"host": "0.0.0.0",
"port": 3000
},
"channels": {
"telegram": {
"enabled": true,
"token": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "open",
"allowFrom": ["*"],
"groupPolicy": "open"
}
},
"workspace": {
"path": "/app/workspace"
},
"memory": {
"enabled": true,
"path": "/app/state/memory"
},
"logging": {
"level": "info",
"file": "/app/state/logs/gateway.log"
}
}
workspace/SOUL.md
# SOUL.md
Você é um assistente pessoal operando via Telegram.
## Ferramentas Google Workspace
- Você tem acesso COMPLETO ao Google Workspace via ferramenta `exec` usando o comando `gog`
- O binário `gog` está disponível em `/usr/local/bin/gog`
- As variáveis `GOG_KEYRING_PASSWORD` e `GOG_ACCOUNT` já estão configuradas — nunca peça senha ou conta
- Serviços disponíveis: Gmail, Calendar, Drive, Docs, Sheets, Slides, Contacts, Tasks, Chat, Classroom, Forms, AppScript
- Exemplos de uso:
- `gog calendar list` — listar calendários
- `gog calendar events primary --from <iso> --to <iso>` — listar eventos
- `gog gmail search "<query>"` — buscar emails
- `gog gmail send --to <email> --subject "<assunto>" --body "<mensagem>"` — enviar email
- `gog drive search "<query>"` — buscar arquivos no Drive
- `gog contacts list` — listar contatos
- `gog sheets get <sheetId> "Tab!A1:D10"` — ler planilha
- Nunca diga que não tem acesso ao Google Workspace — use sempre o `exec` com `gog`
- Confirme com o usuário antes de enviar emails, criar ou modificar eventos e arquivos
## Restrições absolutas
- NUNCA use ferramentas de browser (`browser`, `open_url`, `navigate`) para nenhuma tarefa
- Para Google Drive: use EXCLUSIVAMENTE `gog drive`
- Para Gmail: use EXCLUSIVAMENTE `gog gmail`
- Para Calendar: use EXCLUSIVAMENTE `gog calendar`
- Se uma tarefa parecer exigir browser, informe o usuário e sugira alternativa via gog
workspace/AGENTS.md
# AGENTS.md
Workspace do OpenClaw em Docker.
## Regras
- Mantenha logs em memory/
- Use paths relativos dentro do workspace
Certificado SSL
Instalar o Certbot
sudo apt update && sudo apt install certbot -y
sudo mkdir -p /var/www/certbot
Configurar o Nginx apenas com HTTP (temporário)
server {
listen 80;
server_name seu.subdominio.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
Subir o Nginx
docker compose up -d nginx
Emitir o certificado
sudo certbot certonly --webroot \
-w /var/www/certbot \
-d seu.subdominio.com \
--email seu@email.com \
--agree-tos --non-interactive
Nginx com HTTPS
server {
listen 80;
server_name seu.subdominio.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name seu.subdominio.com;
ssl_certificate /etc/letsencrypt/live/seu.subdominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/seu.subdominio.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location /oauth2/callback {
proxy_pass http://openclaw-gateway:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
proxy_connect_timeout 10s;
}
location / {
proxy_pass http://openclaw-gateway:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 10s;
}
}
Subir o Stack Completo
docker compose down && docker compose up -d
Verifique os logs:
docker compose logs -f openclaw
Teste o health:
curl https://seu.subdominio.com/health
# Esperado: {"ok":true,"status":"live"}
Configuração do State
O OpenClaw gera o arquivo /app/state/openclaw.json automaticamente na primeira execução. Execute o setup inicial:
docker compose exec openclaw openclaw setup
docker compose exec openclaw openclaw doctor --fix
Crie o state no host:
cat > /tmp/state.json << 'EOF'
{
"meta": {
"lastTouchedVersion": "2026.3.13",
"lastTouchedAt": "2026-03-16T00:00:00.000Z"
},
"agents": {
"defaults": {
"workspace": "/app/workspace",
"model": "openrouter/minimax/minimax-m2.5",
"compaction": {
"mode": "safeguard"
}
}
},
"commands": {
"native": "auto",
"nativeSkills": "auto",
"restart": true,
"ownerDisplay": "raw"
},
"channels": {
"telegram": {
"enabled": true,
"dmPolicy": "open",
"allowFrom": ["*"],
"groupPolicy": "open",
"streaming": "partial"
}
},
"gateway": {
"mode": "local",
"bind": "lan",
"port": 3000,
"auth": {
"mode": "token",
"token": "seu-token-gerado-pelo-setup"
},
"trustedProxies": ["172.18.0.0/16"],
"controlUi": {
"allowedOrigins": [
"https://seu.subdominio.com",
"https://app.openclaw.ai"
]
}
}
}
EOF
Copie e reinicie:
docker cp /tmp/state.json openclaw-gateway:/app/state/openclaw.json
docker compose down && docker compose up -d
Verifique o modelo ativo:
docker compose logs openclaw | grep "agent model"
# Esperado: agent model: openrouter/minimax/minimax-m2.5
Modelo: MiniMax M2.5 via OpenRouter
O MiniMax M2.5 é o modelo padrão desta configuração. Principais características:
- Preço: $0.15/M tokens de entrada, $1.15/M tokens de saída — para uso pessoal (~50 mensagens/dia), os $5 iniciais duram meses
- Contexto: 196k tokens
- Tool calling: suportado — obrigatório para o OpenClaw funcionar
- Foco: produtividade real-world, agentic workflows, office (Drive, Sheets, Docs)
Trocar de modelo
Se necessário, edite diretamente no state:
docker exec -it openclaw-gateway sed -i 's/"model": "openrouter\/minimax\/minimax-m2.5"/"model": "openrouter\/NOVO_MODELO"/' /app/state/openclaw.json
cd /home/ubuntu/openclaw-docker && docker compose down && docker compose up -d
Ou via Telegram/Control UI:
/model openrouter/minimax/minimax-m2.5
Verificar IDs de modelos disponíveis
docker compose exec openclaw openclaw models list 2>&1 | grep openrouter
Acesso ao Control UI
O Control UI fica disponível em https://seu.subdominio.com. O acesso exige um token de sessão gerado dinamicamente — diferente do OPENCLAW_TOKEN no .env.
⚠️ Não cole o
OPENCLAW_TOKENdo.envna interface web. Isso resulta emgateway token mismatche bloqueio temporário por rate limiting.
Fluxo correto de acesso
Passo 1 — Gerar a URL tokenizada
docker compose exec openclaw openclaw dashboard
Passo 2 — Adaptar para o domínio público
Substitua http://127.0.0.1:3000 pelo seu subdomínio:
https://seu.subdominio.com/#token=...
Passo 3 — Aprovar o dispositivo
docker compose exec openclaw openclaw devices list
docker compose exec openclaw openclaw devices approve <requestId>
Recarregue o browser. Acesso permanente neste browser a partir daí.
Gerenciar dispositivos
docker compose exec openclaw openclaw devices list
docker compose exec openclaw openclaw devices revoke <deviceId>
docker compose exec openclaw openclaw devices remove <deviceId>
Integração com Google Workspace (gog)
Pré-requisitos no Google Cloud Console
- Crie um projeto em console.cloud.google.com
- Ative as APIs: Gmail, Google Calendar, Google Drive
- Configure a Tela de Consentimento OAuth (Externo, adicione seu email como usuário de teste)
- Crie credenciais: ID do cliente OAuth → Aplicativo da Web
- Origens autorizadas:
https://seu.subdominio.com - URIs de redirecionamento:
https://seu.subdominio.com/oauth2/callback - Baixe o JSON das credenciais
Autenticar
A autenticação OAuth do gog requer acesso a um servidor web temporário na porta 4000. Como a VPS está atrás de um bastion Oracle, o acesso direto à porta 4000 pode ser bloqueado — use um tunnel SSH.
Terminal 1 — tunnel SSH (deixe aberto durante todo o processo):
ssh -i ssh-key.key \
-o ProxyCommand="ssh -i ssh-key.key -W %h:%p -p 22 <bastion-session>@host.bastion.<region>.oci.oraclecloud.com" \
-L 4000:localhost:4000 \
-p 22 ubuntu@<ip-privado-vps>
Terminal 2 — copie as credenciais e inicie o login:
scp /caminho/local/client_secret_*.json ubuntu@sua-vps:/home/ubuntu/
docker cp ~/client_secret_*.json openclaw-gateway:/app/state/google-credentials.json
docker exec -it openclaw-gateway bash -c "gog auth credentials /app/state/google-credentials.json && gog auth login --services=calendar,gmail,drive,contacts,sheets,docs --listen-addr=0.0.0.0:4000 --redirect-host=seu.subdominio.com --force-consent"
Quando aparecer Server listening on [::]:4000, acesse no browser do seu PC:
http://localhost:4000
Autorize todos os serviços solicitados.
⚠️ O URI de redirecionamento no Google Cloud Console deve ser exatamente
https://seu.subdominio.com/oauth2/callback. Qualquer diferença causa erroredirect_uri_mismatch.⚠️ Se aparecer
address already in useao tentar reconectar, reinicie o container antes de tentar novamente:docker compose restart openclaw
Verificar
# Listar autenticações ativas
docker exec -it openclaw-gateway bash -c "gog auth list"
# Testar acesso ao Calendar (especifique a conta explicitamente)
docker exec -it openclaw-gateway bash -c "gog calendar list --account seu-email@gmail.com"
Nota: sempre use
--account seu-email@gmail.comnos comandosgogpara evitar ambiguidade, especialmente se houver múltiplas contas autenticadas.
Serviços disponíveis
| Serviço | Exemplo |
|---|---|
| Calendar | gog calendar events primary --from 2026-05-01T00:00:00 --to 2026-05-01T23:59:59 |
| Gmail | gog gmail search "is:unread" |
| Drive | gog drive search "relatório" |
| Contacts | gog contacts list |
| Sheets | gog sheets get <sheetId> "Aba!A1:D10" |
| Docs | gog docs cat <docId> |
Organizar arquivos no Google Drive via agente
O OpenClaw acessa o Drive exclusivamente via gog drive — sem browser. Para solicitar organização de arquivos, use o seguinte prompt no Telegram:
Quero organizar os arquivos soltos na raiz do meu Google Drive. Siga estas regras:
1. Use `gog drive list` para listar todos os arquivos e pastas na raiz
2. Identifique quais são arquivos soltos (não estão dentro de nenhuma pasta)
3. Para cada arquivo solto, infira o assunto ou projeto pelo nome do arquivo e decida a pasta mais adequada dentre as que já existem na raiz
4. Só crie uma nova pasta se nenhuma existente for adequada para aquele arquivo
5. Antes de mover qualquer coisa, me apresente o plano completo no formato:
- 📄 nome_do_arquivo → 📁 pasta_destino (existente ou NOVA)
6. Aguarde minha confirmação antes de executar qualquer movimentação
7. NUNCA delete nada — apenas mova
8. NUNCA use browser — use exclusivamente comandos `gog drive`
Renovação Automática do SSL
sudo crontab -e
# Adicione:
0 3 * * * certbot renew --quiet && docker compose -f /home/ubuntu/openclaw-docker/docker-compose.yml restart nginx
Comandos Úteis
# Reiniciar COM releitura do .env (obrigatório para mudanças em variáveis)
docker compose down && docker compose up -d
# Reiniciar SEM releitura do .env (apenas para mudanças no state)
docker compose restart openclaw
# Ver logs em tempo real
docker compose logs -f openclaw
# Verificar modelo ativo
docker compose logs openclaw | grep "agent model"
# Gerar URL tokenizada do dashboard
docker compose exec openclaw openclaw dashboard
# Listar e aprovar dispositivos
docker compose exec openclaw openclaw devices list
docker compose exec openclaw openclaw devices approve <requestId>
# Trocar modelo no state
docker exec -it openclaw-gateway sed -i 's/"model": "modelo-atual"/"model": "novo-modelo"/' /app/state/openclaw.json
# Listar modelos disponíveis
docker compose exec openclaw openclaw models list 2>&1
# Verificar autenticação do gog
docker compose exec openclaw bash -c "gog calendar list"
Solução de Problemas
docker compose restart não aplica mudanças no .env
Causa: restart não relê variáveis de ambiente — apenas reinicia o processo no container existente.
Solução: docker compose down && docker compose up -d
Agente tenta usar browser em vez do gog
Sintoma: [tools] browser failed: No supported browser found
Causa: o agente tentou abrir o Drive/Gmail no browser em vez de usar o gog.
Solução: adicione a seção Restrições absolutas ao SOUL.md (já incluída neste guia). Certifique-se de que o arquivo está salvo e reinicie o container.
Erro redirect_uri_mismatch no OAuth do gog
Causa: a URI de redirecionamento no Google Cloud Console não bate com a usada pelo gog.
Solução: verifique em APIs e Serviços → Credenciais → seu cliente OAuth que a URI https://seu.subdominio.com/oauth2/callback está cadastrada exatamente assim em URIs de redirecionamento autorizados.
Insufficient credits no OpenRouter (erro 402)
Causa: conta OpenRouter sem saldo.
Solução: adicione créditos em openrouter.ai/settings/credits. O mínimo recomendado é $5 — para uso pessoal dura meses com o MiniMax M2.5 ($0.15/M input).
Rate limit temporário no OpenRouter (erro 429)
Causa: pico de demanda no provider upstream.
Solução: aguarde alguns minutos e tente novamente. O OpenClaw reprocessa automaticamente na próxima mensagem.
State com modelo desatualizado após troca
Sintoma: agente reporta modelo diferente do configurado no state.
Causa: o OpenClaw faz cache do modelo em memória — restart simples não é suficiente.
Solução:
# Verificar o que está no state
docker exec -it openclaw-gateway grep '"model"' /app/state/openclaw.json
# Corrigir se necessário
docker exec -it openclaw-gateway sed -i 's/"model": "modelo-errado"/"model": "openrouter\/minimax\/minimax-m2.5"/' /app/state/openclaw.json
# Reiniciar completamente
cd /home/ubuntu/openclaw-docker && docker compose down && docker compose up -d
Fluxo de Funcionamento
Telegram ──► OpenClaw Gateway (porta 3000, rede interna Docker)
Internet ──► :443 ──► Nginx ──► openclaw-gateway:3000
OAuth ──► :443/oauth2/callback ──► Nginx ──► openclaw-gateway:4000
OpenClaw ──► OpenRouter API ──► MiniMax M2.5
O OpenClaw recebe mensagens do Telegram via polling, processa com o MiniMax M2.5 via OpenRouter e responde diretamente no chat. Para requisições ao Google Workspace, o agente usa o gog via ferramenta exec — sem browser, sem OAuth adicional em runtime.