🧪 Skills

SetupOrion ByImpa

Setup completo de VPS Ubuntu/Debian para produção com Docker Swarm, Traefik v3 (SSL/HTTPS automático), Portainer CE e rede overlay. Baseado no SetupOrion v2.8.0. Executa todos os comandos automatic

v1.0.0
❤️ 0
⬇️ 764
👁 2
Share

Description


name: vps-setup description: Setup completo de VPS Ubuntu/Debian para produção com Docker Swarm, Traefik v3 (SSL/HTTPS automático), Portainer CE e rede overlay. Baseado no SetupOrion v2.8.0. Executa todos os comandos automaticamente. metadata: openclaw: requires: bins: [] env: VPS_HOSTNAME: "Nome do servidor (ex: Orion)" VPS_NETWORK: "Nome da rede overlay Docker (ex: Impasevid)" VPS_EMAIL_SSL: "Email para certificados Let's Encrypt (ex: admin@seudominio.com)" VPS_PORTAINER_DOMAIN: "Domínio do Portainer (ex: portainer.seudominio.com)" VPS_PORTAINER_USER: "Usuário admin do Portainer (ex: admin)" VPS_PORTAINER_PASS: "Senha admin do Portainer (mínimo 12 caracteres)" VPS_POSTGRES_PASS: "Senha do PostgreSQL (auto-gerada se vazia). Use openssl rand -hex 16" VPS_EVOLUTION_DOMAIN: "Domínio da Evolution API (ex: api.seudominio.com)" VPS_EVOLUTION_API_KEY: "Global API Key da Evolution (auto-gerada se vazia). Use openssl rand -hex 16"

VPS Setup - Docker Swarm + Traefik + Portainer

Setup automatizado de VPS para produção. Instala Docker, inicia Swarm, cria rede overlay, deploya Traefik v3 com SSL automático e Portainer CE.

Requisitos: Ubuntu 20.04+ ou Debian 11+ com acesso root/sudo.


Execução Completa (todos os passos em ordem)

Execute cada etapa na ordem. Todas as etapas são idempotentes (seguro re-executar).


Etapa 1 - Atualizar Sistema e Configurar Servidor

# Atualizar sistema
sudo apt-get update && sudo apt-get upgrade -y

# Instalar utilitários essenciais
sudo apt-get install -y apt-utils apparmor-utils curl jq htpasswd ca-certificates gnupg lsb-release

# Configurar timezone
sudo timedatectl set-timezone America/Sao_Paulo

# Definir hostname do servidor
sudo hostnamectl set-hostname $VPS_HOSTNAME
sudo sed -i "s/127.0.0.1[[:space:]]localhost/127.0.0.1 $VPS_HOSTNAME/g" /etc/hosts

Verificação:

timedatectl | grep "Time zone"
# Esperado: America/Sao_Paulo

hostname
# Esperado: $VPS_HOSTNAME

Etapa 2 - Instalar Docker

# Instalar Docker via script oficial
curl -fsSL https://get.docker.com | bash

# Habilitar e iniciar Docker
sudo systemctl enable docker
sudo systemctl start docker

# Fix: garantir compatibilidade com API mínima
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo bash -c 'cat > /etc/systemd/system/docker.service.d/override.conf <<EOF
[Service]
Environment=DOCKER_MIN_API_VERSION=1.24
EOF'

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl restart docker

Se falhar, instalar manualmente:

sudo install -m 0755 -d /etc/apt/keyrings
OS_ID=$(source /etc/os-release && echo "$ID")
OS_CODENAME=$(source /etc/os-release && echo "$VERSION_CODENAME")

curl -fsSL https://download.docker.com/linux/$OS_ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS_ID $OS_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable docker
sudo systemctl start docker

Verificação:

docker --version
# Esperado: Docker version 2X.x.x

docker info --format '{{.Swarm.LocalNodeState}}'
# Esperado: inactive (ainda não iniciamos o Swarm)

Etapa 3 - Iniciar Docker Swarm

# Obter IP público da VPS (ignora loopback e IPs internos)
IP=$(hostname -I | tr ' ' '\n' | grep -v '^127\.' | grep -v '^10\.0\.0\.' | head -n1)

# Iniciar Swarm
docker swarm init --advertise-addr $IP

Verificação:

docker info --format '{{.Swarm.LocalNodeState}}'
# Esperado: active

docker node ls
# Esperado: 1 node com STATUS=Ready, MANAGER STATUS=Leader

Etapa 4 - Criar Rede Overlay e Volumes

# Criar rede overlay para comunicação entre containers
docker network create --driver=overlay $VPS_NETWORK

# Criar volumes necessários
docker volume create volume_swarm_shared
docker volume create volume_swarm_certificates
docker volume create portainer_data
docker volume create postgres_data
docker volume create evolution_instances
docker volume create evolution_redis

Verificação:

docker network ls | grep $VPS_NETWORK
# Esperado: linha com $VPS_NETWORK, DRIVER=overlay, SCOPE=swarm

docker volume ls | grep -E "shared|certificates|portainer|postgres|evolution"
# Esperado: 6 volumes listados

Etapa 5 - Deploy do Traefik v3 (Proxy Reverso + SSL)

Criar o arquivo traefik.yaml e fazer deploy:

cat > /root/traefik.yaml << 'TRAEFIKEOF'
version: "3.7"
services:
  traefik:
    image: traefik:v3.5.3
    command:
      - "--api.dashboard=true"
      - "--providers.swarm=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=NETWORK_PLACEHOLDER"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.transport.respondingTimeouts.idleTimeout=3600"
      - "--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.letsencryptresolver.acme.storage=/etc/traefik/letsencrypt/acme.json"
      - "--certificatesresolvers.letsencryptresolver.acme.email=EMAIL_PLACEHOLDER"
      - "--log.level=DEBUG"
      - "--log.format=common"
      - "--log.filePath=/var/log/traefik/traefik.log"
      - "--accesslog=true"
      - "--accesslog.filepath=/var/log/traefik/access-log"

    volumes:
      - "vol_certificates:/etc/traefik/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

    networks:
      - network_overlay

    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host

    deploy:
      placement:
        constraints:
          - node.role == manager
      labels:
        - "traefik.enable=true"
        - "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
        - "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"
        - "traefik.http.routers.http-catchall.rule=Host(`{host:.+}`)"
        - "traefik.http.routers.http-catchall.entrypoints=web"
        - "traefik.http.routers.http-catchall.middlewares=redirect-https@docker"
        - "traefik.http.routers.http-catchall.priority=1"

volumes:
  vol_shared:
    external: true
    name: volume_swarm_shared
  vol_certificates:
    external: true
    name: volume_swarm_certificates

networks:
  network_overlay:
    external: true
    attachable: true
    name: NETWORK_PLACEHOLDER
TRAEFIKEOF

# Substituir placeholders pelas variáveis reais
sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/traefik.yaml
sed -i "s/EMAIL_PLACEHOLDER/$VPS_EMAIL_SSL/g" /root/traefik.yaml

# Deploy
docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik

Aguardar Traefik ficar online:

# Verificar a cada 10s até o serviço mostrar 1/1
while ! docker service ls --filter name='traefik_traefik' --format '{{.Replicas}}' | grep -q '1/1'; do
  echo "Aguardando Traefik..."
  sleep 10
done
echo "Traefik online!"

Verificação:

docker service ls --filter name=traefik
# Esperado: traefik_traefik   1/1

curl -sI http://localhost:80 | head -3
# Esperado: HTTP redirect ou resposta do Traefik

Etapa 6 - Deploy do Portainer CE (Gerenciador Docker)

Criar o arquivo portainer.yaml e fazer deploy:

cat > /root/portainer.yaml << 'PORTAINEREOF'
version: "3.7"
services:
  agent:
    image: portainer/agent:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    networks:
      - network_overlay
    deploy:
      mode: global
      placement:
        constraints: [node.platform.os == linux]

  portainer:
    image: portainer/portainer-ce:latest
    command: -H tcp://tasks.agent:9001 --tlsskipverify
    volumes:
      - portainer_data:/data
    networks:
      - network_overlay
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.portainer.rule=Host(`PORTAINER_DOMAIN_PLACEHOLDER`)"
        - "traefik.http.services.portainer.loadbalancer.server.port=9000"
        - "traefik.http.routers.portainer.tls.certresolver=letsencryptresolver"
        - "traefik.http.routers.portainer.service=portainer"
        - "traefik.docker.network=NETWORK_PLACEHOLDER"
        - "traefik.http.routers.portainer.entrypoints=websecure"
        - "traefik.http.routers.portainer.priority=1"

volumes:
  portainer_data:
    external: true
    name: portainer_data

networks:
  network_overlay:
    external: true
    attachable: true
    name: NETWORK_PLACEHOLDER
PORTAINEREOF

# Substituir placeholders
sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/portainer.yaml
sed -i "s/PORTAINER_DOMAIN_PLACEHOLDER/$VPS_PORTAINER_DOMAIN/g" /root/portainer.yaml

# Deploy
docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer

Aguardar Portainer ficar online:

# Aguardar agent + portainer
while ! docker service ls --filter name='portainer_portainer' --format '{{.Replicas}}' | grep -q '1/1'; do
  echo "Aguardando Portainer..."
  sleep 10
done
echo "Portainer online!"

Verificação:

docker service ls --filter name=portainer
# Esperado: portainer_agent 1/1 (global), portainer_portainer 1/1

Etapa 7 - Criar Conta Admin no Portainer

# Aguardar API do Portainer estar pronta (30s após container online)
sleep 30

# Criar usuário admin (tentativa com retry)
for i in 1 2 3 4; do
  RESPONSE=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/users/admin/init" \
    -H "Content-Type: application/json" \
    -d "{\"Username\": \"$VPS_PORTAINER_USER\", \"Password\": \"$VPS_PORTAINER_PASS\"}")
  
  if echo "$RESPONSE" | jq -e '.Id' > /dev/null 2>&1; then
    echo "Admin criado com sucesso!"
    break
  fi
  
  echo "Tentativa $i falhou, aguardando 15s..."
  sleep 15
done

# Obter token JWT para validar
TOKEN=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/auth" \
  -H "Content-Type: application/json" \
  -d "{\"username\":\"$VPS_PORTAINER_USER\",\"password\":\"$VPS_PORTAINER_PASS\"}" | jq -r .jwt)

echo "Token: $TOKEN"

Verificação:

curl -k -s "https://$VPS_PORTAINER_DOMAIN/api/status" | jq .
# Esperado: JSON com Version e InstanceID

echo "Portainer acessível em: https://$VPS_PORTAINER_DOMAIN"
echo "Usuário: $VPS_PORTAINER_USER"

Etapa 8 - Deploy do PostgreSQL 14 (Banco de Dados)

O PostgreSQL é necessário para a Evolution API e outros serviços.

# Gerar senha do Postgres (ou usar VPS_POSTGRES_PASS se definida)
POSTGRES_PASS="${VPS_POSTGRES_PASS:-$(openssl rand -hex 16)}"
echo "Senha do PostgreSQL: $POSTGRES_PASS"

# Criar volume para dados do Postgres
docker volume create postgres_data

# Criar stack postgres.yaml
cat > /root/postgres.yaml << POSTGRESEOF
version: "3.7"
services:
  postgres:
    image: postgres:14
    command: >
      postgres
      -c max_connections=500
      -c shared_buffers=512MB
      -c timezone=America/Sao_Paulo

    volumes:
      - postgres_data:/var/lib/postgresql/data

    networks:
      - network_overlay

    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASS}
      - TZ=America/Sao_Paulo

    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      resources:
        limits:
          cpus: "1"
          memory: 1024M

volumes:
  postgres_data:
    external: true
    name: postgres_data

networks:
  network_overlay:
    external: true
    name: NETWORK_PLACEHOLDER
POSTGRESEOF

# Substituir placeholder da rede
sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/postgres.yaml

# Deploy
docker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres

Aguardar PostgreSQL ficar online:

while ! docker service ls --filter name='postgres_postgres' --format '{{.Replicas}}' | grep -q '1/1'; do
  echo "Aguardando PostgreSQL..."
  sleep 10
done
echo "PostgreSQL online!"

Verificação:

docker service ls --filter name=postgres
# Esperado: postgres_postgres 1/1

# Testar conexão
CONTAINER_ID=$(docker ps -q --filter "name=^postgres_postgres")
docker exec "$CONTAINER_ID" psql -U postgres -c "SELECT version();"
# Esperado: PostgreSQL 14.x

echo ""
echo "=== DADOS DO POSTGRESQL ==="
echo "Host: postgres (interno Docker)"
echo "Porta: 5432"
echo "Usuário: postgres"
echo "Senha: $POSTGRES_PASS"

Etapa 9 - Deploy da Evolution API v2 (WhatsApp)

Instala a Evolution API com Redis para cache e PostgreSQL como banco de dados.

# Obter senha do Postgres (já deve estar definida na Etapa 8)
POSTGRES_PASS="${VPS_POSTGRES_PASS:-$(grep 'POSTGRES_PASSWORD' /root/postgres.yaml | awk -F '=' '{print $2}')}"

# Gerar Global API Key (ou usar VPS_EVOLUTION_API_KEY se definida)
EVOLUTION_API_KEY="${VPS_EVOLUTION_API_KEY:-$(openssl rand -hex 16)}"
echo "Evolution Global API Key: $EVOLUTION_API_KEY"

# Criar banco de dados para a Evolution no PostgreSQL
CONTAINER_ID=$(docker ps -q --filter "name=^postgres_postgres")
docker exec "$CONTAINER_ID" psql -U postgres -c "CREATE DATABASE evolution;" 2>/dev/null || echo "Banco 'evolution' já existe"

# Criar volumes
docker volume create evolution_instances
docker volume create evolution_redis

# Criar stack evolution.yaml
cat > /root/evolution.yaml << 'EVOLUTIONEOF'
version: "3.7"
services:

  evolution_api:
    image: evoapicloud/evolution-api:latest

    volumes:
      - evolution_instances:/evolution/instances

    networks:
      - network_overlay

    environment:
    ## Configuracoes Gerais
      - SERVER_URL=https://EVOLUTION_DOMAIN_PLACEHOLDER
      - AUTHENTICATION_API_KEY=EVOLUTION_APIKEY_PLACEHOLDER
      - AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true
      - DEL_INSTANCE=false
      - QRCODE_LIMIT=1902
      - LANGUAGE=pt-BR

    ## Configuracao do Cliente
      - CONFIG_SESSION_PHONE_CLIENT=OpenClaw
      - CONFIG_SESSION_PHONE_NAME=Chrome

    ## Banco de Dados
      - DATABASE_ENABLED=true
      - DATABASE_PROVIDER=postgresql
      - DATABASE_CONNECTION_URI=postgresql://postgres:POSTGRES_PASS_PLACEHOLDER@postgres:5432/evolution
      - DATABASE_CONNECTION_CLIENT_NAME=evolution
      - DATABASE_SAVE_DATA_INSTANCE=true
      - DATABASE_SAVE_DATA_NEW_MESSAGE=true
      - DATABASE_SAVE_MESSAGE_UPDATE=true
      - DATABASE_SAVE_DATA_CONTACTS=true
      - DATABASE_SAVE_DATA_CHATS=true
      - DATABASE_SAVE_DATA_LABELS=true
      - DATABASE_SAVE_DATA_HISTORIC=true

    ## Integracoes (chatbots)
      - N8N_ENABLED=true
      - EVOAI_ENABLED=true
      - OPENAI_ENABLED=true
      - DIFY_ENABLED=true
      - TYPEBOT_ENABLED=true
      - TYPEBOT_API_VERSION=latest

    ## Chatwoot
      - CHATWOOT_ENABLED=true
      - CHATWOOT_MESSAGE_READ=true
      - CHATWOOT_MESSAGE_DELETE=true
      - CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=false

    ## Cache Redis
      - CACHE_REDIS_ENABLED=true
      - CACHE_REDIS_URI=redis://evolution_redis:6379/1
      - CACHE_REDIS_PREFIX_KEY=evolution
      - CACHE_REDIS_SAVE_INSTANCES=false
      - CACHE_LOCAL_ENABLED=false

    ## S3 (desabilitado por padrao)
      - S3_ENABLED=false

    ## WhatsApp Business (Cloud API)
      - WA_BUSINESS_TOKEN_WEBHOOK=evolution
      - WA_BUSINESS_URL=https://graph.facebook.com
      - WA_BUSINESS_VERSION=v23.0
      - WA_BUSINESS_LANGUAGE=pt_BR

    ## Telemetria
      - TELEMETRY=false

    ## WebSocket
      - WEBSOCKET_ENABLED=false
      - WEBSOCKET_GLOBAL_EVENTS=false

    ## RabbitMQ (desabilitado por padrao)
      - RABBITMQ_ENABLED=false

    ## Webhook (desabilitado por padrao)
      - WEBHOOK_GLOBAL_ENABLED=false

    ## SQS (desabilitado por padrao)
      - SQS_ENABLED=false

    ## Provider
      - PROVIDER_ENABLED=false

    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      labels:
        - traefik.enable=true
        - traefik.http.routers.evolution.rule=Host(`EVOLUTION_DOMAIN_PLACEHOLDER`)
        - traefik.http.routers.evolution.entrypoints=websecure
        - traefik.http.routers.evolution.priority=1
        - traefik.http.routers.evolution.tls.certresolver=letsencryptresolver
        - traefik.http.routers.evolution.service=evolution
        - traefik.http.services.evolution.loadbalancer.server.port=8080
        - traefik.http.services.evolution.loadbalancer.passHostHeader=true

  evolution_redis:
    image: redis:latest
    command: ["redis-server", "--appendonly", "yes", "--port", "6379"]

    volumes:
      - evolution_redis:/data

    networks:
      - network_overlay

    deploy:
      placement:
        constraints:
          - node.role == manager
      resources:
        limits:
          cpus: "1"
          memory: 1024M

volumes:
  evolution_instances:
    external: true
    name: evolution_instances
  evolution_redis:
    external: true
    name: evolution_redis

networks:
  network_overlay:
    external: true
    name: NETWORK_PLACEHOLDER
EVOLUTIONEOF

# Substituir placeholders
sed -i "s/EVOLUTION_DOMAIN_PLACEHOLDER/$VPS_EVOLUTION_DOMAIN/g" /root/evolution.yaml
sed -i "s/EVOLUTION_APIKEY_PLACEHOLDER/$EVOLUTION_API_KEY/g" /root/evolution.yaml
sed -i "s/POSTGRES_PASS_PLACEHOLDER/$POSTGRES_PASS/g" /root/evolution.yaml
sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/evolution.yaml

# Deploy
docker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution

Aguardar Evolution API ficar online:

# Aguardar Redis + Evolution API
while ! docker service ls --filter name='evolution_evolution_redis' --format '{{.Replicas}}' | grep -q '1/1'; do
  echo "Aguardando Redis..."
  sleep 10
done
echo "Redis online!"

while ! docker service ls --filter name='evolution_evolution_api' --format '{{.Replicas}}' | grep -q '1/1'; do
  echo "Aguardando Evolution API..."
  sleep 10
done
echo "Evolution API online!"

# Aguardar inicialização completa
sleep 30

Verificação:

docker service ls --filter name=evolution
# Esperado: evolution_evolution_api 1/1, evolution_evolution_redis 1/1

# Testar API
curl -sk "https://$VPS_EVOLUTION_DOMAIN" | head -c 200
# Esperado: resposta JSON da API

echo ""
echo "=== DADOS DA EVOLUTION API ==="
echo "Manager: https://$VPS_EVOLUTION_DOMAIN/manager"
echo "BaseUrl: https://$VPS_EVOLUTION_DOMAIN"
echo "Global API Key: $EVOLUTION_API_KEY"

Operações de Manutenção

Reiniciar Traefik

docker service update --force $(docker service ls --filter name='traefik_traefik' -q)

Reiniciar Portainer

docker service update --force $(docker service ls --filter name='portainer_agent' -q)
docker service update --force $(docker service ls --filter name='portainer_portainer' -q)

Atualizar Portainer

docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer

Reset Senha Portainer

# Parar Portainer
docker service scale portainer_portainer=0

# Reset
docker pull portainer/helper-reset-password
docker run --rm -v /var/lib/docker/volumes/portainer_data/_data:/data portainer/helper-reset-password

# Subir novamente
docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer

Atualizar Traefik

docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik

Ver Logs do Traefik

docker service logs traefik_traefik --tail 100 -f

Ver Logs do Portainer

docker service logs portainer_portainer --tail 100 -f

Reiniciar PostgreSQL

docker service update --force $(docker service ls --filter name='postgres_postgres' -q)

Reiniciar Evolution API

docker service update --force $(docker service ls --filter name='evolution_evolution_api' -q)
docker service update --force $(docker service ls --filter name='evolution_evolution_redis' -q)

Atualizar Evolution API

docker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution

Ver Logs da Evolution API

docker service logs evolution_evolution_api --tail 100 -f

Ver Logs do Redis (Evolution)

docker service logs evolution_evolution_redis --tail 50 -f

Criar Banco Adicional no PostgreSQL

CONTAINER_ID=$(docker ps -q --filter "name=^postgres_postgres")
docker exec "$CONTAINER_ID" psql -U postgres -c "CREATE DATABASE nome_do_banco;"

Listar Bancos no PostgreSQL

CONTAINER_ID=$(docker ps -q --filter "name=^postgres_postgres")
docker exec "$CONTAINER_ID" psql -U postgres -lqt

Deploy de Novos Serviços via Portainer API

Use a API do Portainer para deploy automatizado:

# 1. Obter token
TOKEN=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/auth" \
  -H "Content-Type: application/json" \
  -d "{\"username\":\"$VPS_PORTAINER_USER\",\"password\":\"$VPS_PORTAINER_PASS\"}" | jq -r .jwt)

# 2. Listar endpoints (stacks)
curl -k -s "https://$VPS_PORTAINER_DOMAIN/api/endpoints" \
  -H "Authorization: Bearer $TOKEN" | jq '.[].Id'

# 3. Deploy stack via API (exemplo)
curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/stacks/create/swarm/string?endpointId=1" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"meu-servico\",
    \"stackFileContent\": \"$(cat /root/meu-servico.yaml | jq -sR .)\"
  }"

Habilitar Dashboard do Traefik (Opcional)

Para acessar o painel do Traefik com autenticação:

# Gerar credenciais BasicAuth
TRAEFIK_USER="admin"
TRAEFIK_PASS="SuaSenhaForte123"
TRAEFIK_DOMAIN="traefik.seudominio.com"
BASICAUTH=$(htpasswd -nbB "$TRAEFIK_USER" "$TRAEFIK_PASS" | sed 's/\$/\$\$/g')

# Recriar traefik.yaml adicionando '--api.insecure=true' no command
# E estas labels extras no deploy:
#   - "traefik.http.routers.traefik.rule=Host(`$TRAEFIK_DOMAIN`)"
#   - "traefik.http.services.traefik.loadbalancer.server.port=8080"
#   - "traefik.http.routers.traefik.tls.certresolver=letsencryptresolver"
#   - "traefik.http.routers.traefik.service=traefik"
#   - "traefik.http.routers.traefik.entrypoints=websecure"
#   - "traefik.http.routers.traefik.priority=1"
#   - "traefik.http.routers.traefik.middlewares=authtraefik"
#   - "traefik.http.middlewares.authtraefik.basicauth.users=$BASICAUTH"

# Redeploy
docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik

Checklist Final

Após completar todas as etapas, verifique:

echo "=== Status dos Serviços ==="
docker service ls

echo ""
echo "=== Rede Overlay ==="
docker network ls | grep overlay

echo ""
echo "=== Volumes ==="
docker volume ls

echo ""
echo "=== Nodes do Swarm ==="
docker node ls

echo ""
echo "=== Portas em uso ==="
ss -tlnp | grep -E ':80|:443|:9000|:8080|:5432|:6379'

Resultado esperado:

Serviço Status URL
Traefik 1/1 (interno, gerencia SSL)
Portainer Agent 1/1 (global) (interno)
Portainer CE 1/1 https://$VPS_PORTAINER_DOMAIN
PostgreSQL 14 1/1 postgres:5432 (interno)
Evolution API 1/1 https://$VPS_EVOLUTION_DOMAIN
Evolution Redis 1/1 redis:6379 (interno)
Rede overlay ativa $VPS_NETWORK

Troubleshooting

Docker Swarm não inicia

# Verificar IP usado
hostname -I

# Forçar com IP específico
docker swarm init --advertise-addr SEU_IP_AQUI

Certificado SSL não gerado

# Verificar logs do Traefik
docker service logs traefik_traefik 2>&1 | grep -i "acme\|certificate\|error"

# Verificar se porta 80 está acessível externamente
curl -sI http://SEU_DOMINIO

Portainer API não responde

# Verificar se o container está rodando
docker service ps portainer_portainer

# Testar conectividade
curl -k -s https://$VPS_PORTAINER_DOMAIN/api/status

Container não conecta à rede

# Listar redes do container
docker inspect CONTAINER_ID | jq '.[].NetworkSettings.Networks'

# Reconectar
docker network connect $VPS_NETWORK CONTAINER_ID

PostgreSQL não inicia

# Verificar logs
docker service logs postgres_postgres --tail 50

# Verificar volume
docker volume inspect postgres_data

# Se o volume está corrompido, recriar (PERDA DE DADOS!)
# docker volume rm postgres_data && docker volume create postgres_data
# docker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres

Evolution API não conecta ao banco

# Verificar se o banco existe
CONTAINER_ID=$(docker ps -q --filter "name=^postgres_postgres")
docker exec "$CONTAINER_ID" psql -U postgres -lqt | grep evolution
# Se não existe, criar:
docker exec "$CONTAINER_ID" psql -U postgres -c "CREATE DATABASE evolution;"

# Verificar logs da Evolution
docker service logs evolution_evolution_api --tail 50 2>&1 | grep -i "database\|error\|postgres"

Evolution API retorna 401/403

# Verificar API Key configurada no YAML
grep "AUTHENTICATION_API_KEY" /root/evolution.yaml

# Testar com a API Key correta
curl -sk -H "apikey: SUA_API_KEY" "https://$VPS_EVOLUTION_DOMAIN/instance/fetchInstances"

Redis da Evolution não inicia

docker service logs evolution_evolution_redis --tail 30
# Verificar volume
docker volume inspect evolution_redis

Dicas

  1. Sempre use docker stack deploy em vez de docker compose up — Swarm gerencia réplicas, restart e rolling updates
  2. Todo serviço precisa estar na rede overlay $VPS_NETWORK para o Traefik fazer proxy
  3. Labels Traefik obrigatórias para cada serviço: traefik.enable=true, Host(), server.port, certresolver, entrypoints=websecure
  4. Nunca exponha portas diretamente — use Traefik como proxy reverso
  5. Salve os YAMLs em /root/ para facilitar redeploys futuros
  6. Portainer API permite deploy automatizado sem acessar o painel web

Reviews (0)

Sign in to write a review.

No reviews yet. Be the first to review!

Comments (0)

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts!

Compatible Platforms

Pricing

Free

Related Configs