Instalar Dokploy en DigitalOcean
Qué es esto: cómo montamos Dokploy (PaaS self-hosted) en un droplet de DigitalOcean, configurado como si fuera producción. El objetivo era evaluar si puede reemplazar Netlify / Render / Blackbird.
Versiones: Dokploy v0.29.12 · Ubuntu 24.04 LTS · Julio 2026
Parte 0 — Crear el droplet
| Campo | Valor |
|---|---|
| Plan | Basic / Shared CPU (Regular SSD) |
| Tamaño | $24/mo — 2 vCPU, 4 GB RAM, 80 GB SSD |
| Región | New York (NYC1) |
| OS | Ubuntu 24.04 LTS x64 |
| IP pública | 143.198.113.169 |
Por qué Regular y no Premium Intel: al mismo precio, Premium daba 2 GB de RAM contra 4 GB. Con Docker + Traefik + panel + apps, la RAM es el cuello de botella, no el CPU.
Opciones que apagamos y por qué:
| Opción | Estado | Razón |
|---|---|---|
| Backups automáticos | ❌ | El droplet del POC es desechable — si falla, se recrea |
| Managed Database ($15/mo) | ❌ | Dokploy gestiona las BD como contenedores; pagar esto iría contra el objetivo de reducir costos |
| Improved Metrics (Free) | ✅ | Gráficas de CPU/RAM/disco para ver si 4 GB aguantan |
Autenticación: password de root. El acceso habitual es por DigitalOcean Web Console (Droplet → Access → Launch Console), que funciona aunque se pierda la password. Se puede migrar a SSH keys después sin recrear el droplet.
Costo backups (referencia para producción): Weekly $4.80/mo (retención 28 días) · Daily $7.20/mo (7 días). Se activan cuando se quiera, sin recrear nada.
Parte 1 — Preparar el servidor
Acceso por Web Console como root. Si sale droplet-agent is not running, esperar 1–3 min y darle Reload (normal en droplet nuevo).
Zona horaria: se deja en UTC (estándar en servidores multi-proyecto; evita líos con horario de verano y cron). Cada app maneja su offset con la variable TZ.
Problema al hacer apt update — error de llave GPG:
NO_PUBKEY 77B79B3FFAF7EF65
Es una rotación de llave del lado de DigitalOcean (solo afecta al repo del Metrics Agent, no a los de Ubuntu). Se arregla con el script oficial, que limpia las fuentes viejas y reinstala la llave correcta:
curl -sSL https://repos.insights.digitalocean.com/install.sh | sudo bash
systemctl status do-agent # debe decir: active (running)
Después, actualizar el sistema:
apt update && apt upgrade -y
Parte 2 — Instalar Dokploy
Dokploy necesita los puertos 80, 443 y 3000 libres:
ss -tulnp | grep -E ':80 |:443 |:3000 ' # salida vacía = libres ✅
Instalación (script oficial, idempotente y reproducible):
curl -sSL https://dokploy.com/install.sh | sh
⚠️ El script corre
docker swarm leave --forceal inicio. Nunca correrlo en un servidor con Docker Swarm en producción.
Qué instala:
| Componente | Rol |
|---|---|
| Docker + Swarm | Motor de contenedores |
dokploy v0.29.12 | Panel web |
dokploy-postgres (PostgreSQL 16) | BD interna del panel |
dokploy-traefik (Traefik v3.6.7) | Reverse proxy + SSL automático |
Verificar:
docker service ls # dokploy y dokploy-postgres en 1/1
docker ps | grep traefik # traefik Up, puertos 80/443
Crear la cuenta admin: abrir http://143.198.113.169:3000 → pantalla "Setup the server" → llenar los datos.
- Usar correo de empresa (recuperable a nivel organización, no atado a una persona).
- Dokploy cierra el registro tras el primer usuario. Registrarse de inmediato — hasta entonces el panel está expuesto sin protección.
Parte 3 — Dominio y SSL
Dominio: inmersys.dev (Namecheap) · Subdominio del panel: panel.inmersys.dev
1. Registro DNS (Namecheap → Advanced DNS → Add New Record):
| Type | Host | Value |
|---|---|---|
| A Record | panel | 143.198.113.169 |
2. Verificar propagación (desde el droplet, que es lo que Let's Encrypt contacta):
dig +short panel.inmersys.dev # → 143.198.113.169 ✅
⚠️ No continuar hasta que el DNS resuelva. Si se pide el certificado antes, Let's Encrypt falla.
Los dominios
.devestán en la lista HSTS de Google: los navegadores fuerzan HTTPS. Sin SSL válido, el dominio no carga. En.devel SSL no es opcional.
3. Configurar en Dokploy (Settings → Web Server → Server Domain):
| Campo | Valor |
|---|---|
| Domain | panel.inmersys.dev |
| Let's Encrypt Email | developer@inmersys.com |
| HTTPS | ✅ |
| Certificate Provider | Let's Encrypt |
3.5 Problema encontrado: certificado ACME no se emitió al primer intento
Error en los logs de Traefik (docker logs --tail 50 dokploy-traefik):
ERR Unable to obtain ACME certificate ... error: 404 ... Certificate not found
No era fallo de DNS (ya propagaba, y el puerto 80 respondía con un 308 correcto). El estado de ACME quedó atorado con una solicitud fallida. Solución:
rm -f /etc/dokploy/traefik/dynamic/acme.json
docker restart dokploy-traefik
docker logs --since 5m dokploy-traefik # observar el reintento
⚠️ Rate limit de Let's Encrypt: ~5 fallos por hora por dominio. No repetir esto varias veces seguidas o el dominio queda bloqueado una hora.
Resultado: certificado emitido, panel en https://panel.inmersys.dev con SSL válido y renovación automática.
Pendientes para producción
Hardening
Cerrar el puerto 3000 (el panel sigue accesible por http://IP:3000 sin cifrar). Una vez confirmado que el dominio HTTPS carga bien:
docker service update --publish-rm "published=3000,target=3000,mode=host" dokploy
Otros pendientes: firewall (abrir solo 22, 80, 443), fail2ban, migrar de password a SSH keys.
Al migrar a producción real
| Ítem | Decisión |
|---|---|
| Droplet | Subir a $48/mo (4 vCPU, 8 GB RAM) |
| Backups | Activar (Weekly $4.80/mo alcanza) |
⚠️ Hallazgo para la evaluación
Dokploy no tiene "Netlify Drop" (arrastrar una carpeta dist/). Todos los métodos parten de un repo Git o una imagen Docker. Es una diferencia real frente a Netlify a considerar en la comparativa. (Sí hay subida de .zip, ver Desplegar con .zip.)