🚀 Guía: Subdominios Dinámicos en Rails 8 con Kamal 2 y Cloudflare
Esta arquitectura permite que cada usuario tenga su propia URL (ej: usuario.tuapp.com) compartiendo la misma base de datos y servidor.
1. Configuración de DNS (El "Embudo")
Para que cualquier subdominio llegue a tu servidor, necesitas un comodín (Wildcard).
- En Cloudflare: Crea un registro
Acon el nombre*apuntando a la IP de tu servidor. - Estado de Proxy: Activa la nube naranja (Proxied). Esto nos da SSL gratuito sin configurar certificados complejos en el servidor.
2. Compartir la Sesión (Login Universal)
Por defecto, Rails trata a cada subdominio como un sitio diferente. Para que el usuario no se desloguee al saltar del dominio principal al subdominio, debemos configurar la cookie.
config/initializers/session_store.rb:
Ruby
# El punto inicial permite que la cookie sea válida para todos los subdominios
domain = Rails.env.production? ? ".tuapp.blog" : ".lvh.me"
Rails.application.config.session_store :cookie_store,
key: '_tu_app_session',
domain: domain,
tld_length: 2 # Ajusta según tu dominio (ej: .com = 2, .com.mx = 3)
3. La "Aduana" de Rutas (Constraint)
Necesitamos una clase que decida si una petición debe ir a la "Landing Page" o al "Blog del Usuario".
app/constraints/subdomain_required.rb:
Ruby
class SubdomainRequired
def self.matches?(request)
# Filtramos para no atrapar el dominio principal o subdominios técnicos
request.subdomain.present? && !["www", "admin", "api"].include?(request.subdomain)
end
end
4. El Mapa de Rutas (routes.rb)
El orden es vital: Rails lee de arriba hacia abajo. El bloque del subdominio debe ir primero.
Ruby
Rails.application.routes.draw do
constraints(SubdomainRequired) do
root "profiles#show", as: :user_blog
resources :posts
end
# Rutas del dominio principal
devise_for :users
root "homes#index"
end
5. Configuración de Producción (Rails 8)
Rails 8 es muy estricto con la seguridad. Hay que configurar el TLD Length (para dominios como .blog) y el Host Authorization.
config/environments/production.rb:
Ruby
# 1. TLD Length: Segmentos del dominio base menos uno (ej: tuapp.blog = 1)
config.action_dispatch.tld_length = 1
# 2. Host Authorization: Permitir subdominios y excluir el Health Check de Kamal
config.hosts << ".tuapp.blog"
config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
# 3. SSL Detrás de Cloudflare (Modo Flexible)
config.assume_ssl = true
config.force_ssl = true
6. El Despliegue con Kamal 2
Kamal Proxy debe saber que tiene permitido dejar pasar los subdominios hacia el contenedor de la app.
config/deploy.yml:
YAML
proxy:
# Lista de hosts permitidos
host:
- tuapp.blog
- "*.tuapp.blog"
app_port: 3000 # Puerto interno de Rails 8
ssl: false # Porque Cloudflare ya cifra el tráfico
7. Resumen de comandos útiles
Acción | Comando |
Actualizar infraestructura |
|
Solo actualizar el Proxy |
|
Ver logs del Proxy |
|
Ver logs de la App |
|
Consola de producción |
|
🛠️ Configuración en Cloudflare (El "Cerebro" de la Red)
Cloudflare no solo protege tu sitio, sino que actúa como el director de orquesta para tus subdominios dinámicos.
1. DNS: El Comodín (Wildcard)
Para que cualquier-cosa.tuapp.blog funcione sin que tengas que crear registros manuales para cada usuario:
- Tipo:
A(oCNAMEsi usas un alias). - Nombre (Name):
*(el asterisco es el secreto, captura todos los subdominios). - Contenido (Content): La IP de tu servidor Hetzner.
- Proxy Status: Proxied (Nube Naranja).
- ¿Por qué? Esto permite que Cloudflare maneje el certificado SSL por ti y oculte la IP real de tu servidor.
[!TIP] No olvides crear también un registro
Apara el dominio raíz (@) apuntando a la misma IP.
2. SSL/TLS: Modo "Flexible"
Como en nuestra configuración de Kamal Proxy pusimos ssl: false, necesitamos que Cloudflare se encargue de la "cara pública" (HTTPS) mientras habla con nuestro servidor por un canal privado (HTTP).
- Configuración: Ve a la pestaña SSL/TLS -> Overview.
- Modo: Selecciona Flexible.
- Resultado: El usuario ve
https://usuario.tuapp.blog(con candado), pero Cloudflare le pide la información a tu servidor por el puerto 80 (HTTP). Es la forma más rápida de evitar errores de "Handshake" o certificados expirados.
3. Ajustes de Seguridad Esenciales
Para garantizar que nadie entre por conexiones no seguras, activa estos dos interruptores en SSL/TLS -> Edge Certificates:
- Always Use HTTPS: Redirige automáticamente cualquier intento de
http://ahttps://. - Automatic HTTPS Rewrites: Ayuda a solucionar errores de "contenido mixto" si accidentalmente cargas una imagen por HTTP.