Desarrollo9 de septiembre de 2025

Cómo desplegar una aplicación Rails con Mina, Nginx y Puma

¿Qué es Mina?

Mina es una herramienta de despliegue parecida a Capistrano. Su gran ventaja es la velocidad. Mina es especialmente rápida porque es un generador de scripts Bash de despliegue: genera todo el procedimiento como un script Bash y lo ejecuta en remoto en el servidor. Además, ejecuta los comandos de forma inteligente: si no cambias los assets (CSS, JS, imágenes), no lanza la precompilación de assets. Y lo mismo con las migraciones.

Configuración de Mina

Veamos cómo configurar Mina con Puma. Primero tienes que añadir Mina y mina-puma al Gemfile, en el grupo de desarrollo. Mina cambió hace poco de mantenedor; el nuevo repositorio está aquí y lo mejor es instalarlo desde Git.


gem 'mina', require: false
gem 'mina-puma', require: false, github: 'untitledkingdom/mina-puma'

Si usas una versión de Rails anterior a la 5, añade la gema Puma a la sección global.

Después, instala las gemas y ejecuta el comando inicial de Mina para generar el archivo config/deploy.rb.


bundle
mina init

Aquí tienes un ejemplo de la configuración por defecto de Mina 1.0.0. Haz clic aquí para ver la configuración completa.

Explicación detallada del archivo de despliegue de Mina


#Set the domain or ip address of the remote server.
set :domain, 'yourdomain.ru'
#Set the folder of the remote server where Mina will deploy your application.
set :deploy_to, 'path/to/directory'
#Set a link to the repository. Example: git@bitbucket.org/yourteam/myapp.git
set :repository, 'git@…'
#Set the name of a branch you plan to deploy as default master.
set :branch, 'master'
#Fill in the names of the files and directories that will be symlinks to the shared directory.
#All folders will be created automatically on Mina setup.
#Don’t forget to add a path to the uploads folder if you are using Dragonfly or CarrierWave.
#Otherwise, you will lose your uploads on each deploy.
set :shared_dirs, fetch(:shared_dirs, []).push('log', 'tmp/pids', 'tmp/sockets', 'public/uploads')
set :shared_files, fetch(:shared_files, []).push('config/database.yml', 'config/secrets.yml', 'config/puma.rb')
#Username of ssh user for access to the remote server.
set :user, 'username'
#This is not a required field. You can use it to set an application name for easy recognition.
set :application_name, 'MyApplication'
#Set ruby version. If you have RVM installed globally, you’ll also need to set an RVM path,
#like: set :rvm_use_path, '/usr/local/rvm/scripts/rvm'.
#You can find the RVM location with the rvm info command.
task :environment do
invoke :'rvm:use', 'ruby-2.4.0@default'
end

Por defecto, Mina crea todas las carpetas indicadas en shared_dirs y shared_files. Aun así, en la tarea setup puedes añadir la creación automática de archivos vacíos para rellenarlos más tarde.


task :setup do
command %[touch "#{fetch(:shared_path)}/config/database.yml"]
command %[touch "#{fetch(:shared_path)}/config/secrets.yml"]
command %[touch "#{fetch(:shared_path)}/config/puma.rb"]
comment "Be sure to edit '#{fetch(:shared_path)}/config/database.yml', 'secrets.yml' and puma.rb."
end

Hecho esto, ya puedes ejecutar mina setup para preparar toda la estructura de archivos necesaria en el servidor remoto.

La sección deploy de tu deploy.rb debería quedar así:


task :deploy do
deploy do
comment "Deploying #{fetch(:application_name)} to #{fetch(:domain)}:#{fetch(:deploy_to)}"
invoke :'git:clone'
invoke :'deploy:link_shared_paths'
invoke :'rvm:load_env_vars'
invoke :'bundle:install'
invoke :'rails:db_migrate'
command %{#{fetch(:rails)} db:seed}
invoke :'rails:assets_precompile'
invoke :'deploy:cleanup'
on :launch do
invoke :'puma:phased_restart'
end
end
end

Configuración de Puma

Crea o rellena el archivo puma.rb en la carpeta config.


environment "production"
bind "unix:///{path_to_your_app}/shared/tmp/sockets/puma.sock"
pidfile "/{path_to_your_app}/shared/tmp/pids/puma.pid"
state_path "/{path_to_your_app}/shared/tmp/sockets/puma.state"
directory "/{path_to_your_app}/current"
workers 2
threads 1,2
daemonize true
activate_control_app 'unix:///{path_to_your_app}/shared/tmp/sockets/pumactl.sock'
prune_bundler

Tienes que indicar la ruta a pumactl.sock en activate_control_app. Si no, mina puma:stop y restart no funcionarán.

Rellena database.yml y secrets.yml

Ve a la carpeta shared y asegúrate de rellenar estos dos archivos.

Configuración de nginx

Crea el archivo myapp.conf en la carpeta /nginx/etc/conf.d con un contenido similar a este.


upstream mysite {
server unix:///home/admin/mysite/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
listen [::]:80;
server_name mysite.com;
root /home/admin/mysite/current/public;
location ~ ^/assets/ {
expires max;
gzip_static on;
gzip_vary on;
add_header Cache-Control public;
break;
}
location / {
proxy_pass http://mysite;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/(500|404|422).html {
root /home/admin/mysite/current/public;
}
error_page 500 502 503 504 /500.html;
error_page 404 /404.html;
error_page 422 /422.html;
client_max_body_size 4G;
keepalive_timeout 10;
}

Genera las claves ssh

Genera claves ssh nuevas en tu servidor con el comando ssh-keygen. Después, añádelas a las deploy keys de tu proyecto en GitHub o Bitbucket.

Misión cumplida

Eso es todo. Ya puedes desplegar tu aplicación. Si ya has ejecutado mina setup, lanza mina deploy y espera.

Resolución de problemas

Si tienes problemas con el git clone, comprueba que has añadido la clave pública ssh a tu repositorio e intenta clonar el repositorio directamente desde el servidor.

En el primer arranque, usa mina puma:start en lugar de phased_restart.

Enlaces útiles

Mina y despliegue en varios entornos (multi-stage)

Cuéntanos tu caso

Escríbenos