← Todos los artículos

Cómo alojar varios proyectos en un servidor con subdominios

DNS, hosts virtuales Apache, puertos locales y HTTPS. Una guía práctica basada en 40i.net, donde sitios estáticos y aplicaciones Rails comparten un servidor.

Un subdominio da una dirección, pero no aísla una aplicación. DNS dirige el nombre a una IP; Apache elige un sitio según el host; el host sirve archivos o envía la petición a un proceso local. En 40i.net, el dominio raíz sirve una wiki estática desde /var/www/40i-wiki, site-builder.40i.net usa un proxy a Rails en 127.0.0.1:3000 y otros subdominios tienen directorios o backends propios.

¿Cómo llega una petición al proyecto correcto?

El recorrido tiene cuatro decisiones: DNS resuelve el nombre a una IP; TLS selecciona el certificado; Apache elige un host virtual según el nombre solicitado; el host sirve archivos o reenvía la petición a un puerto local. DNS no inicia la aplicación ni emite su certificado, y Apache no mantiene el proceso activo. Cuando un sitio falla, revisa cada capa por separado.

Recorrido de una petición en un servidor
Navegador
  │  https://app.example.com
  ▼
DNS A / comodín ──► SERVER_IP
  │
  ▼
Apache :443 ── certificado TLS + host virtual por Host
  ├── DocumentRoot ──► archivos del sitio
  └── ProxyPass ─────► 127.0.0.1:3001 (proceso)

¿Qué registros DNS necesitan los subdominios?

Crea un registro A para cada subdominio de proyecto que apunte a la IPv4 pública del servidor. Un comodín *.example.com puede dirigir otros subdominios a la misma IP; el dominio raíz necesita su propio registro. Los registros DNS más específicos prevalecen. El comodín facilita resolver nombres, pero no crea sitios web. Conserva MX, SPF, DKIM y DMARC al editar el DNS web.

¿Por qué mantener Apache en vez de cambiar a nginx?

Esta decisión se refiere al servidor que ya atiende los proyectos, no afirma que Apache sea siempre mejor. El host 40i.net ejecuta Apache 2.4; nginx no está instalado. ISPConfig administra los archivos de hosts virtuales de Apache y la ruta de validación ACME, y los sitios, registros y renovaciones de certificados ya dependen de esa configuración. ISPConfig admite Apache y nginx, así que el panel por sí solo no determina la elección. En este servidor, conservar Apache evita migrar los hosts virtuales generados y el flujo TLS o añadir otra capa de proxy, con poca ganancia práctica para la carga actual. nginx es una opción válida para un servidor nuevo o una necesidad medida; el cambio requiere un plan para todos los sitios, el servicio que poseerá los puertos 80/443, la renovación de certificados y la reversión.

Cómo encajan ISPConfig y el servidor web
Panel ISPConfig
  └── genera y administra hosts virtuales y la ruta ACME
       │
       ▼
Apache 2.4 (activo en 40i.net)
  ├── sitios estáticos
  └── proxy inverso ──► app en 127.0.0.1:PORT

nginx: no está instalado en este host

¿Cómo selecciona Apache el host virtual?

Apache compara la cabecera HTTP Host con ServerName y ServerAlias de los hosts que escuchan en ese puerto. Define un ServerName explícito para cada proyecto y añade alias solo para nombres del mismo sitio. Un alias amplio *.example.com puede capturar un subdominio de otro proyecto. Si ningún nombre coincide, Apache usa el primer host apropiado. Configura una respuesta predeterminada deliberada para no mostrar accidentalmente otro sitio.

¿Cuándo puede Apache servir archivos estáticos?

Un sitio estático solo necesita un DocumentRoot propio, permisos de lectura y DirectoryIndex; no requiere proceso de aplicación. Este modelo sirve para HTML exportado. La wiki raíz de 40i.net se sirve así, igual que las páginas públicas de Transcriber y Profile Analyzer. Mantén cada publicación en su directorio y da a Apache acceso de lectura, sin exponer secretos ni repositorios. El host virtual separa rutas; los permisos Unix limitan los archivos disponibles para el proceso.

¿Cómo puede Apache usar proxy para una aplicación?

Ejecuta cada aplicación en su propio puerto local y deja que Apache gestione el tráfico público. La app debe escuchar en 127.0.0.1 para que los clientes no eludan TLS ni el enrutamiento por host. Conserva Host y el esquema originales para generar enlaces y cookies correctos. site-builder.40i.net usa Rails en el puerto 3000. Otros proyectos tienen directorios estáticos o backends locales propios. Las rutas WebSocket, como Rails Action Cable, necesitan una regla específica antes del proxy HTTP general.

Host virtual para un backend local
<VirtualHost *:443>
    ServerName app.example.com
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/app.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/app.example.com/privkey.pem

    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"
    ProxyPass / http://127.0.0.1:3001/
    ProxyPassReverse / http://127.0.0.1:3001/
</VirtualHost>

¿Cómo mantiene systemd las aplicaciones activas?

Usa un servicio systemd por proceso web de larga duración y trabajador en segundo plano. Define su usuario Unix, directorio de trabajo, archivo de entorno y política de reinicio. Guarda secretos fuera del directorio público y Git. En el despliegue Rails, el proceso web y los trabajos están en servicios separados. Tras editar una unidad, ejecuta systemctl daemon-reload y reiníciala. Si cambias el entorno de la app, reinicia también el proceso. Consulta el estado y el journal antes de investigar Apache.

¿Cómo debe gestionar la aplicación su hostname?

El proxy conserva la cabecera Host, pero la aplicación necesita una lista de hosts permitidos y una URL canónica. En este despliegue Rails, APP_HOST define el host, APP_BASE_DOMAIN la base de subdominios de clientes y RAILS_ALLOWED_HOSTS los hosts aceptados. Reserva nombres como www y admin para que el enrutador no los confunda con sitios de clientes. Tras un cambio, revisa redirecciones, enlaces de acceso y recuperación, cookies, WebSocket y URL canónicas.

¿El DNS comodín proporciona un certificado HTTPS comodín?

No. DNS indica adónde resolver el nombre; el certificado requiere una validación aparte. HTTP-01 de Let’s Encrypt recupera un token en /.well-known/acme-challenge/ por el puerto 80. DNS-01 valida un registro TXT y se requiere para certificados comodín. Los certificados de nombres exactos son adecuados para una lista pequeña y estable. DNS-01 comodín encaja con nombres que cambian a menudo si el proveedor automatiza DNS de forma segura. Actualiza los SAN conservando todos los hosts activos.

Mantén accesible HTTP-01 antes de redirigir el resto a HTTPS
Alias /.well-known/acme-challenge/ /path/served/by/certbot/

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
RewriteRule ^ https://app.example.com%{REQUEST_URI} [R=301,L,NE]

¿Cómo funciona la renovación de certificados en 40i.net?

Para HTTP-01, Let’s Encrypt debe recuperar el challenge de cada hostname. No desvíes el path ACME del webroot de Certbot mediante redirección o proxy. La configuración de 40i.net usa un webroot ACME de ISPConfig; un script recopila los hosts activos de sitios y clientes, amplía el certificado SAN con Certbot y recarga Apache. site-builder.40i.net usa un certificado independiente. Conserva los nombres activos al ampliar un SAN, comprueba que Apache cargue los archivos y simula la renovación tras cambios de DNS o webroot.

¿Cómo añadir un proyecto nuevo sin afectar a los demás?

Reserva un hostname único y comprueba que no coincida con un subdominio de cliente o proyecto existente. Dirige DNS al servidor o confirma que lo cubre el comodín. Elige un directorio estático o puerto loopback libre. Configura un host Apache exacto, la lista de hosts permitidos, la URL canónica y su certificado. Valida Apache antes de recargarlo, prueba el backend localmente y después la URL HTTPS pública. Guarda la unidad systemd y la configuración junto al código o en un repositorio de operaciones.

¿Cómo localizar la capa que falla?

Comprueba por orden: dig +short app.example.com muestra DNS; apachectl -S indica el host elegido; apachectl configtest encuentra errores; systemctl status y journalctl muestran el estado de la app; curl con Host a 127.0.0.1:PORT prueba el backend sin DNS público; openssl s_client con el nombre muestra el certificado. Un 502 suele indicar el proceso o puerto de origen; una página inesperada, el host virtual; un certificado incorrecto, TLS o el host seleccionado.

¿Cuál es el límite de un único servidor?

Los subdominios separan rutas, no CPU, memoria, disco, capacidad de base de datos ni el dominio de fallo de la máquina. Una app saturada ralentiza las demás y una avería del servidor desconecta todos los proyectos. Una base compartida también puede ser un cuello de botella. Vigila recursos y prueba restauraciones de copias. Traslada un proyecto o usa balanceo cuando necesites aislamiento, disponibilidad o capacidad; prepara DNS y certificados en el destino antes de cambiar el tráfico.

Proyectos relacionados

Documentación técnica primaria