TLDR;
Desplegar una aplicación en Ruby on Rails en producción es un proceso que cada vez que se hace tiene un problema diferente. De esto depende las gemas, las dependencias y el sistema operativo que se use. Veremos como se despliega en Ubuntu 22 siendo la base más sencilla sobre la que se puede operar, con gemas estándar y con un código fuente de ejemplo que incluyo.
Para este tutorial utilizaremos DigitalOcean como proveedor de servicios en la nube.
Usando este link obtienes un bono de $200 en DigitalOcean para que puedas hacer este tutorial y usarlo en futuros despliegues.
Nota: Este tutorial también está en Youtube, donde explico en formato de video el paso a paso y doy comentarios acerca de cada paso.
EstoyProgramando es un canal en Youtube que enseña cómo incursionar en el mundo del desarrollo de software.
Cualquier persona de cualquier carrera puede cambiar su profesión a programador debido a las múltiples facilidades que se encuentran disponibles, también aprovechando el mercado laboral que se encuentra en auge.
Suscríbete a mi canal para más contenido de cómo iniciar en el mundo de la programación, además de encontrar contenido específico de programación en Ruby.
Paso 1.
Crea un servidor Ubuntu versión 22.04 (LTS). Recomiendo mínimo 1GB de RAM.
En la sección de método de autenticación puedes escoger Password por simplicidad, o puedes configurar tus llaves de acceso.
Al final hacer click en Crear. Cuando se termine de crear ya podemos acceder por protocolo SSH al Droplet (es decir, al server)
Abrimos la Terminal (o la aplicación de línea de comandos según el sistema operativo que se tenga) e ingresamos el comando de ssh con el usuario root y la ip del Droplet.
ssh root@1.2.3.4
Ahora configuramos el usuario con el que vamos a operar, todos estos comandos deben ingresarse en la aplicación de Terminal con la sesión de SSH abierta en nuestro server remoto.
En los siguientes comandos voy a crear mi usuario david, si tu usuario se llama diferente debes ajustar todos los comandos con el nombre del usuario adecuado.
Crear el usuario:
sudo adduser david
Agregar el usuario al grupo de sudoers:
sudo usermod -aG sudo david
Cambiamos desde el usuario root al usuario david:
su david
# Pide la contraseña
Cambiamos el nombre del host (Cambiar server por el nombre que quieras asignar al servidor):
sudo hostnamectl set-hostname server
Para ver los cambios en el nombre del servidor podemos salir con exit y reingresar con su david .
Paso 2.
Con la sesión abierta y el usuario designado logueado vamos a actualizar el sistema e instalar las librerías necesarias:
sudo apt-get update
sudo apt-get install software-properties-common
sudo apt-get install libssl-dev
Ahora podemos instalar RVM (Aunque se puede usar cualquier otro manejador de versiones de Ruby)
\curl -sSL https://get.rvm.io | bash -s stable
Aquí debe salir un error, el cual pide que agregues la clave del autor, por razones de seguridad no coloco ese comando aquí.. pero puedes copiarlo y pegarlo. Una vez lo hagas corre de nuevo el comando anterior para instalar RVM.
Ahora vamos a cargar el RVM con el comando:
source /home/david/.rvm/scripts/rvm
Así, el comando rvm ya estará disponible.
Luego instalamos openssl:
rvm pkg install openssl
Y ahora si instalamos Ruby indicándole el directorio de OpenSSL:
rvm install 3.0.4 --with-openssl-dir=$HOME/.rvm/usr
(En mi caso instalé la versión 3.0.4, pero según cuando estés haciendo este tutorial puede haber otra versión más reciente)
Este comando debe demorarse varios minutos…
Mientras esperas te recomiendo algunos de mis videos más populares:
📚 Tips para conseguir trabajo como programador
📚 Debo estudiar ingeniería de sistemas?
📚 Estudiar programación en el 2023
📚 Los programadores deben saber inglés
📚 Curso de fundamentos de programación
Ahora puedes indicarle al sistema operativo que use por defecto la versión de Ruby que acabamos de instalar, con el comando:
rvm use 3.0.4 --default
Si te da un error debes modificar el archivo ~/.bashrc:
# nano ~/.bashrc
# Puedes incluirlo al final del archivo:
source ~/.rvm/scripts/rvm
Luego de salir y regresar a la sesión del usuario ya el comando rvm use debería funcionar correctamente.
Paso 3
Debes clonar el código del proyecto en cualquier parte de la carpeta de tu usuario. Por ejemplo, podemos usar este proyecto de ejemplo el cual es un pequeño sistema de información en Ruby on Rails 7 o puedes usar tu propio proyecto. Si usas tu propio proyecto debes considerar las dependencias específicas, por ejemplo si necesitas librerías adicionales para que las gemas de tu proyecto funcione.
git clone https://github.com/damuz91/mi-bodega-rails
luego accedemos a la carpeta recién creada con el comando cd y corremos el comando bundle install . Aquí podrán salir errores si acaso el comando bundle no logró instalar las gemas listadas en el Gemfile, esto normalmente es porque harán falta algunas librerías para compilar las gemas necesarias.
En este video hacemos el sistema que usamos de ejemplo en este tutorial.
Los siguientes pasos corresponden a configuración específica del proyecto de ejemplo aunque podrían ser usados en tu caso también:
Borramos el credentials.yml.enc existente: rm config/credentials.yml.enc
Generamos un nuevo archivo de credenciales: Editor="nano --wait" bin/rails credentials:edit
Creamos y migramos la base de datos: rails db:create db:migrate db:seed RAILS_ENV=production
Los pasos 1 y 2 pueden no aplicar en tu caso si acaso el proyecto tiene credenciales encriptadas en el archivo y si cuentas o no con la clave correcta en el archivo master.key .
Paso 4
Vamos a instalar Nginx para administrar las peticiones web entrantes:
sudo apt-get install nginx
Creamos el archivo donde colocaremos la configuración de nginx:
sudo nano /etc/nginx/sites-enabled/app.conf
Colocamos el siguiente script con cuidado de modificar la ruta adecuada según donde esté ubicada la carpeta de tu proyecto:
upstream app {
server unix:///home/david/mi-bodega-rails/puma.sock fail_timeout=0;
}
server {
server_name _;
root /home/david/mi-bodega-rails/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Host 'www.railsapp.com';
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~ ^/(500|404|422).html {
root /home/david/mi-bodega-rails/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;
}
Borramos la configuración por defecto anterior:
sudo rm /etc/nginx/sites-enabled/default
Corremos el servicio de nginx como nuestro usuario (Otra alternativa es dar permisos al usuario www-data de lectura y escritura a la carpeta del proyecto):
sudo nano /etc/nginx/nginx.conf
# Modificar la primera linea:
user david # En lugar de www-data. Coloca el nombre de tu usuario
Reiniciamos nginx:
sudo service nginx restart
Ahora creamos el script para que el servidor de App PUMA corra en el Systemd:
sudo nano /etc/systemd/system/puma.service
Y colocamos la siguiente configuración (Recuerda ajustarlo a tu usuario y directorio del proyecto):
[Unit]
Description=Puma HTTP Server
After=network.target
[Service]
Type=simple
User=david
WorkingDirectory=/home/david/mi-bodega-rails
Environment=RAILS_ENV=production
ExecStart=/home/david/.rvm/gems/ruby-3.0.4/wrappers/bundle exec puma -C /home/david/mi-bodega-rails/config/puma/production.rb
Restart=always
KillMode=process
[Install]
WantedBy=multi-user.target
Luego reiniciamos el servicio y activamos la nueva configuración:
sudo systemctl daemon-reload
sudo systemctl enable puma
Precompilamos los assets de nuestro proyecto:
cd /ruta/al/proyecto
bundle exec rails assets:precompile RAILS_ENV=production
E iniciamos (o reiniciamos) el servidor de Puma:
sudo service puma restart
Y debería cargar la aplicación:
Cualquier error que surja se puede consultar en:
log/production.log
log/pumastdout.log
log/pumastderr.log
sudo journalctl -u puma -f -n 100
Este mismo tutorial en versiónAmazon Linux 2 lo encuentras en mi perfil.
Cualquier pregunta o comentario es bienvenido!