VPS Setup - Docker Swarm + Traefik + Portainer
Automates VPS setup with Docker Swarm, Traefik, and Portainer for efficient production deployment.
Install this skill
Security score
The VPS Setup - Docker Swarm + Traefik + Portainer skill was audited on May 15, 2026 and we found 71 security issues across 5 threat categories, including 2 high-severity. Review the findings below before installing.
Categories Tested
Security Issues
Template literal with variable interpolation in command context
| 387 | ```bash |
Template literal with variable interpolation in command context
| 479 | ```bash |
Piping content to bash shell
| 66 | curl -fsSL https://get.docker.com | bash |
Curl to non-GitHub URL
| 66 | curl -fsSL https://get.docker.com | bash |
Curl to non-GitHub URL
| 90 | curl -fsSL https://download.docker.com/linux/$OS_ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg |
Curl to non-GitHub URL
| 257 | curl -sI http://localhost:80 | head -3 |
Curl to non-GitHub URL
| 351 | RESPONSE=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/users/admin/init" \ |
Curl to non-GitHub URL
| 365 | TOKEN=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/auth" \ |
Curl to non-GitHub URL
| 374 | curl -k -s "https://$VPS_PORTAINER_DOMAIN/api/status" | jq . |
Curl to non-GitHub URL
| 668 | curl -sk "https://$VPS_EVOLUTION_DOMAIN" | head -c 200 |
Curl to non-GitHub URL
| 772 | TOKEN=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/auth" \ |
Curl to non-GitHub URL
| 777 | curl -k -s "https://$VPS_PORTAINER_DOMAIN/api/endpoints" \ |
Curl to non-GitHub URL
| 781 | curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/stacks/create/swarm/string?endpointId=1" \ |
Curl to non-GitHub URL
| 875 | curl -sI http://SEU_DOMINIO |
Curl to non-GitHub URL
| 884 | curl -k -s https://$VPS_PORTAINER_DOMAIN/api/status |
Curl to non-GitHub URL
| 927 | curl -sk -H "apikey: SUA_API_KEY" "https://$VPS_EVOLUTION_DOMAIN/instance/fetchInstances" |
Webhook reference - potential data exfiltration
| 560 | - WA_BUSINESS_TOKEN_WEBHOOK=evolution |
Webhook reference - potential data exfiltration
| 575 | ## Webhook (desabilitado por padrao) |
Webhook reference - potential data exfiltration
| 576 | - WEBHOOK_GLOBAL_ENABLED=false |
Access to root home directory
| 164 | cat > /root/traefik.yaml << 'TRAEFIKEOF' |
Access to root home directory
| 235 | sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/traefik.yaml |
Access to root home directory
| 236 | sed -i "s/EMAIL_PLACEHOLDER/$VPS_EMAIL_SSL/g" /root/traefik.yaml |
Access to root home directory
| 239 | docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik |
Access to root home directory
| 268 | cat > /root/portainer.yaml << 'PORTAINEREOF' |
Access to root home directory
| 318 | sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/portainer.yaml |
Access to root home directory
| 319 | sed -i "s/PORTAINER_DOMAIN_PLACEHOLDER/$VPS_PORTAINER_DOMAIN/g" /root/portainer.yaml |
Access to root home directory
| 322 | docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer |
Access to root home directory
| 396 | cat > /root/postgres.yaml << POSTGRESEOF |
Access to root home directory
| 440 | sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/postgres.yaml |
Access to root home directory
| 443 | docker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres |
Access to root home directory
| 481 | POSTGRES_PASS="${VPS_POSTGRES_PASS:-$(grep 'POSTGRES_PASSWORD' /root/postgres.yaml | awk -F '=' '{print $2}')}" |
Access to root home directory
| 496 | cat > /root/evolution.yaml << 'EVOLUTIONEOF' |
Access to root home directory
| 634 | sed -i "s/EVOLUTION_DOMAIN_PLACEHOLDER/$VPS_EVOLUTION_DOMAIN/g" /root/evolution.yaml |
Access to root home directory
| 635 | sed -i "s/EVOLUTION_APIKEY_PLACEHOLDER/$EVOLUTION_API_KEY/g" /root/evolution.yaml |
Access to root home directory
| 636 | sed -i "s/POSTGRES_PASS_PLACEHOLDER/$POSTGRES_PASS/g" /root/evolution.yaml |
Access to root home directory
| 637 | sed -i "s/NETWORK_PLACEHOLDER/$VPS_NETWORK/g" /root/evolution.yaml |
Access to root home directory
| 640 | docker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution |
Access to root home directory
| 695 | docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer |
Access to root home directory
| 708 | docker stack deploy --prune --resolve-image always -c /root/portainer.yaml portainer |
Access to root home directory
| 713 | docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik |
Access to root home directory
| 739 | docker stack deploy --prune --resolve-image always -c /root/evolution.yaml evolution |
Access to root home directory
| 786 | \"stackFileContent\": \"$(cat /root/meu-servico.yaml | jq -sR .)\" |
Access to root home directory
| 815 | docker stack deploy --prune --resolve-image always -c /root/traefik.yaml traefik |
Access to root home directory
| 906 | # docker stack deploy --prune --resolve-image always -c /root/postgres.yaml postgres |
Access to root home directory
| 924 | grep "AUTHENTICATION_API_KEY" /root/evolution.yaml |
Access to root home directory
| 945 | 5. **Salve os YAMLs** em `/root/` para facilitar redeploys futuros |
Access to system keychain/keyring
| 86 | sudo install -m 0755 -d /etc/apt/keyrings |
Access to system keychain/keyring
| 90 | curl -fsSL https://download.docker.com/linux/$OS_ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg |
Access to system keychain/keyring
| 91 | sudo chmod a+r /etc/apt/keyrings/docker.gpg |
Access to system keychain/keyring
| 93 | 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 |
External URL reference
| 66 | curl -fsSL https://get.docker.com | bash |
External URL reference
| 90 | curl -fsSL https://download.docker.com/linux/$OS_ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg |
External URL reference
| 93 | 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 |
External URL reference
| 257 | curl -sI http://localhost:80 | head -3 |
External URL reference
| 351 | RESPONSE=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/users/admin/init" \ |
External URL reference
| 365 | TOKEN=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/auth" \ |
External URL reference
| 374 | curl -k -s "https://$VPS_PORTAINER_DOMAIN/api/status" | jq . |
External URL reference
| 377 | echo "Portainer acessível em: https://$VPS_PORTAINER_DOMAIN" |
External URL reference
| 511 | - SERVER_URL=https://EVOLUTION_DOMAIN_PLACEHOLDER |
External URL reference
| 561 | - WA_BUSINESS_URL=https://graph.facebook.com |
External URL reference
| 668 | curl -sk "https://$VPS_EVOLUTION_DOMAIN" | head -c 200 |
External URL reference
| 673 | echo "Manager: https://$VPS_EVOLUTION_DOMAIN/manager" |
External URL reference
| 674 | echo "BaseUrl: https://$VPS_EVOLUTION_DOMAIN" |
External URL reference
| 772 | TOKEN=$(curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/auth" \ |
External URL reference
| 777 | curl -k -s "https://$VPS_PORTAINER_DOMAIN/api/endpoints" \ |
External URL reference
| 781 | curl -k -s -X POST "https://$VPS_PORTAINER_DOMAIN/api/stacks/create/swarm/string?endpointId=1" \ |
External URL reference
| 850 | | Portainer CE | 1/1 | `https://$VPS_PORTAINER_DOMAIN` | |
External URL reference
| 852 | | Evolution API | 1/1 | `https://$VPS_EVOLUTION_DOMAIN` | |
External URL reference
| 875 | curl -sI http://SEU_DOMINIO |
External URL reference
| 884 | curl -k -s https://$VPS_PORTAINER_DOMAIN/api/status |
External URL reference
| 927 | curl -sk -H "apikey: SUA_API_KEY" "https://$VPS_EVOLUTION_DOMAIN/instance/fetchInstances" |