--- title: "Cómo desplegar Rails con Puma y Nginx en Ubuntu 24.04" description: "Despliega una aplicación Ruby on Rails en Ubuntu 24.04 con rbenv, PostgreSQL, Puma gestionado por systemd y Nginx como proxy inverso con HTTPS de Let's Encrypt." category: "E-commerce y CMS" language: es source: https://cubepath.com/es/docs/e-commerce-y-cms/implementacion-de-ruby-on-rails-con-puma-y-nginx updated: 2026-09-25 --- # Cómo desplegar Rails con Puma y Nginx en Ubuntu 24.04 Una aplicación Ruby on Rails en producción se ejecuta con Puma, el servidor de aplicaciones que Rails incluye por defecto, y con Nginx delante para servir los archivos estáticos, terminar TLS y reenviar el resto de peticiones. En este tutorial instalarás Ruby con rbenv en Ubuntu 24.04, prepararás la base de datos en PostgreSQL, ejecutarás Puma como servicio de systemd y publicarás la aplicación con Nginx y un certificado de Let's Encrypt. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM (compilar Ruby consume bastante memoria). - Un usuario no root con privilegios `sudo`. En los ejemplos se llama `your_user` y es también el usuario que ejecutará la aplicación. - Un dominio con un registro DNS `A` apuntando a la IP del servidor. En los ejemplos se usa `your_domain`. - Una aplicación Rails 7.1 o posterior en un repositorio Git, con los archivos `.ruby-version` y `config/credentials.yml.enc` versionados, y su clave maestra `config/master.key` a mano. La aplicación de ejemplo se llama `myapp` y vive en `/var/www/myapp`. ## Paso 1: Instalar las dependencias del sistema Instala las librerías necesarias para compilar Ruby y las gemas nativas más comunes, además de PostgreSQL y Nginx: ```bash sudo apt update sudo apt install git curl build-essential autoconf libssl-dev libyaml-dev libreadline-dev zlib1g-dev libgmp-dev libffi-dev libpq-dev postgresql nginx ``` Abre en el cortafuegos SSH, HTTP y HTTPS: ```bash sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable ``` ## Paso 2: Instalar rbenv y ruby-build rbenv permite instalar la versión exacta de Ruby que pide cada aplicación, sin depender de la que trae Ubuntu. Clónalo junto con el plugin `ruby-build`, que es el que compila Ruby: ```bash git clone https://github.com/rbenv/rbenv.git ~/.rbenv git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build ``` Añade rbenv a tu shell y recarga la configuración: ```bash echo 'eval "$(~/.rbenv/bin/rbenv init - bash)"' >> ~/.bashrc source ~/.bashrc ``` Comprueba que el comando está disponible: ```bash rbenv --version ``` ```output rbenv 1.3.x ``` ## Paso 3: Descargar la aplicación e instalar Ruby Crea el directorio de la aplicación con tu usuario como propietario y clona el repositorio: ```bash sudo mkdir -p /var/www/myapp sudo chown your_user:your_user /var/www/myapp git clone https://github.com/your_account/myapp.git /var/www/myapp cd /var/www/myapp ``` Ejecutado sin argumentos dentro del proyecto, `rbenv install` lee la versión de `.ruby-version` y la compila. Tarda varios minutos: ```bash cat .ruby-version rbenv install ``` Comprueba que dentro del proyecto se usa esa versión: ```bash ruby -v ``` ```output ruby 3.4.x (...) +PRISM [x86_64-linux] ``` ## Paso 4: Instalar las gemas de producción Configura Bundler para que instale las gemas dentro del proyecto y omita los grupos de desarrollo y test. Estos ajustes se guardan en `.bundle/config` y se aplican a todas las ejecuciones posteriores: ```bash bundle config set --local deployment true bundle config set --local without 'development test' bundle install ``` ```output ... Bundle complete! 18 Gemfile dependencies, 92 gems now installed. Gems in the groups 'development' and 'test' were not installed. Bundled gems are installed into `./vendor/bundle` ``` > Nota: si la aplicación usa `jsbundling-rails` o `cssbundling-rails`, necesitas además Node.js y el gestor de paquetes que indique el proyecto para compilar los assets. Las aplicaciones con los valores por defecto de Rails (importmap y Propshaft o Sprockets) no lo necesitan. ## Paso 5: Crear el usuario de PostgreSQL Abre `config/database.yml` y busca la sección `production`. En las aplicaciones generadas con `--database=postgresql`, el usuario suele llamarse como la aplicación y la contraseña se lee de una variable de entorno: ```yaml production: primary: &primary_production <<: *default database: myapp_production username: myapp password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %> ``` Rails 8 define además bases de datos para `cache`, `queue` y `cable` con el mismo usuario. Crea ese usuario con permiso `CREATEDB` para que Rails pueda crearlas todas. Sustituye `your_strong_password` por una contraseña larga y aleatoria: ```bash sudo -u postgres psql -c "CREATE USER myapp WITH CREATEDB PASSWORD 'your_strong_password';" ``` ## Paso 6: Definir las variables de entorno Rails necesita en producción el entorno, la contraseña de la base de datos y la clave maestra que descifra `config/credentials.yml.enc`. Guárdalas en un archivo que usarán tanto systemd como tus comandos: ```bash sudo nano /etc/myapp.env ``` ```ini RAILS_ENV=production RAILS_MASTER_KEY=contenido_de_config_master_key MYAPP_DATABASE_PASSWORD=your_strong_password SOLID_QUEUE_IN_PUMA=1 ``` `SOLID_QUEUE_IN_PUMA=1` hace que el `config/puma.rb` de Rails 8 arranque el procesador de trabajos de Solid Queue dentro de Puma, suficiente en un único servidor. Omítela si tu aplicación no usa Solid Queue. Protege el archivo, ya que contiene la clave maestra: ```bash sudo chown root:your_user /etc/myapp.env sudo chmod 640 /etc/myapp.env ``` Carga las variables en tu sesión actual: ```bash set -a; source /etc/myapp.env; set +a ``` ## Paso 7: Preparar la base de datos y compilar los assets `db:prepare` crea las bases de datos que falten, carga el esquema y ejecuta las migraciones pendientes: ```bash cd /var/www/myapp bin/rails db:prepare ``` Compila los assets en `public/assets`, desde donde Nginx los servirá directamente: ```bash bin/rails assets:precompile ``` Comprueba que la aplicación arranca en modo producción y se conecta a la base de datos: ```bash bin/rails runner 'puts ActiveRecord::Base.connection.current_database' ``` ```output myapp_production ``` ## Paso 8: Ejecutar Puma con systemd Crea un servicio de systemd para Puma. El shim de rbenv usa la versión de `.ruby-version`, y `-b` hace que Puma escuche solo en `127.0.0.1:3000`, de modo que únicamente Nginx puede llegar a él: ```bash sudo nano /etc/systemd/system/myapp.service ``` ```ini [Unit] Description=Puma for myapp After=network.target postgresql.service [Service] Type=simple User=your_user WorkingDirectory=/var/www/myapp EnvironmentFile=/etc/myapp.env ExecStart=/home/your_user/.rbenv/shims/bundle exec puma -C config/puma.rb -b tcp://127.0.0.1:3000 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` Activa e inicia el servicio: ```bash sudo systemctl daemon-reload sudo systemctl enable --now myapp systemctl status myapp --no-pager ``` ```output ● myapp.service - Puma for myapp Active: active (running) since ... ``` Comprueba que Puma responde. La cabecera `X-Forwarded-Proto` simula lo que enviará Nginx; sin ella, `config.force_ssl` respondería con una redirección: ```bash curl -s -o /dev/null -w "%{http_code}\n" -H "Host: your_domain" -H "X-Forwarded-Proto: https" http://127.0.0.1:3000/up ``` ```output 200 ``` `/up` es la ruta de comprobación de salud que Rails añade desde la versión 7.1. Los logs de la aplicación están en `journalctl -u myapp`, porque Rails escribe en la salida estándar en producción. ## Paso 9: Configurar Nginx Crea un bloque de servidor para el dominio: ```bash sudo nano /etc/nginx/sites-available/myapp ``` Nginx busca primero el archivo en `public/` y, si no existe, pasa la petición a Puma. Los assets compilados llevan un hash en el nombre, así que pueden cachearse durante un año: ```nginx upstream puma_myapp { server 127.0.0.1:3000; } server { listen 80; listen [::]:80; server_name your_domain www.your_domain; root /var/www/myapp/public; client_max_body_size 20M; location ^~ /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; try_files $uri =404; } location / { try_files $uri @puma; } location @puma { proxy_pass http://puma_myapp; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } } ``` Activa el sitio, desactiva el sitio por defecto y comprueba la sintaxis: ```bash sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl reload nginx ``` Nginx necesita poder leer `/var/www/myapp/public`. Con los permisos por defecto (`755` en directorios y `644` en archivos) no hay que cambiar nada. ## Paso 10: Activar HTTPS con Let's Encrypt Instala Certbot con su plugin para Nginx y solicita el certificado. Certbot añade la configuración TLS y la redirección de HTTP a HTTPS: ```bash sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your_domain -d www.your_domain ``` Comprueba que la renovación automática funciona: ```bash sudo certbot renew --dry-run ``` Abre `https://your_domain` en el navegador. Deberías ver tu aplicación, y `https://your_domain/up` debe mostrar una página verde. ## Actualizar la aplicación Para desplegar cambios, descarga el código, instala las gemas nuevas, migra, recompila los assets y reinicia Puma: ```bash cd /var/www/myapp git pull set -a; source /etc/myapp.env; set +a bundle install bin/rails db:migrate bin/rails assets:precompile sudo systemctl restart myapp ``` Si el nuevo código cambia `.ruby-version`, ejecuta `rbenv install` antes de `bundle install`. ## Solución de problemas - **`ActiveSupport::MessageEncryptor::InvalidMessage` o `Missing secret_key_base`**: `RAILS_MASTER_KEY` no coincide con `config/credentials.yml.enc`. Copia de nuevo el contenido de tu `config/master.key` local. - **502 Bad Gateway**: Puma no está escuchando. Revisa `sudo journalctl -u myapp -n 50`. - **`PG::ConnectionBad: password authentication failed`**: la contraseña de `/etc/myapp.env` no coincide con la del usuario de PostgreSQL, o el nombre de la variable no es el que usa `config/database.yml`. - **Bucle de redirecciones a HTTPS**: Nginx no está enviando `X-Forwarded-Proto`. Comprueba que el bloque `@puma` incluye esa cabecera. ## Conclusión Tu aplicación Rails funciona en producción con Ruby instalado mediante rbenv, PostgreSQL, Puma gestionado por systemd y Nginx sirviendo los assets y el tráfico HTTPS. Como siguientes pasos puedes: - Programar copias de seguridad de las bases de datos con `pg_dump`. - Mover el procesamiento de trabajos a un servicio de systemd propio (`bin/jobs`) si la carga crece. - Automatizar el despliegue con Kamal o con un pipeline de CI.