{
  "schemaVersion": "1.0",
  "item": {
    "slug": "setuporion-byimpa",
    "name": "SetupOrion ByImpa",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/impa365/setuporion-byimpa",
    "canonicalUrl": "https://clawhub.ai/impa365/setuporion-byimpa",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/setuporion-byimpa",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=setuporion-byimpa",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/setuporion-byimpa"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/setuporion-byimpa",
    "agentPageUrl": "https://openagent3.xyz/skills/setuporion-byimpa/agent",
    "manifestUrl": "https://openagent3.xyz/skills/setuporion-byimpa/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/setuporion-byimpa/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "VPS Setup - Docker Swarm + Traefik + Portainer",
        "body": "Setup automatizado de VPS para produção. Instala Docker, inicia Swarm, cria rede overlay, deploya Traefik v3 com SSL automático e Portainer CE.\n\nRequisitos: Ubuntu 20.04+ ou Debian 11+ com acesso root/sudo."
      },
      {
        "title": "Execução Completa (todos os passos em ordem)",
        "body": "Execute cada etapa na ordem. Todas as etapas são idempotentes (seguro re-executar)."
      },
      {
        "title": "Etapa 1 - Atualizar Sistema e Configurar Servidor",
        "body": "# Atualizar sistema\nsudo apt-get update && sudo apt-get upgrade -y\n\n# Instalar utilitários essenciais\nsudo apt-get install -y apt-utils apparmor-utils curl jq htpasswd ca-certificates gnupg lsb-release\n\n# Configurar timezone\nsudo timedatectl set-timezone America/Sao_Paulo\n\n# Definir hostname do servidor\nsudo hostnamectl set-hostname $VPS_HOSTNAME\nsudo sed -i \"s/127.0.0.1[[:space:]]localhost/127.0.0.1 $VPS_HOSTNAME/g\" /etc/hosts\n\nVerificação:\n\ntimedatectl | grep \"Time zone\"\n# Esperado: America/Sao_Paulo\n\nhostname\n# Esperado: $VPS_HOSTNAME"
      },
      {
        "title": "Etapa 2 - Instalar Docker",
        "body": "# Instalar Docker via script oficial\ncurl -fsSL https://get.docker.com | bash\n\n# Habilitar e iniciar Docker\nsudo systemctl enable docker\nsudo systemctl start docker\n\n# Fix: garantir compatibilidade com API mínima\nsudo mkdir -p /etc/systemd/system/docker.service.d\nsudo bash -c 'cat > /etc/systemd/system/docker.service.d/override.conf <<EOF\n[Service]\nEnvironment=DOCKER_MIN_API_VERSION=1.24\nEOF'\n\nsudo systemctl daemon-reexec\nsudo systemctl daemon-reload\nsudo systemctl restart docker\n\nSe falhar, instalar manualmente:\n\nsudo install -m 0755 -d /etc/apt/keyrings\nOS_ID=$(source /etc/os-release && echo \"$ID\")\nOS_CODENAME=$(source /etc/os-release && echo \"$VERSION_CODENAME\")\n\ncurl -fsSL https://download.docker.com/linux/$OS_ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\nsudo chmod a+r /etc/apt/keyrings/docker.gpg\n\necho \"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\n\nsudo apt-get update\nsudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\nsudo systemctl enable docker\nsudo systemctl start docker\n\nVerificação:\n\ndocker --version\n# Esperado: Docker version 2X.x.x\n\ndocker info --format '{{.Swarm.LocalNodeState}}'\n# Esperado: inactive (ainda não iniciamos o Swarm)"
      },
      {
        "title": "Etapa 3 - Iniciar Docker Swarm",
        "body": "# Obter IP público da VPS (ignora loopback e IPs internos)\nIP=$(hostname -I | tr ' ' '\\n' | grep -v '^127\\.' | grep -v '^10\\.0\\.0\\.' | head -n1)\n\n# Iniciar Swarm\ndocker swarm init --advertise-addr $IP\n\nVerificação:\n\ndocker info --format '{{.Swarm.LocalNodeState}}'\n# Esperado: active\n\ndocker node ls\n# Esperado: 1 node com STATUS=Ready, MANAGER STATUS=Leader"
      },
      {
        "title": "Etapa 4 - Criar Rede Overlay e Volumes",
        "body": "# Criar rede overlay para comunicação entre containers\ndocker network create --driver=overlay $VPS_NETWORK\n\n# Criar volumes necessários\ndocker volume create volume_swarm_shared\ndocker volume create volume_swarm_certificates\ndocker volume create portainer_data\ndocker volume create postgres_data\ndocker volume create evolution_instances\ndocker volume create evolution_redis\n\nVerificação:\n\ndocker network ls | grep $VPS_NETWORK\n# Esperado: linha com $VPS_NETWORK, DRIVER=overlay, SCOPE=swarm\n\ndocker volume ls | grep -E \"shared|certificates|portainer|postgres|evolution\"\n# Esperado: 6 volumes listados"
      },
      {
        "title": "Etapa 5 - Deploy do Traefik v3 (Proxy Reverso + SSL)",
        "body": "Criar o arquivo traefik.yaml e fazer deploy:\n\ncat > /root/traefik.yaml << 'TRAEFIKEOF'\nversion: \"3.7\"\nservices:\n  traefik:\n    image: traefik:v3.5.3\n    command:\n      - \"--api.dashboard=true\"\n      - \"--providers.swarm=true\"\n      - \"--providers.docker.endpoint=unix:///var/run/docker.sock\"\n      - \"--providers.docker.exposedbydefault=false\"\n      - \"--providers.docker.network=NETWORK_PLACEHOLDER\"\n      - \"--entrypoints.web.address=:80\"\n      - \"--entrypoints.web.http.redirections.entryPoint.to=websecure\"\n      - \"--entrypoints.web.http.redirections.entryPoint.scheme=https\"\n      - \"--entrypoints.web.http.redirections.entrypoint.permanent=true\"\n      - \"--entrypoints.websecure.address=:443\"\n      - \"--entrypoints.web.transport.respondingTimeouts.idleTimeout=3600\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.storage=/etc/traefik/letsencrypt/acme.json\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.email=EMAIL_PLACEHOLDER\"\n      - \"--log.level=DEBUG\"\n      - \"--log.format=common\"\n      - \"--log.filePath=/var/log/traefik/traefik.log\"\n      - \"--accesslog=true\"\n      - \"--accesslog.filepath=/var/log/traefik/access-log\"\n\n    volumes:\n      - \"vol_certificates:/etc/traefik/letsencrypt\"\n      - \"/var/run/docker.sock:/var/run/docker.sock:ro\"\n\n    networks:\n      - network_overlay\n\n    ports:\n      - target: 80\n        published: 80\n        mode: host\n      - target: 443\n        published: 443\n        mode: host\n\n    deploy:\n      placement:\n        constraints:\n          - node.role == manager\n      labels:\n        - \"traefik.enable=true\"\n        - \"traefik.http.middlewares.redirect-https.redirectscheme.scheme=https\"\n        - \"traefik.http.middlewares.redirect-https.redirectscheme.permanent=true\"\n        - \"traefik.http.routers.http-catchall.rule=Host(`{host:.+}`)\"\n        - \"traefik.http.routers.http-catchall.entrypoints=web\"\n        - \"traefik.http.routers.http-catchall.middlewares=redirect-https@docker\"\n        - \"traefik.http.routers.http-catchall.priority=1\"\n\nvolumes:\n  vol_shared:\n    external: true\n    name: volume_swarm_shared\n  vol_certificates:\n    external: true\n    name: volume_swarm_certificates\n\nnetworks:\n  network_overlay:\n    external: true\n    attachable: true\n    name: NETWORK_PLACEHOLDER\nTRAEFIKEOF\n\n# Substituir placeholders pelas variáveis reais\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/traefik.yaml\nsed -i \"s/EMAIL_PLACEHOLDER/$VPS_EMAIL_SSL/g\" /root/traefik.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik\n\nAguardar Traefik ficar online:\n\n# Verificar a cada 10s até o serviço mostrar 1/1\nwhile ! docker service ls --filter name='traefik_traefik' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Traefik...\"\n  sleep 10\ndone\necho \"Traefik online!\"\n\nVerificação:\n\ndocker service ls --filter name=traefik\n# Esperado: traefik_traefik   1/1\n\ncurl -sI http://localhost:80 | head -3\n# Esperado: HTTP redirect ou resposta do Traefik"
      },
      {
        "title": "Etapa 6 - Deploy do Portainer CE (Gerenciador Docker)",
        "body": "Criar o arquivo portainer.yaml e fazer deploy:\n\ncat > /root/portainer.yaml << 'PORTAINEREOF'\nversion: \"3.7\"\nservices:\n  agent:\n    image: portainer/agent:latest\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n      - /var/lib/docker/volumes:/var/lib/docker/volumes\n    networks:\n      - network_overlay\n    deploy:\n      mode: global\n      placement:\n        constraints: [node.platform.os == linux]\n\n  portainer:\n    image: portainer/portainer-ce:latest\n    command: -H tcp://tasks.agent:9001 --tlsskipverify\n    volumes:\n      - portainer_data:/data\n    networks:\n      - network_overlay\n    deploy:\n      mode: replicated\n      replicas: 1\n      placement:\n        constraints: [node.role == manager]\n      labels:\n        - \"traefik.enable=true\"\n        - \"traefik.http.routers.portainer.rule=Host(`PORTAINER_DOMAIN_PLACEHOLDER`)\"\n        - \"traefik.http.services.portainer.loadbalancer.server.port=9000\"\n        - \"traefik.http.routers.portainer.tls.certresolver=letsencryptresolver\"\n        - \"traefik.http.routers.portainer.service=portainer\"\n        - \"traefik.docker.network=NETWORK_PLACEHOLDER\"\n        - \"traefik.http.routers.portainer.entrypoints=websecure\"\n        - \"traefik.http.routers.portainer.priority=1\"\n\nvolumes:\n  portainer_data:\n    external: true\n    name: portainer_data\n\nnetworks:\n  network_overlay:\n    external: true\n    attachable: true\n    name: NETWORK_PLACEHOLDER\nPORTAINEREOF\n\n# Substituir placeholders\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/portainer.yaml\nsed -i \"s/PORTAINER_DOMAIN_PLACEHOLDER/$VPS_PORTAINER_DOMAIN/g\" /root/portainer.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer\n\nAguardar Portainer ficar online:\n\n# Aguardar agent + portainer\nwhile ! docker service ls --filter name='portainer_portainer' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Portainer...\"\n  sleep 10\ndone\necho \"Portainer online!\"\n\nVerificação:\n\ndocker service ls --filter name=portainer\n# Esperado: portainer_agent 1/1 (global), portainer_portainer 1/1"
      },
      {
        "title": "Etapa 7 - Criar Conta Admin no Portainer",
        "body": "# Aguardar API do Portainer estar pronta (30s após container online)\nsleep 30\n\n# Criar usuário admin (tentativa com retry)\nfor i in 1 2 3 4; do\n  RESPONSE=$(curl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/users/admin/init\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"{\\\"Username\\\": \\\"$VPS_PORTAINER_USER\\\", \\\"Password\\\": \\\"$VPS_PORTAINER_PASS\\\"}\")\n  \n  if echo \"$RESPONSE\" | jq -e '.Id' > /dev/null 2>&1; then\n    echo \"Admin criado com sucesso!\"\n    break\n  fi\n  \n  echo \"Tentativa $i falhou, aguardando 15s...\"\n  sleep 15\ndone\n\n# Obter token JWT para validar\nTOKEN=$(curl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/auth\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\\\"username\\\":\\\"$VPS_PORTAINER_USER\\\",\\\"password\\\":\\\"$VPS_PORTAINER_PASS\\\"}\" | jq -r .jwt)\n\necho \"Token: $TOKEN\"\n\nVerificação:\n\ncurl -k -s \"https://$VPS_PORTAINER_DOMAIN/api/status\" | jq .\n# Esperado: JSON com Version e InstanceID\n\necho \"Portainer acessível em: https://$VPS_PORTAINER_DOMAIN\"\necho \"Usuário: $VPS_PORTAINER_USER\""
      },
      {
        "title": "Etapa 8 - Deploy do PostgreSQL 14 (Banco de Dados)",
        "body": "O PostgreSQL é necessário para a Evolution API e outros serviços.\n\n# Gerar senha do Postgres (ou usar VPS_POSTGRES_PASS se definida)\nPOSTGRES_PASS=\"${VPS_POSTGRES_PASS:-$(openssl rand -hex 16)}\"\necho \"Senha do PostgreSQL: $POSTGRES_PASS\"\n\n# Criar volume para dados do Postgres\ndocker volume create postgres_data\n\n# Criar stack postgres.yaml\ncat > /root/postgres.yaml << POSTGRESEOF\nversion: \"3.7\"\nservices:\n  postgres:\n    image: postgres:14\n    command: >\n      postgres\n      -c max_connections=500\n      -c shared_buffers=512MB\n      -c timezone=America/Sao_Paulo\n\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n\n    networks:\n      - network_overlay\n\n    environment:\n      - POSTGRES_PASSWORD=${POSTGRES_PASS}\n      - TZ=America/Sao_Paulo\n\n    deploy:\n      mode: replicated\n      replicas: 1\n      placement:\n        constraints:\n          - node.role == manager\n      resources:\n        limits:\n          cpus: \"1\"\n          memory: 1024M\n\nvolumes:\n  postgres_data:\n    external: true\n    name: postgres_data\n\nnetworks:\n  network_overlay:\n    external: true\n    name: NETWORK_PLACEHOLDER\nPOSTGRESEOF\n\n# Substituir placeholder da rede\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/postgres.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres\n\nAguardar PostgreSQL ficar online:\n\nwhile ! docker service ls --filter name='postgres_postgres' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando PostgreSQL...\"\n  sleep 10\ndone\necho \"PostgreSQL online!\"\n\nVerificação:\n\ndocker service ls --filter name=postgres\n# Esperado: postgres_postgres 1/1\n\n# Testar conexão\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"SELECT version();\"\n# Esperado: PostgreSQL 14.x\n\necho \"\"\necho \"=== DADOS DO POSTGRESQL ===\"\necho \"Host: postgres (interno Docker)\"\necho \"Porta: 5432\"\necho \"Usuário: postgres\"\necho \"Senha: $POSTGRES_PASS\""
      },
      {
        "title": "Etapa 9 - Deploy da Evolution API v2 (WhatsApp)",
        "body": "Instala a Evolution API com Redis para cache e PostgreSQL como banco de dados.\n\n# Obter senha do Postgres (já deve estar definida na Etapa 8)\nPOSTGRES_PASS=\"${VPS_POSTGRES_PASS:-$(grep 'POSTGRES_PASSWORD' /root/postgres.yaml | awk -F '=' '{print $2}')}\"\n\n# Gerar Global API Key (ou usar VPS_EVOLUTION_API_KEY se definida)\nEVOLUTION_API_KEY=\"${VPS_EVOLUTION_API_KEY:-$(openssl rand -hex 16)}\"\necho \"Evolution Global API Key: $EVOLUTION_API_KEY\"\n\n# Criar banco de dados para a Evolution no PostgreSQL\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"CREATE DATABASE evolution;\" 2>/dev/null || echo \"Banco 'evolution' já existe\"\n\n# Criar volumes\ndocker volume create evolution_instances\ndocker volume create evolution_redis\n\n# Criar stack evolution.yaml\ncat > /root/evolution.yaml << 'EVOLUTIONEOF'\nversion: \"3.7\"\nservices:\n\n  evolution_api:\n    image: evoapicloud/evolution-api:latest\n\n    volumes:\n      - evolution_instances:/evolution/instances\n\n    networks:\n      - network_overlay\n\n    environment:\n    ## Configuracoes Gerais\n      - SERVER_URL=https://EVOLUTION_DOMAIN_PLACEHOLDER\n      - AUTHENTICATION_API_KEY=EVOLUTION_APIKEY_PLACEHOLDER\n      - AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true\n      - DEL_INSTANCE=false\n      - QRCODE_LIMIT=1902\n      - LANGUAGE=pt-BR\n\n    ## Configuracao do Cliente\n      - CONFIG_SESSION_PHONE_CLIENT=OpenClaw\n      - CONFIG_SESSION_PHONE_NAME=Chrome\n\n    ## Banco de Dados\n      - DATABASE_ENABLED=true\n      - DATABASE_PROVIDER=postgresql\n      - DATABASE_CONNECTION_URI=postgresql://postgres:POSTGRES_PASS_PLACEHOLDER@postgres:5432/evolution\n      - DATABASE_CONNECTION_CLIENT_NAME=evolution\n      - DATABASE_SAVE_DATA_INSTANCE=true\n      - DATABASE_SAVE_DATA_NEW_MESSAGE=true\n      - DATABASE_SAVE_MESSAGE_UPDATE=true\n      - DATABASE_SAVE_DATA_CONTACTS=true\n      - DATABASE_SAVE_DATA_CHATS=true\n      - DATABASE_SAVE_DATA_LABELS=true\n      - DATABASE_SAVE_DATA_HISTORIC=true\n\n    ## Integracoes (chatbots)\n      - N8N_ENABLED=true\n      - EVOAI_ENABLED=true\n      - OPENAI_ENABLED=true\n      - DIFY_ENABLED=true\n      - TYPEBOT_ENABLED=true\n      - TYPEBOT_API_VERSION=latest\n\n    ## Chatwoot\n      - CHATWOOT_ENABLED=true\n      - CHATWOOT_MESSAGE_READ=true\n      - CHATWOOT_MESSAGE_DELETE=true\n      - CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=false\n\n    ## Cache Redis\n      - CACHE_REDIS_ENABLED=true\n      - CACHE_REDIS_URI=redis://evolution_redis:6379/1\n      - CACHE_REDIS_PREFIX_KEY=evolution\n      - CACHE_REDIS_SAVE_INSTANCES=false\n      - CACHE_LOCAL_ENABLED=false\n\n    ## S3 (desabilitado por padrao)\n      - S3_ENABLED=false\n\n    ## WhatsApp Business (Cloud API)\n      - WA_BUSINESS_TOKEN_WEBHOOK=evolution\n      - WA_BUSINESS_URL=https://graph.facebook.com\n      - WA_BUSINESS_VERSION=v23.0\n      - WA_BUSINESS_LANGUAGE=pt_BR\n\n    ## Telemetria\n      - TELEMETRY=false\n\n    ## WebSocket\n      - WEBSOCKET_ENABLED=false\n      - WEBSOCKET_GLOBAL_EVENTS=false\n\n    ## RabbitMQ (desabilitado por padrao)\n      - RABBITMQ_ENABLED=false\n\n    ## Webhook (desabilitado por padrao)\n      - WEBHOOK_GLOBAL_ENABLED=false\n\n    ## SQS (desabilitado por padrao)\n      - SQS_ENABLED=false\n\n    ## Provider\n      - PROVIDER_ENABLED=false\n\n    deploy:\n      mode: replicated\n      replicas: 1\n      placement:\n        constraints:\n          - node.role == manager\n      labels:\n        - traefik.enable=true\n        - traefik.http.routers.evolution.rule=Host(`EVOLUTION_DOMAIN_PLACEHOLDER`)\n        - traefik.http.routers.evolution.entrypoints=websecure\n        - traefik.http.routers.evolution.priority=1\n        - traefik.http.routers.evolution.tls.certresolver=letsencryptresolver\n        - traefik.http.routers.evolution.service=evolution\n        - traefik.http.services.evolution.loadbalancer.server.port=8080\n        - traefik.http.services.evolution.loadbalancer.passHostHeader=true\n\n  evolution_redis:\n    image: redis:latest\n    command: [\"redis-server\", \"--appendonly\", \"yes\", \"--port\", \"6379\"]\n\n    volumes:\n      - evolution_redis:/data\n\n    networks:\n      - network_overlay\n\n    deploy:\n      placement:\n        constraints:\n          - node.role == manager\n      resources:\n        limits:\n          cpus: \"1\"\n          memory: 1024M\n\nvolumes:\n  evolution_instances:\n    external: true\n    name: evolution_instances\n  evolution_redis:\n    external: true\n    name: evolution_redis\n\nnetworks:\n  network_overlay:\n    external: true\n    name: NETWORK_PLACEHOLDER\nEVOLUTIONEOF\n\n# Substituir placeholders\nsed -i \"s/EVOLUTION_DOMAIN_PLACEHOLDER/$VPS_EVOLUTION_DOMAIN/g\" /root/evolution.yaml\nsed -i \"s/EVOLUTION_APIKEY_PLACEHOLDER/$EVOLUTION_API_KEY/g\" /root/evolution.yaml\nsed -i \"s/POSTGRES_PASS_PLACEHOLDER/$POSTGRES_PASS/g\" /root/evolution.yaml\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/evolution.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution\n\nAguardar Evolution API ficar online:\n\n# Aguardar Redis + Evolution API\nwhile ! docker service ls --filter name='evolution_evolution_redis' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Redis...\"\n  sleep 10\ndone\necho \"Redis online!\"\n\nwhile ! docker service ls --filter name='evolution_evolution_api' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Evolution API...\"\n  sleep 10\ndone\necho \"Evolution API online!\"\n\n# Aguardar inicialização completa\nsleep 30\n\nVerificação:\n\ndocker service ls --filter name=evolution\n# Esperado: evolution_evolution_api 1/1, evolution_evolution_redis 1/1\n\n# Testar API\ncurl -sk \"https://$VPS_EVOLUTION_DOMAIN\" | head -c 200\n# Esperado: resposta JSON da API\n\necho \"\"\necho \"=== DADOS DA EVOLUTION API ===\"\necho \"Manager: https://$VPS_EVOLUTION_DOMAIN/manager\"\necho \"BaseUrl: https://$VPS_EVOLUTION_DOMAIN\"\necho \"Global API Key: $EVOLUTION_API_KEY\""
      },
      {
        "title": "Reiniciar Traefik",
        "body": "docker service update --force $(docker service ls --filter name='traefik_traefik' -q)"
      },
      {
        "title": "Reiniciar Portainer",
        "body": "docker service update --force $(docker service ls --filter name='portainer_agent' -q)\ndocker service update --force $(docker service ls --filter name='portainer_portainer' -q)"
      },
      {
        "title": "Atualizar Portainer",
        "body": "docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer"
      },
      {
        "title": "Reset Senha Portainer",
        "body": "# Parar Portainer\ndocker service scale portainer_portainer=0\n\n# Reset\ndocker pull portainer/helper-reset-password\ndocker run --rm -v /var/lib/docker/volumes/portainer_data/_data:/data portainer/helper-reset-password\n\n# Subir novamente\ndocker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer"
      },
      {
        "title": "Atualizar Traefik",
        "body": "docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik"
      },
      {
        "title": "Ver Logs do Traefik",
        "body": "docker service logs traefik_traefik --tail 100 -f"
      },
      {
        "title": "Ver Logs do Portainer",
        "body": "docker service logs portainer_portainer --tail 100 -f"
      },
      {
        "title": "Reiniciar PostgreSQL",
        "body": "docker service update --force $(docker service ls --filter name='postgres_postgres' -q)"
      },
      {
        "title": "Reiniciar Evolution API",
        "body": "docker service update --force $(docker service ls --filter name='evolution_evolution_api' -q)\ndocker service update --force $(docker service ls --filter name='evolution_evolution_redis' -q)"
      },
      {
        "title": "Atualizar Evolution API",
        "body": "docker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution"
      },
      {
        "title": "Ver Logs da Evolution API",
        "body": "docker service logs evolution_evolution_api --tail 100 -f"
      },
      {
        "title": "Ver Logs do Redis (Evolution)",
        "body": "docker service logs evolution_evolution_redis --tail 50 -f"
      },
      {
        "title": "Criar Banco Adicional no PostgreSQL",
        "body": "CONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"CREATE DATABASE nome_do_banco;\""
      },
      {
        "title": "Listar Bancos no PostgreSQL",
        "body": "CONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -lqt"
      },
      {
        "title": "Deploy de Novos Serviços via Portainer API",
        "body": "Use a API do Portainer para deploy automatizado:\n\n# 1. Obter token\nTOKEN=$(curl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/auth\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\\\"username\\\":\\\"$VPS_PORTAINER_USER\\\",\\\"password\\\":\\\"$VPS_PORTAINER_PASS\\\"}\" | jq -r .jwt)\n\n# 2. Listar endpoints (stacks)\ncurl -k -s \"https://$VPS_PORTAINER_DOMAIN/api/endpoints\" \\\n  -H \"Authorization: Bearer $TOKEN\" | jq '.[].Id'\n\n# 3. Deploy stack via API (exemplo)\ncurl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/stacks/create/swarm/string?endpointId=1\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\n    \\\"name\\\": \\\"meu-servico\\\",\n    \\\"stackFileContent\\\": \\\"$(cat /root/meu-servico.yaml | jq -sR .)\\\"\n  }\""
      },
      {
        "title": "Habilitar Dashboard do Traefik (Opcional)",
        "body": "Para acessar o painel do Traefik com autenticação:\n\n# Gerar credenciais BasicAuth\nTRAEFIK_USER=\"admin\"\nTRAEFIK_PASS=\"SuaSenhaForte123\"\nTRAEFIK_DOMAIN=\"traefik.seudominio.com\"\nBASICAUTH=$(htpasswd -nbB \"$TRAEFIK_USER\" \"$TRAEFIK_PASS\" | sed 's/\\$/\\$\\$/g')\n\n# Recriar traefik.yaml adicionando '--api.insecure=true' no command\n# E estas labels extras no deploy:\n#   - \"traefik.http.routers.traefik.rule=Host(`$TRAEFIK_DOMAIN`)\"\n#   - \"traefik.http.services.traefik.loadbalancer.server.port=8080\"\n#   - \"traefik.http.routers.traefik.tls.certresolver=letsencryptresolver\"\n#   - \"traefik.http.routers.traefik.service=traefik\"\n#   - \"traefik.http.routers.traefik.entrypoints=websecure\"\n#   - \"traefik.http.routers.traefik.priority=1\"\n#   - \"traefik.http.routers.traefik.middlewares=authtraefik\"\n#   - \"traefik.http.middlewares.authtraefik.basicauth.users=$BASICAUTH\"\n\n# Redeploy\ndocker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik"
      },
      {
        "title": "Checklist Final",
        "body": "Após completar todas as etapas, verifique:\n\necho \"=== Status dos Serviços ===\"\ndocker service ls\n\necho \"\"\necho \"=== Rede Overlay ===\"\ndocker network ls | grep overlay\n\necho \"\"\necho \"=== Volumes ===\"\ndocker volume ls\n\necho \"\"\necho \"=== Nodes do Swarm ===\"\ndocker node ls\n\necho \"\"\necho \"=== Portas em uso ===\"\nss -tlnp | grep -E ':80|:443|:9000|:8080|:5432|:6379'\n\nResultado esperado:\n\nServiçoStatusURLTraefik1/1(interno, gerencia SSL)Portainer Agent1/1 (global)(interno)Portainer CE1/1https://$VPS_PORTAINER_DOMAINPostgreSQL 141/1postgres:5432 (interno)Evolution API1/1https://$VPS_EVOLUTION_DOMAINEvolution Redis1/1redis:6379 (interno)Rede overlayativa$VPS_NETWORK"
      },
      {
        "title": "Docker Swarm não inicia",
        "body": "# Verificar IP usado\nhostname -I\n\n# Forçar com IP específico\ndocker swarm init --advertise-addr SEU_IP_AQUI"
      },
      {
        "title": "Certificado SSL não gerado",
        "body": "# Verificar logs do Traefik\ndocker service logs traefik_traefik 2>&1 | grep -i \"acme\\|certificate\\|error\"\n\n# Verificar se porta 80 está acessível externamente\ncurl -sI http://SEU_DOMINIO"
      },
      {
        "title": "Portainer API não responde",
        "body": "# Verificar se o container está rodando\ndocker service ps portainer_portainer\n\n# Testar conectividade\ncurl -k -s https://$VPS_PORTAINER_DOMAIN/api/status"
      },
      {
        "title": "Container não conecta à rede",
        "body": "# Listar redes do container\ndocker inspect CONTAINER_ID | jq '.[].NetworkSettings.Networks'\n\n# Reconectar\ndocker network connect $VPS_NETWORK CONTAINER_ID"
      },
      {
        "title": "PostgreSQL não inicia",
        "body": "# Verificar logs\ndocker service logs postgres_postgres --tail 50\n\n# Verificar volume\ndocker volume inspect postgres_data\n\n# Se o volume está corrompido, recriar (PERDA DE DADOS!)\n# docker volume rm postgres_data && docker volume create postgres_data\n# docker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres"
      },
      {
        "title": "Evolution API não conecta ao banco",
        "body": "# Verificar se o banco existe\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -lqt | grep evolution\n# Se não existe, criar:\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"CREATE DATABASE evolution;\"\n\n# Verificar logs da Evolution\ndocker service logs evolution_evolution_api --tail 50 2>&1 | grep -i \"database\\|error\\|postgres\""
      },
      {
        "title": "Evolution API retorna 401/403",
        "body": "# Verificar API Key configurada no YAML\ngrep \"AUTHENTICATION_API_KEY\" /root/evolution.yaml\n\n# Testar com a API Key correta\ncurl -sk -H \"apikey: SUA_API_KEY\" \"https://$VPS_EVOLUTION_DOMAIN/instance/fetchInstances\""
      },
      {
        "title": "Redis da Evolution não inicia",
        "body": "docker service logs evolution_evolution_redis --tail 30\n# Verificar volume\ndocker volume inspect evolution_redis"
      },
      {
        "title": "Dicas",
        "body": "Sempre use docker stack deploy em vez de docker compose up — Swarm gerencia réplicas, restart e rolling updates\nTodo serviço precisa estar na rede overlay $VPS_NETWORK para o Traefik fazer proxy\nLabels Traefik obrigatórias para cada serviço: traefik.enable=true, Host(), server.port, certresolver, entrypoints=websecure\nNunca exponha portas diretamente — use Traefik como proxy reverso\nSalve os YAMLs em /root/ para facilitar redeploys futuros\nPortainer API permite deploy automatizado sem acessar o painel web"
      }
    ],
    "body": "VPS Setup - Docker Swarm + Traefik + Portainer\n\nSetup automatizado de VPS para produção. Instala Docker, inicia Swarm, cria rede overlay, deploya Traefik v3 com SSL automático e Portainer CE.\n\nRequisitos: Ubuntu 20.04+ ou Debian 11+ com acesso root/sudo.\n\nExecução Completa (todos os passos em ordem)\n\nExecute cada etapa na ordem. Todas as etapas são idempotentes (seguro re-executar).\n\nEtapa 1 - Atualizar Sistema e Configurar Servidor\n# Atualizar sistema\nsudo apt-get update && sudo apt-get upgrade -y\n\n# Instalar utilitários essenciais\nsudo apt-get install -y apt-utils apparmor-utils curl jq htpasswd ca-certificates gnupg lsb-release\n\n# Configurar timezone\nsudo timedatectl set-timezone America/Sao_Paulo\n\n# Definir hostname do servidor\nsudo hostnamectl set-hostname $VPS_HOSTNAME\nsudo sed -i \"s/127.0.0.1[[:space:]]localhost/127.0.0.1 $VPS_HOSTNAME/g\" /etc/hosts\n\n\nVerificação:\n\ntimedatectl | grep \"Time zone\"\n# Esperado: America/Sao_Paulo\n\nhostname\n# Esperado: $VPS_HOSTNAME\n\nEtapa 2 - Instalar Docker\n# Instalar Docker via script oficial\ncurl -fsSL https://get.docker.com | bash\n\n# Habilitar e iniciar Docker\nsudo systemctl enable docker\nsudo systemctl start docker\n\n# Fix: garantir compatibilidade com API mínima\nsudo mkdir -p /etc/systemd/system/docker.service.d\nsudo bash -c 'cat > /etc/systemd/system/docker.service.d/override.conf <<EOF\n[Service]\nEnvironment=DOCKER_MIN_API_VERSION=1.24\nEOF'\n\nsudo systemctl daemon-reexec\nsudo systemctl daemon-reload\nsudo systemctl restart docker\n\n\nSe falhar, instalar manualmente:\n\nsudo install -m 0755 -d /etc/apt/keyrings\nOS_ID=$(source /etc/os-release && echo \"$ID\")\nOS_CODENAME=$(source /etc/os-release && echo \"$VERSION_CODENAME\")\n\ncurl -fsSL https://download.docker.com/linux/$OS_ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\nsudo chmod a+r /etc/apt/keyrings/docker.gpg\n\necho \"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\n\nsudo apt-get update\nsudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\nsudo systemctl enable docker\nsudo systemctl start docker\n\n\nVerificação:\n\ndocker --version\n# Esperado: Docker version 2X.x.x\n\ndocker info --format '{{.Swarm.LocalNodeState}}'\n# Esperado: inactive (ainda não iniciamos o Swarm)\n\nEtapa 3 - Iniciar Docker Swarm\n# Obter IP público da VPS (ignora loopback e IPs internos)\nIP=$(hostname -I | tr ' ' '\\n' | grep -v '^127\\.' | grep -v '^10\\.0\\.0\\.' | head -n1)\n\n# Iniciar Swarm\ndocker swarm init --advertise-addr $IP\n\n\nVerificação:\n\ndocker info --format '{{.Swarm.LocalNodeState}}'\n# Esperado: active\n\ndocker node ls\n# Esperado: 1 node com STATUS=Ready, MANAGER STATUS=Leader\n\nEtapa 4 - Criar Rede Overlay e Volumes\n# Criar rede overlay para comunicação entre containers\ndocker network create --driver=overlay $VPS_NETWORK\n\n# Criar volumes necessários\ndocker volume create volume_swarm_shared\ndocker volume create volume_swarm_certificates\ndocker volume create portainer_data\ndocker volume create postgres_data\ndocker volume create evolution_instances\ndocker volume create evolution_redis\n\n\nVerificação:\n\ndocker network ls | grep $VPS_NETWORK\n# Esperado: linha com $VPS_NETWORK, DRIVER=overlay, SCOPE=swarm\n\ndocker volume ls | grep -E \"shared|certificates|portainer|postgres|evolution\"\n# Esperado: 6 volumes listados\n\nEtapa 5 - Deploy do Traefik v3 (Proxy Reverso + SSL)\n\nCriar o arquivo traefik.yaml e fazer deploy:\n\ncat > /root/traefik.yaml << 'TRAEFIKEOF'\nversion: \"3.7\"\nservices:\n  traefik:\n    image: traefik:v3.5.3\n    command:\n      - \"--api.dashboard=true\"\n      - \"--providers.swarm=true\"\n      - \"--providers.docker.endpoint=unix:///var/run/docker.sock\"\n      - \"--providers.docker.exposedbydefault=false\"\n      - \"--providers.docker.network=NETWORK_PLACEHOLDER\"\n      - \"--entrypoints.web.address=:80\"\n      - \"--entrypoints.web.http.redirections.entryPoint.to=websecure\"\n      - \"--entrypoints.web.http.redirections.entryPoint.scheme=https\"\n      - \"--entrypoints.web.http.redirections.entrypoint.permanent=true\"\n      - \"--entrypoints.websecure.address=:443\"\n      - \"--entrypoints.web.transport.respondingTimeouts.idleTimeout=3600\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.storage=/etc/traefik/letsencrypt/acme.json\"\n      - \"--certificatesresolvers.letsencryptresolver.acme.email=EMAIL_PLACEHOLDER\"\n      - \"--log.level=DEBUG\"\n      - \"--log.format=common\"\n      - \"--log.filePath=/var/log/traefik/traefik.log\"\n      - \"--accesslog=true\"\n      - \"--accesslog.filepath=/var/log/traefik/access-log\"\n\n    volumes:\n      - \"vol_certificates:/etc/traefik/letsencrypt\"\n      - \"/var/run/docker.sock:/var/run/docker.sock:ro\"\n\n    networks:\n      - network_overlay\n\n    ports:\n      - target: 80\n        published: 80\n        mode: host\n      - target: 443\n        published: 443\n        mode: host\n\n    deploy:\n      placement:\n        constraints:\n          - node.role == manager\n      labels:\n        - \"traefik.enable=true\"\n        - \"traefik.http.middlewares.redirect-https.redirectscheme.scheme=https\"\n        - \"traefik.http.middlewares.redirect-https.redirectscheme.permanent=true\"\n        - \"traefik.http.routers.http-catchall.rule=Host(`{host:.+}`)\"\n        - \"traefik.http.routers.http-catchall.entrypoints=web\"\n        - \"traefik.http.routers.http-catchall.middlewares=redirect-https@docker\"\n        - \"traefik.http.routers.http-catchall.priority=1\"\n\nvolumes:\n  vol_shared:\n    external: true\n    name: volume_swarm_shared\n  vol_certificates:\n    external: true\n    name: volume_swarm_certificates\n\nnetworks:\n  network_overlay:\n    external: true\n    attachable: true\n    name: NETWORK_PLACEHOLDER\nTRAEFIKEOF\n\n# Substituir placeholders pelas variáveis reais\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/traefik.yaml\nsed -i \"s/EMAIL_PLACEHOLDER/$VPS_EMAIL_SSL/g\" /root/traefik.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik\n\n\nAguardar Traefik ficar online:\n\n# Verificar a cada 10s até o serviço mostrar 1/1\nwhile ! docker service ls --filter name='traefik_traefik' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Traefik...\"\n  sleep 10\ndone\necho \"Traefik online!\"\n\n\nVerificação:\n\ndocker service ls --filter name=traefik\n# Esperado: traefik_traefik   1/1\n\ncurl -sI http://localhost:80 | head -3\n# Esperado: HTTP redirect ou resposta do Traefik\n\nEtapa 6 - Deploy do Portainer CE (Gerenciador Docker)\n\nCriar o arquivo portainer.yaml e fazer deploy:\n\ncat > /root/portainer.yaml << 'PORTAINEREOF'\nversion: \"3.7\"\nservices:\n  agent:\n    image: portainer/agent:latest\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n      - /var/lib/docker/volumes:/var/lib/docker/volumes\n    networks:\n      - network_overlay\n    deploy:\n      mode: global\n      placement:\n        constraints: [node.platform.os == linux]\n\n  portainer:\n    image: portainer/portainer-ce:latest\n    command: -H tcp://tasks.agent:9001 --tlsskipverify\n    volumes:\n      - portainer_data:/data\n    networks:\n      - network_overlay\n    deploy:\n      mode: replicated\n      replicas: 1\n      placement:\n        constraints: [node.role == manager]\n      labels:\n        - \"traefik.enable=true\"\n        - \"traefik.http.routers.portainer.rule=Host(`PORTAINER_DOMAIN_PLACEHOLDER`)\"\n        - \"traefik.http.services.portainer.loadbalancer.server.port=9000\"\n        - \"traefik.http.routers.portainer.tls.certresolver=letsencryptresolver\"\n        - \"traefik.http.routers.portainer.service=portainer\"\n        - \"traefik.docker.network=NETWORK_PLACEHOLDER\"\n        - \"traefik.http.routers.portainer.entrypoints=websecure\"\n        - \"traefik.http.routers.portainer.priority=1\"\n\nvolumes:\n  portainer_data:\n    external: true\n    name: portainer_data\n\nnetworks:\n  network_overlay:\n    external: true\n    attachable: true\n    name: NETWORK_PLACEHOLDER\nPORTAINEREOF\n\n# Substituir placeholders\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/portainer.yaml\nsed -i \"s/PORTAINER_DOMAIN_PLACEHOLDER/$VPS_PORTAINER_DOMAIN/g\" /root/portainer.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer\n\n\nAguardar Portainer ficar online:\n\n# Aguardar agent + portainer\nwhile ! docker service ls --filter name='portainer_portainer' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Portainer...\"\n  sleep 10\ndone\necho \"Portainer online!\"\n\n\nVerificação:\n\ndocker service ls --filter name=portainer\n# Esperado: portainer_agent 1/1 (global), portainer_portainer 1/1\n\nEtapa 7 - Criar Conta Admin no Portainer\n# Aguardar API do Portainer estar pronta (30s após container online)\nsleep 30\n\n# Criar usuário admin (tentativa com retry)\nfor i in 1 2 3 4; do\n  RESPONSE=$(curl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/users/admin/init\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"{\\\"Username\\\": \\\"$VPS_PORTAINER_USER\\\", \\\"Password\\\": \\\"$VPS_PORTAINER_PASS\\\"}\")\n  \n  if echo \"$RESPONSE\" | jq -e '.Id' > /dev/null 2>&1; then\n    echo \"Admin criado com sucesso!\"\n    break\n  fi\n  \n  echo \"Tentativa $i falhou, aguardando 15s...\"\n  sleep 15\ndone\n\n# Obter token JWT para validar\nTOKEN=$(curl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/auth\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\\\"username\\\":\\\"$VPS_PORTAINER_USER\\\",\\\"password\\\":\\\"$VPS_PORTAINER_PASS\\\"}\" | jq -r .jwt)\n\necho \"Token: $TOKEN\"\n\n\nVerificação:\n\ncurl -k -s \"https://$VPS_PORTAINER_DOMAIN/api/status\" | jq .\n# Esperado: JSON com Version e InstanceID\n\necho \"Portainer acessível em: https://$VPS_PORTAINER_DOMAIN\"\necho \"Usuário: $VPS_PORTAINER_USER\"\n\nEtapa 8 - Deploy do PostgreSQL 14 (Banco de Dados)\n\nO PostgreSQL é necessário para a Evolution API e outros serviços.\n\n# Gerar senha do Postgres (ou usar VPS_POSTGRES_PASS se definida)\nPOSTGRES_PASS=\"${VPS_POSTGRES_PASS:-$(openssl rand -hex 16)}\"\necho \"Senha do PostgreSQL: $POSTGRES_PASS\"\n\n# Criar volume para dados do Postgres\ndocker volume create postgres_data\n\n# Criar stack postgres.yaml\ncat > /root/postgres.yaml << POSTGRESEOF\nversion: \"3.7\"\nservices:\n  postgres:\n    image: postgres:14\n    command: >\n      postgres\n      -c max_connections=500\n      -c shared_buffers=512MB\n      -c timezone=America/Sao_Paulo\n\n    volumes:\n      - postgres_data:/var/lib/postgresql/data\n\n    networks:\n      - network_overlay\n\n    environment:\n      - POSTGRES_PASSWORD=${POSTGRES_PASS}\n      - TZ=America/Sao_Paulo\n\n    deploy:\n      mode: replicated\n      replicas: 1\n      placement:\n        constraints:\n          - node.role == manager\n      resources:\n        limits:\n          cpus: \"1\"\n          memory: 1024M\n\nvolumes:\n  postgres_data:\n    external: true\n    name: postgres_data\n\nnetworks:\n  network_overlay:\n    external: true\n    name: NETWORK_PLACEHOLDER\nPOSTGRESEOF\n\n# Substituir placeholder da rede\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/postgres.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres\n\n\nAguardar PostgreSQL ficar online:\n\nwhile ! docker service ls --filter name='postgres_postgres' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando PostgreSQL...\"\n  sleep 10\ndone\necho \"PostgreSQL online!\"\n\n\nVerificação:\n\ndocker service ls --filter name=postgres\n# Esperado: postgres_postgres 1/1\n\n# Testar conexão\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"SELECT version();\"\n# Esperado: PostgreSQL 14.x\n\necho \"\"\necho \"=== DADOS DO POSTGRESQL ===\"\necho \"Host: postgres (interno Docker)\"\necho \"Porta: 5432\"\necho \"Usuário: postgres\"\necho \"Senha: $POSTGRES_PASS\"\n\nEtapa 9 - Deploy da Evolution API v2 (WhatsApp)\n\nInstala a Evolution API com Redis para cache e PostgreSQL como banco de dados.\n\n# Obter senha do Postgres (já deve estar definida na Etapa 8)\nPOSTGRES_PASS=\"${VPS_POSTGRES_PASS:-$(grep 'POSTGRES_PASSWORD' /root/postgres.yaml | awk -F '=' '{print $2}')}\"\n\n# Gerar Global API Key (ou usar VPS_EVOLUTION_API_KEY se definida)\nEVOLUTION_API_KEY=\"${VPS_EVOLUTION_API_KEY:-$(openssl rand -hex 16)}\"\necho \"Evolution Global API Key: $EVOLUTION_API_KEY\"\n\n# Criar banco de dados para a Evolution no PostgreSQL\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"CREATE DATABASE evolution;\" 2>/dev/null || echo \"Banco 'evolution' já existe\"\n\n# Criar volumes\ndocker volume create evolution_instances\ndocker volume create evolution_redis\n\n# Criar stack evolution.yaml\ncat > /root/evolution.yaml << 'EVOLUTIONEOF'\nversion: \"3.7\"\nservices:\n\n  evolution_api:\n    image: evoapicloud/evolution-api:latest\n\n    volumes:\n      - evolution_instances:/evolution/instances\n\n    networks:\n      - network_overlay\n\n    environment:\n    ## Configuracoes Gerais\n      - SERVER_URL=https://EVOLUTION_DOMAIN_PLACEHOLDER\n      - AUTHENTICATION_API_KEY=EVOLUTION_APIKEY_PLACEHOLDER\n      - AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true\n      - DEL_INSTANCE=false\n      - QRCODE_LIMIT=1902\n      - LANGUAGE=pt-BR\n\n    ## Configuracao do Cliente\n      - CONFIG_SESSION_PHONE_CLIENT=OpenClaw\n      - CONFIG_SESSION_PHONE_NAME=Chrome\n\n    ## Banco de Dados\n      - DATABASE_ENABLED=true\n      - DATABASE_PROVIDER=postgresql\n      - DATABASE_CONNECTION_URI=postgresql://postgres:POSTGRES_PASS_PLACEHOLDER@postgres:5432/evolution\n      - DATABASE_CONNECTION_CLIENT_NAME=evolution\n      - DATABASE_SAVE_DATA_INSTANCE=true\n      - DATABASE_SAVE_DATA_NEW_MESSAGE=true\n      - DATABASE_SAVE_MESSAGE_UPDATE=true\n      - DATABASE_SAVE_DATA_CONTACTS=true\n      - DATABASE_SAVE_DATA_CHATS=true\n      - DATABASE_SAVE_DATA_LABELS=true\n      - DATABASE_SAVE_DATA_HISTORIC=true\n\n    ## Integracoes (chatbots)\n      - N8N_ENABLED=true\n      - EVOAI_ENABLED=true\n      - OPENAI_ENABLED=true\n      - DIFY_ENABLED=true\n      - TYPEBOT_ENABLED=true\n      - TYPEBOT_API_VERSION=latest\n\n    ## Chatwoot\n      - CHATWOOT_ENABLED=true\n      - CHATWOOT_MESSAGE_READ=true\n      - CHATWOOT_MESSAGE_DELETE=true\n      - CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=false\n\n    ## Cache Redis\n      - CACHE_REDIS_ENABLED=true\n      - CACHE_REDIS_URI=redis://evolution_redis:6379/1\n      - CACHE_REDIS_PREFIX_KEY=evolution\n      - CACHE_REDIS_SAVE_INSTANCES=false\n      - CACHE_LOCAL_ENABLED=false\n\n    ## S3 (desabilitado por padrao)\n      - S3_ENABLED=false\n\n    ## WhatsApp Business (Cloud API)\n      - WA_BUSINESS_TOKEN_WEBHOOK=evolution\n      - WA_BUSINESS_URL=https://graph.facebook.com\n      - WA_BUSINESS_VERSION=v23.0\n      - WA_BUSINESS_LANGUAGE=pt_BR\n\n    ## Telemetria\n      - TELEMETRY=false\n\n    ## WebSocket\n      - WEBSOCKET_ENABLED=false\n      - WEBSOCKET_GLOBAL_EVENTS=false\n\n    ## RabbitMQ (desabilitado por padrao)\n      - RABBITMQ_ENABLED=false\n\n    ## Webhook (desabilitado por padrao)\n      - WEBHOOK_GLOBAL_ENABLED=false\n\n    ## SQS (desabilitado por padrao)\n      - SQS_ENABLED=false\n\n    ## Provider\n      - PROVIDER_ENABLED=false\n\n    deploy:\n      mode: replicated\n      replicas: 1\n      placement:\n        constraints:\n          - node.role == manager\n      labels:\n        - traefik.enable=true\n        - traefik.http.routers.evolution.rule=Host(`EVOLUTION_DOMAIN_PLACEHOLDER`)\n        - traefik.http.routers.evolution.entrypoints=websecure\n        - traefik.http.routers.evolution.priority=1\n        - traefik.http.routers.evolution.tls.certresolver=letsencryptresolver\n        - traefik.http.routers.evolution.service=evolution\n        - traefik.http.services.evolution.loadbalancer.server.port=8080\n        - traefik.http.services.evolution.loadbalancer.passHostHeader=true\n\n  evolution_redis:\n    image: redis:latest\n    command: [\"redis-server\", \"--appendonly\", \"yes\", \"--port\", \"6379\"]\n\n    volumes:\n      - evolution_redis:/data\n\n    networks:\n      - network_overlay\n\n    deploy:\n      placement:\n        constraints:\n          - node.role == manager\n      resources:\n        limits:\n          cpus: \"1\"\n          memory: 1024M\n\nvolumes:\n  evolution_instances:\n    external: true\n    name: evolution_instances\n  evolution_redis:\n    external: true\n    name: evolution_redis\n\nnetworks:\n  network_overlay:\n    external: true\n    name: NETWORK_PLACEHOLDER\nEVOLUTIONEOF\n\n# Substituir placeholders\nsed -i \"s/EVOLUTION_DOMAIN_PLACEHOLDER/$VPS_EVOLUTION_DOMAIN/g\" /root/evolution.yaml\nsed -i \"s/EVOLUTION_APIKEY_PLACEHOLDER/$EVOLUTION_API_KEY/g\" /root/evolution.yaml\nsed -i \"s/POSTGRES_PASS_PLACEHOLDER/$POSTGRES_PASS/g\" /root/evolution.yaml\nsed -i \"s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g\" /root/evolution.yaml\n\n# Deploy\ndocker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution\n\n\nAguardar Evolution API ficar online:\n\n# Aguardar Redis + Evolution API\nwhile ! docker service ls --filter name='evolution_evolution_redis' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Redis...\"\n  sleep 10\ndone\necho \"Redis online!\"\n\nwhile ! docker service ls --filter name='evolution_evolution_api' --format '{{.Replicas}}' | grep -q '1/1'; do\n  echo \"Aguardando Evolution API...\"\n  sleep 10\ndone\necho \"Evolution API online!\"\n\n# Aguardar inicialização completa\nsleep 30\n\n\nVerificação:\n\ndocker service ls --filter name=evolution\n# Esperado: evolution_evolution_api 1/1, evolution_evolution_redis 1/1\n\n# Testar API\ncurl -sk \"https://$VPS_EVOLUTION_DOMAIN\" | head -c 200\n# Esperado: resposta JSON da API\n\necho \"\"\necho \"=== DADOS DA EVOLUTION API ===\"\necho \"Manager: https://$VPS_EVOLUTION_DOMAIN/manager\"\necho \"BaseUrl: https://$VPS_EVOLUTION_DOMAIN\"\necho \"Global API Key: $EVOLUTION_API_KEY\"\n\nOperações de Manutenção\nReiniciar Traefik\ndocker service update --force $(docker service ls --filter name='traefik_traefik' -q)\n\nReiniciar Portainer\ndocker service update --force $(docker service ls --filter name='portainer_agent' -q)\ndocker service update --force $(docker service ls --filter name='portainer_portainer' -q)\n\nAtualizar Portainer\ndocker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer\n\nReset Senha Portainer\n# Parar Portainer\ndocker service scale portainer_portainer=0\n\n# Reset\ndocker pull portainer/helper-reset-password\ndocker run --rm -v /var/lib/docker/volumes/portainer_data/_data:/data portainer/helper-reset-password\n\n# Subir novamente\ndocker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer\n\nAtualizar Traefik\ndocker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik\n\nVer Logs do Traefik\ndocker service logs traefik_traefik --tail 100 -f\n\nVer Logs do Portainer\ndocker service logs portainer_portainer --tail 100 -f\n\nReiniciar PostgreSQL\ndocker service update --force $(docker service ls --filter name='postgres_postgres' -q)\n\nReiniciar Evolution API\ndocker service update --force $(docker service ls --filter name='evolution_evolution_api' -q)\ndocker service update --force $(docker service ls --filter name='evolution_evolution_redis' -q)\n\nAtualizar Evolution API\ndocker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution\n\nVer Logs da Evolution API\ndocker service logs evolution_evolution_api --tail 100 -f\n\nVer Logs do Redis (Evolution)\ndocker service logs evolution_evolution_redis --tail 50 -f\n\nCriar Banco Adicional no PostgreSQL\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"CREATE DATABASE nome_do_banco;\"\n\nListar Bancos no PostgreSQL\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -lqt\n\nDeploy de Novos Serviços via Portainer API\n\nUse a API do Portainer para deploy automatizado:\n\n# 1. Obter token\nTOKEN=$(curl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/auth\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\\\"username\\\":\\\"$VPS_PORTAINER_USER\\\",\\\"password\\\":\\\"$VPS_PORTAINER_PASS\\\"}\" | jq -r .jwt)\n\n# 2. Listar endpoints (stacks)\ncurl -k -s \"https://$VPS_PORTAINER_DOMAIN/api/endpoints\" \\\n  -H \"Authorization: Bearer $TOKEN\" | jq '.[].Id'\n\n# 3. Deploy stack via API (exemplo)\ncurl -k -s -X POST \"https://$VPS_PORTAINER_DOMAIN/api/stacks/create/swarm/string?endpointId=1\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \"{\n    \\\"name\\\": \\\"meu-servico\\\",\n    \\\"stackFileContent\\\": \\\"$(cat /root/meu-servico.yaml | jq -sR .)\\\"\n  }\"\n\nHabilitar Dashboard do Traefik (Opcional)\n\nPara acessar o painel do Traefik com autenticação:\n\n# Gerar credenciais BasicAuth\nTRAEFIK_USER=\"admin\"\nTRAEFIK_PASS=\"SuaSenhaForte123\"\nTRAEFIK_DOMAIN=\"traefik.seudominio.com\"\nBASICAUTH=$(htpasswd -nbB \"$TRAEFIK_USER\" \"$TRAEFIK_PASS\" | sed 's/\\$/\\$\\$/g')\n\n# Recriar traefik.yaml adicionando '--api.insecure=true' no command\n# E estas labels extras no deploy:\n#   - \"traefik.http.routers.traefik.rule=Host(`$TRAEFIK_DOMAIN`)\"\n#   - \"traefik.http.services.traefik.loadbalancer.server.port=8080\"\n#   - \"traefik.http.routers.traefik.tls.certresolver=letsencryptresolver\"\n#   - \"traefik.http.routers.traefik.service=traefik\"\n#   - \"traefik.http.routers.traefik.entrypoints=websecure\"\n#   - \"traefik.http.routers.traefik.priority=1\"\n#   - \"traefik.http.routers.traefik.middlewares=authtraefik\"\n#   - \"traefik.http.middlewares.authtraefik.basicauth.users=$BASICAUTH\"\n\n# Redeploy\ndocker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik\n\nChecklist Final\n\nApós completar todas as etapas, verifique:\n\necho \"=== Status dos Serviços ===\"\ndocker service ls\n\necho \"\"\necho \"=== Rede Overlay ===\"\ndocker network ls | grep overlay\n\necho \"\"\necho \"=== Volumes ===\"\ndocker volume ls\n\necho \"\"\necho \"=== Nodes do Swarm ===\"\ndocker node ls\n\necho \"\"\necho \"=== Portas em uso ===\"\nss -tlnp | grep -E ':80|:443|:9000|:8080|:5432|:6379'\n\n\nResultado esperado:\n\nServiço\tStatus\tURL\nTraefik\t1/1\t(interno, gerencia SSL)\nPortainer Agent\t1/1 (global)\t(interno)\nPortainer CE\t1/1\thttps://$VPS_PORTAINER_DOMAIN\nPostgreSQL 14\t1/1\tpostgres:5432 (interno)\nEvolution API\t1/1\thttps://$VPS_EVOLUTION_DOMAIN\nEvolution Redis\t1/1\tredis:6379 (interno)\nRede overlay\tativa\t$VPS_NETWORK\nTroubleshooting\nDocker Swarm não inicia\n# Verificar IP usado\nhostname -I\n\n# Forçar com IP específico\ndocker swarm init --advertise-addr SEU_IP_AQUI\n\nCertificado SSL não gerado\n# Verificar logs do Traefik\ndocker service logs traefik_traefik 2>&1 | grep -i \"acme\\|certificate\\|error\"\n\n# Verificar se porta 80 está acessível externamente\ncurl -sI http://SEU_DOMINIO\n\nPortainer API não responde\n# Verificar se o container está rodando\ndocker service ps portainer_portainer\n\n# Testar conectividade\ncurl -k -s https://$VPS_PORTAINER_DOMAIN/api/status\n\nContainer não conecta à rede\n# Listar redes do container\ndocker inspect CONTAINER_ID | jq '.[].NetworkSettings.Networks'\n\n# Reconectar\ndocker network connect $VPS_NETWORK CONTAINER_ID\n\nPostgreSQL não inicia\n# Verificar logs\ndocker service logs postgres_postgres --tail 50\n\n# Verificar volume\ndocker volume inspect postgres_data\n\n# Se o volume está corrompido, recriar (PERDA DE DADOS!)\n# docker volume rm postgres_data && docker volume create postgres_data\n# docker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres\n\nEvolution API não conecta ao banco\n# Verificar se o banco existe\nCONTAINER_ID=$(docker ps -q --filter \"name=^postgres_postgres\")\ndocker exec \"$CONTAINER_ID\" psql -U postgres -lqt | grep evolution\n# Se não existe, criar:\ndocker exec \"$CONTAINER_ID\" psql -U postgres -c \"CREATE DATABASE evolution;\"\n\n# Verificar logs da Evolution\ndocker service logs evolution_evolution_api --tail 50 2>&1 | grep -i \"database\\|error\\|postgres\"\n\nEvolution API retorna 401/403\n# Verificar API Key configurada no YAML\ngrep \"AUTHENTICATION_API_KEY\" /root/evolution.yaml\n\n# Testar com a API Key correta\ncurl -sk -H \"apikey: SUA_API_KEY\" \"https://$VPS_EVOLUTION_DOMAIN/instance/fetchInstances\"\n\nRedis da Evolution não inicia\ndocker service logs evolution_evolution_redis --tail 30\n# Verificar volume\ndocker volume inspect evolution_redis\n\nDicas\nSempre use docker stack deploy em vez de docker compose up — Swarm gerencia réplicas, restart e rolling updates\nTodo serviço precisa estar na rede overlay $VPS_NETWORK para o Traefik fazer proxy\nLabels Traefik obrigatórias para cada serviço: traefik.enable=true, Host(), server.port, certresolver, entrypoints=websecure\nNunca exponha portas diretamente — use Traefik como proxy reverso\nSalve os YAMLs em /root/ para facilitar redeploys futuros\nPortainer API permite deploy automatizado sem acessar o painel web"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/impa365/setuporion-byimpa",
    "publisherUrl": "https://clawhub.ai/impa365/setuporion-byimpa",
    "owner": "impa365",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/setuporion-byimpa",
    "downloadUrl": "https://openagent3.xyz/downloads/setuporion-byimpa",
    "agentUrl": "https://openagent3.xyz/skills/setuporion-byimpa/agent",
    "manifestUrl": "https://openagent3.xyz/skills/setuporion-byimpa/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/setuporion-byimpa/agent.md"
  }
}