Publicar un dominio con HTTPS en tu VPS: nginx, certificados y el 502 de todos los días
Publicado el 2026-08-25 por frfrand
Cómo publicar un dominio en un VPS con certificado SSL: qué hace realmente Let's Encrypt, por qué el orden de los pasos importa, cómo leer los logs de nginx para diagnosticar un 502 y cómo hacerlo todo conversando con una IA. Cubre crear_dominio_vps, verificar_dominio_vps, activar_dominio_vps, ver_nginx_dominio_vps, editar_nginx_dominio_vps y ver_logs_nginx_vps.

Poner un dominio en producción con HTTPS son unos pocos pasos que casi siempre se hacen en el orden equivocado, y de ahí sale la frustración: el certificado falla, aparece un 502 y nadie sabe si el problema es el DNS, el proxy o la aplicación.
En ArduMaker hay además una vuelta de tuerca que explica la mayoría de los tropiezos, y que esta guía cuenta primero: tu VPS es un contenedor dentro de un host padre compartido, y las tres cosas que hacen falta para publicar un dominio —el certificado, el nginx de borde y la redirección de puerto— viven en ese host, no en tu máquina. Entender dónde pasa cada cosa hace que el resto sea casi obvio.
Herramientas cubiertas: crear_dominio_vps, listar_dominios_vps, verificar_dominio_vps, activar_dominio_vps, eliminar_dominio_vps, ver_nginx_dominio_vps, editar_nginx_dominio_vps, ver_logs_nginx_vps, y del área vecina listar_redirecciones_vps y crear_redireccion_vps, que en la práctica son parte del mismo procedimiento.
Todas llevan company_id además del vps_id. Si no sabés cuál es, listar_empresas te lo dice, y ver_contexto_inicial te devuelve de una todas las empresas, proyectos y VPS que tu sesión puede ver.
Antes de nada: tu VPS no está solo en la máquina
Casi todo lo que confunde al publicar un dominio en ArduMaker se aclara entendiendo una sola cosa: hay dos capas, y usted administra la de arriba.
El host padre. Es la máquina física, compartida, con la IP pública. Ahí viven tres cosas que no toca nunca: el nginx de borde que termina el HTTPS, los certificados (certbot corre ahí, no en su VPS) y las redirecciones de puerto que conectan el mundo con su máquina. No tiene acceso a esa capa, y es a propósito: es compartida con otros clientes.
Su VPS. Es un container LXC dentro de ese host. Ahí corren sus aplicaciones, sus servicios systemd, sus tareas, sus usuarios de Linux y, si quiere, su propio nginx interno. Todo eso sí es suyo y lo administra entero.
La consecuencia práctica, y es la más importante de esta guía:
Su VPS no tiene IP pública propia. La IP que ve internet es la del host padre, compartida. Lo que hace que su aplicación sea alcanzable no es la IP: es una redirección de puerto. El host abre un puerto suyo y lo conecta contra un puerto de adentro de su container.
internet → IP del host padre → nginx de borde (TLS) → 127.0.0.1:<puerto del host>
↓ redirección
tu VPS → 127.0.0.1:<puerto del container>
Cada VPS arranca además con un nombre DNS propio, del estilo <slug>.arducloud.com, con un registro A que apunta a la IP del host padre. Ese nombre es el que después usa como destino cuando conecta un dominio propio.
Guarda el diagrama en la cabeza. Los tres errores más comunes de esta guía son, en el fondo, el mismo error: confundir el puerto de adentro del VPS con el puerto del host.
Dos caminos distintos, y conviene saber en cuál estás
Publicar un dominio no es un solo procedimiento: son dos, y se comportan de forma muy distinta.
Camino A — un subdominio de la zona por defecto de ArduMaker
Es el camino corto. crear_dominio_vps crea, en la zona de ArduMaker en Cloudflare, un CNAME proxeado que apunta al nombre DNS de tu VPS. No hace falta que toques ningún registrador.
Y acá está lo que casi nadie sabe: en este camino no se emite ningún certificado. El dominio queda cubierto por el certificado de la zona por defecto, que ya existe en el host padre. Por eso tampoco hay verificación de DNS previa, ni validación ACME, ni límites semanales de Let's Encrypt que respetar. Activás y anda.
Dos restricciones de forma que conviene saber de antemano, porque la herramienta las rechaza: el subdominio puede tener una o dos partes (app.arducloud.com o app.cliente.arducloud.com, no más), y cada parte necesita al menos 3 caracteres alfanuméricos.
Camino B — un dominio propio
Acá sí importa el orden, y mucho.
activar_dominio_vps ejecuta certbot certonly --standalone en el host padre. "Standalone" quiere decir que certbot levanta él mismo un servidor en el puerto 80 para responder el desafío de Let's Encrypt: para poder hacerlo, detiene nginx, emite, y lo vuelve a levantar. No es un archivo servido por tu aplicación en /.well-known/acme-challenge/ — tu VPS no participa de la validación en absoluto.
De ahí se deduce lo mismo que decía el orden clásico, pero por el motivo correcto: Let's Encrypt va a consultar el DNS de tu dominio y a golpear la IP que encuentre. Si esa IP no es la del host padre donde corre certbot, la validación falla. Primero el DNS, después la activación. Y sí: los intentos fallidos cuentan contra el límite semanal por dominio.
El orden correcto, entonces:
- Apuntá el dominio, con un A a la IP del host padre o —más cómodo— con un CNAME al nombre DNS del VPS (
<slug>.arducloud.com). - Verificá con
verificar_dominio_vpsantes de activar. - Activá con
activar_dominio_vps, que emite el certificado y escribe el nginx de borde.
Una advertencia sobre verificar_dominio_vps: es más permisiva de lo que parece. Si el nombre resuelve a la IP del host, da OK (a_record). Si resuelve por CNAME al nombre del VPS, también (cname). Pero si resuelve a cualquier otra IP —el caso típico de un dominio proxeado por Cloudflare, donde el mundo ve las IPs de Cloudflare y no la tuya— también da OK, marcado como proxy_forwarded. El único caso que falla de verdad es que el nombre no resuelva a nada.
O sea: un OK de verificar_dominio_vps te confirma que el nombre existe en el DNS, no siempre que llegue a tu host. Si el dominio está proxeado y la nube naranja apunta a otro servidor, la verificación pasa y el certificado igual falla. Cuando dudes, mirá el verify_method que devuelve: proxy_forwarded es "no pude comprobarlo", no "está bien".
Las otras herramientas del área:
listar_dominios_vps muestra qué dominios del nginx de borde corresponden a esta máquina. Los cruza por puerto del host, y por cada dominio te dice a qué puerto del host apunta y —el dato útil— a qué puerto de adentro del container corresponde ese puerto (puerto_in_vps). Es la forma más rápida de reconstruir el camino completo de un sitio publicado.
eliminar_dominio_vps hace la baja: borra el registro DNS si estaba bajo la zona por defecto y limpia la configuración del nginx de borde. No borra el certificado — la respuesta lo dice explícitamente (ssl_cert_deleted: false). Si volvés a publicar el mismo nombre más adelante, el certificado sigue ahí.
Los errores que vas a ver, y qué significa cada uno
Cuando algo falla después de publicar, el código de error te dice bastante más de lo que parece.
502 Bad Gateway — nginx está vivo, del otro lado no hay nadie. El más frecuente y el peor entendido. Nginx recibió la petición, intentó pasarla y no obtuvo respuesta. En esta arquitectura el 502 tiene una causa extra que no existe en un servidor común: puede que la aplicación esté perfecta y lo que falte sea la redirección. El nginx de borde apunta a un puerto del host; si ese puerto no está conectado contra el puerto correcto de adentro del container, el 502 aparece aunque tu app esté escuchando impecablemente. Antes de tocar la app, mirá listar_redirecciones_vps.
504 Gateway Timeout — la aplicación está viva pero tarda demasiado. Nginx conectó, pero no hubo respuesta a tiempo. Vale una precisión local: el nginx de borde ya viene con timeouts de 360 segundos. Si te da 504, no es que el timeout esté corto — seis minutos sin responder es una consulta trabada o un proceso bloqueado, y ahí es donde hay que mirar.
404 sirviendo el sitio equivocado — te falta el server_name. Si al entrar a tu dominio ves otro sitio, nginx no encontró un bloque que coincida con ese nombre y cayó en el sitio por defecto. Es un problema de server_name, no de DNS.
Certificado inválido o "no seguro" en el navegador. El certificado cubre exactamente los nombres para los que se emitió. Si se emitió para midominio.com y entras por www.midominio.com, el navegador protesta con razón.
Las tres herramientas de nginx, y cuál es cuál
Acá está el malentendido que más tiempo hace perder, así que conviene decirlo sin vueltas: estas herramientas no operan todas sobre el mismo nginx.
activar_dominio_vps, listar_dominios_vps y eliminar_dominio_vps trabajan sobre el nginx de borde, en el host padre. Es el que termina el HTTPS y el que decide a qué puerto del host va cada dominio. No hay ninguna herramienta para leer ni editar a mano ese archivo: se administra con activar_dominio_vps y nada más. Tampoco podés leer sus logs.
ver_nginx_dominio_vps, editar_nginx_dominio_vps y ver_logs_nginx_vps trabajan sobre el nginx de adentro de tu VPS. Ese es enteramente tuyo: leen y escriben /etc/nginx/sites-available/<dominio>.conf dentro del container, y los logs que devuelven son /var/log/nginx/<dominio>_access.log y _error.log, también dentro del container.
La consecuencia práctica, en dos puntos:
- Si publicaste un dominio solo con
activar_dominio_vps,ver_logs_nginx_vpsno va a encontrar nada. Esos archivos de log existen únicamente si el nginx interno de tu VPS sirve ese dominio y los declara. No es un error de la herramienta: es que ese tráfico lo está registrando el nginx de borde, en una capa a la que no tenés acceso. editar_nginx_dominio_vpsno cambia a qué puerto del host apunta el borde. Si querés que un dominio publicado apunte a otra aplicación, lo que hay que cambiar es la redirección o volver a activar el dominio contra otro puerto del host, no reescribir el archivo de adentro.
Cuándo usar cada camino, entonces:
- Un dominio, una aplicación, un puerto →
activar_dominio_vpsy listo. No necesitás nginx adentro del VPS para nada. - Varias rutas, varias apps, reglas propias detrás del mismo dominio → activá el dominio contra el puerto donde escucha tu nginx interno, y usá
editar_nginx_dominio_vpspara todo el ruteo fino. Ahí síver_logs_nginx_vpste va a dar logs, porque el que atiende es el tuyo.
Sobre editar_nginx_dominio_vps: es un reemplazo completo del archivo, no un parche. Pídele siempre a la IA que primero lea la configuración actual, aplique el cambio sobre ese contenido y escriba el resultado entero. Lo que sí trae es una red de seguridad que conviene conocer: antes de escribir hace backup, después valida con nginx -t y recarga, y si la validación o el reload fallan revierte solo —archivo y symlink— y te devuelve el error de nginx. No vas a dejar el VPS sin nginx por un error de sintaxis.
Un detalle que ahorra trabajo inútil: el nginx de borde ya viene con client_max_body_size 100M, las cabeceras de WebSocket (Upgrade / Connection) y los headers X-Forwarded-* puestos. Si tu problema es que no se pueden subir archivos grandes o que un WebSocket no conecta, eso ya está resuelto en el borde: el que puede estar limitando es tu nginx interno o la aplicación, no la capa que no ves.
TÚ: Publicá app.cliente.com en el VPS 9, la app corre en el 3000.
IA: listar_redirecciones_vps(company_id = 3, vps_id = 9) -> no hay ninguna redirección contra el puerto 3000
"Ojo con un paso que falta. Tu app escucha en el 3000 adentro del container, pero el nginx que termina el HTTPS vive en el host padre y solo sabe hablar con puertos del host. Necesito crear la redirección primero, si no el dominio queda publicado contra el puerto equivocado y vas a ver un 502."
TÚ: Dale.
IA: crear_redireccion_vps(company_id = 3, vps_id = 9, container_port = 3000) -> { "host_port": 21874, "container_port": 3000, "protocol": "tcp" }
verificar_dominio_vps(company_id = 3, vps_id = 9, domain = "app.cliente.com") -> el nombre no resuelve
"El dominio todavía no apunta a ningún lado. Antes de activar hay que apuntarlo: un A a la IP del host padre, o —más cómodo— un CNAME a <slug>.arducloud.com, que ya tiene el A correcto.
Si activo ahora, certbot corre en el host, la validación de Let's Encrypt no encuentra el dominio y el intento fallido cuenta contra el límite semanal."
[más tarde]
TÚ: Listo, ya puse el CNAME.
IA: verificar_dominio_vps(company_id = 3, vps_id = 9, domain = "app.cliente.com") -> { "matches_host": true, "verify_method": "cname" }
activar_dominio_vps(company_id = 3, vps_id = 9, domain = "app.cliente.com", host_port = 21874) -> certificado emitido, nginx de borde configurado
"Publicado con HTTPS. El camino queda así: app.cliente.com -> host padre :21874 -> tu VPS :3000."
TÚ: Entro y me da 502.
IA: listar_dominios_vps(company_id = 3, vps_id = 9) -> app.cliente.com -> puerto del host 21874 puerto_in_vps: container_port 3000
ejecutar_comando_vps(company_id = 3, vps_id = 9, script = "ss -lntp | grep -E ':(3000|3001)'") -> la app está escuchando en el 3001, no en el 3000
"El camino de red está bien armado: el dominio va al 21874 del host y ese puerto entra al 3000 del container. El que no está es el 3000: la app arrancó en el 3001.
Dos opciones: cambio el puerto de la app, o creo una redirección contra el 3001 y reactivo el dominio contra el puerto del host que salga. ¿Cuál preferís?"
Preguntas frecuentes
¿Mi VPS tiene IP pública propia? No. La IP que ve internet es la del host padre, compartida con otros VPS. Lo que hace alcanzable a tu máquina es una redirección de puerto. Cada VPS sí tiene un nombre DNS propio (<slug>.arducloud.com) con un registro A a esa IP, y es el destino más cómodo para un CNAME desde tu dominio.
¿Por qué falla la emisión del certificado? Porque el DNS no lleva a la IP del host padre donde corre certbot. Verificá el DNS primero; los reintentos a ciegas gastan cupo del límite semanal de Let's Encrypt. Y recordá que un OK de verificar_dominio_vps con verify_method: proxy_forwarded significa "el nombre resuelve pero no pude confirmar que llegue acá", no "está todo bien".
¿Un subdominio de la zona de ArduMaker también emite certificado? No, y por eso es el camino rápido: queda cubierto por el certificado de la zona por defecto, que ya existe en el host. Sin validación ACME y sin límites semanales.
¿Los certificados se renuevan solos? Los de Let's Encrypt duran 90 días y están pensados para renovarse automáticamente, en el host padre. Como esa capa no es tuya, no es algo que administres — pero sí vale confirmar que un sitio sigue con certificado válido antes de que falte una semana, no después.
Tengo un 502, ¿reinicio nginx? Casi nunca es la solución, y además el nginx que importa acá suele ser el de borde, que no podés reiniciar. Mirá tres cosas en este orden: que exista la redirección contra el puerto correcto (listar_redirecciones_vps), que el dominio esté apuntado a ese puerto del host (listar_dominios_vps) y que la app esté efectivamente escuchando.
¿Puedo leer los logs del nginx que termina el HTTPS? No. ver_logs_nginx_vps lee el nginx de adentro de tu VPS. Si publicaste el dominio solo con activar_dominio_vps, no hay logs para leer de tu lado — el tráfico lo registra la capa del host. Si querés logs propios por dominio, poné tu nginx interno en el camino.
¿Necesito un certificado aparte para www? El certificado cubre los nombres exactos para los que se emitió. Si querés servir el dominio con y sin www, ambos nombres tienen que estar contemplados, cada uno con su activación.
¿Puedo editar el nginx a mano? El de adentro de tu VPS, sí, y a veces hace falta. La edición reemplaza el archivo completo, así que leé la configuración actual antes de escribir la nueva — aunque si la nueva no valida, el cambio se revierte solo.
¿Cómo conecto el MCP? Agregando https://mcp.ardumaker.com/mcp en un cliente compatible y autorizándolo con tu cuenta.
Parte de la serie de guías sobre las herramientas del MCP de ArduMaker. La guía anterior cubre DNS, registros y propagación.