POST

Nginx, Passenger y Ruby on Rails en Centos 6

 

Nginx es un servidor http y proxy. Passenger es un servidor de aplicaciones capaz de ejecutar aplicaciones Ruby On Rails que puede funcionar de manera aislada o en combinación con sevidores http Nginx o Apache. Para este funcionamiento conjunto, existe un módulo de Passenger para Nginx de tal manera que podemos emplear Nginx para servir aplicaciones Ruby On Rails. Será esta última solución la que emplearemos en este tutorial, es decir, vamos a compilar Nginx con el módulo de Passenger habilitado y realizaremos las configuracciones necesarias para que nuestra aplicación Ruby On Rails sea servida a través de Nginx.

Asumimos que tenemos en un nuestro servidor instalado RVM con la versiones de Ruby que necesitemos.

Instalamos Passenger

Instalo dependencias necesarias para compilar tanto Nginx como el módulo Passenger-Nginx
1
2
sudo yum install libcurl-devel.x86_64
sudo yum install pcre-devel.x86_64
Instalamos Passenger
1
gem install passenger

Passenger se instalará como gem de ruby en el directorio de la versión de Ruby activa. En nuestro caso estamos usando RVM para gestionar las diferentes versiones con las que trabajamos. Para ver dónde se ha instalado Passenger ejecutamos el siguiente comando. La salida la emplearemos más adelate.

Consultamos el path de Passenger
1
2
3
4
passenger-config --root
[salida]
/home/david/.rvm/gems/ruby-2.2.3/gems/passenger-5.1.5

Las fuentes del módulo Passenger para Nginx están en el directorio src/nginx_module del directorio anterior. Es decir, la instalación de Passenger nos provee ya de estas fuentes. Configuramos una variable de entorno que utilizaremos a continuación para proceder a la compilación de Nginx incluyendo este módulo.

Sacamos a una variables el path de las fuentes del módulo de Passenger para Nginx
1
PASSENGER_NGINX_DIR=`passenger-config --root`/src/nginx_module

Compilación de Nginx con el módulo de Passenger

Debido a que la instalación de Passenger y Nginx a través de “yum” no nos descarga las últimas versiones, realizaremos el proceso de una menera más manual compiando el propio Nginx a partir del código fuente e incluyendo el módulo propio de Passenger.

Descargo y descomprimo la última versión de Nginx
1
2
wget http://nginx.org/download/nginx-1.12.1.tar.gz
tar xzvf nginx-1.12.1.tar.gz

Como podemos jugar con el código fuente, vamos a cambiar la cadena de texto que el sevidor entrega en los headers de cada respuesta http. De esta manera, quienes realicen peticiones a nuestro servidor no sabrán que están interacturando con un servido Nginx, y por tanto no podrán aplicar técnica de hackeo específicas para este servidor. Esto se denomina medida de seguridad por ocultación.

Cambiaremos la línea 48 del fichero src/http/ngx_http_header_filter_module.c
1static char ngx_http_server_string[] = "Server: nginx" CRLF;
2static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
3
4Cambiamos estas dos líneas a algo del estilo:
5
6static char ngx_http_server_string[] = "Server: Mi servidor Web" CRLF;
7static char ngx_http_server_full_string[] = "Server: Mi servidor Web" CRLF;
Configuramos la instalación de Nginx con Passenger como módulo dinámico.
1
./configure --with-http_gzip_static_module --sbin-path=/usr/local/sbin --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --add-dynamic-module=$PASSENGER_NGINX_DIR

Estamos habilitando la compresión de las páginas con gzip, SSL para conexiones seguras, deshabilitando el módulo de correo POP3, IMAP y SMTP y habilitando el módulo dinámico de Passenger.

Rutas donde se instalará Nginx
1nginx path prefix: "/usr/local/nginx"
2nginx binary file: "/usr/local/sbin"
3nginx modules path: "/usr/local/nginx/modules"
4nginx configuration prefix: "/usr/local/nginx/conf"
5nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
6nginx pid file: "/usr/local/nginx/logs/nginx.pid"
7nginx error log file: "/usr/local/nginx/logs/error.log"
8nginx http access log file: "/usr/local/nginx/logs/access.log"
9nginx http client request body temporary files: "client_body_temp"
10nginx http proxy temporary files: "proxy_temp"
11nginx http fastcgi temporary files: "fastcgi_temp"
12nginx http uwsgi temporary files: "uwsgi_temp"
13nginx http scgi temporary files: "scgi_temp"
Compilamos e instalamos Nginx
1
2
sudo make
sudo make install
Validamos la instalación
1
2
rvmsudo passenger-config validate-install
rvmsudo passenger-memory-stats

Añadimos Nginx al inicio del sistema

Creamos el siguiente escript en /etc/init.d con nombre nginx
1#!/bin/sh
2#
3# nginx - this script starts and stops the nginx daemin
4#
5# chkconfig: - 85 15
6# description: Nginx is an HTTP(S) server, HTTP(S) reverse \
7# proxy and IMAP/POP3 proxy server
8# processname: nginx
9# config: /usr/local/nginx/conf/nginx.conf
10# pidfile: /usr/local/nginx/logs/nginx.pid
11
12# Source function library.
13. /etc/rc.d/init.d/functions
14
15# Source networking configuration.
16. /etc/sysconfig/network
17
18# Check that networking is up.
19[ "$NETWORKING" = "no" ] && exit 0
20
21nginx="/usr/local/sbin/nginx"
22prog=$(basename $nginx)
23
24NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"
25
26lockfile=/var/lock/subsys/nginx
27
28start() {
29 [ -x $nginx ] || exit 5
30 [ -f $NGINX_CONF_FILE ] || exit 6
31 echo -n $"Starting $prog: "
32 daemon $nginx -c $NGINX_CONF_FILE
33 retval=$?
34 echo
35 [ $retval -eq 0 ] && touch $lockfile
36 return $retval
37}
38
39stop() {
40 echo -n $"Stopping $prog: "
41 killproc $prog -QUIT
42 retval=$?
43 echo
44 [ $retval -eq 0 ] && rm -f $lockfile
45 return $retval
46}
47
48restart() {
49 configtest || return $?
50 stop
51 start
52}
53
54
55reload() {
56 configtest || return $?
57 echo -n $"Reloading $prog: "
58 killproc $nginx -HUP
59 RETVAL=$?
60 echo
61}
62
63force_reload() {
64 restart
65}
66
67configtest() {
68 $nginx -t -c $NGINX_CONF_FILE
69}
70
71rh_status() {
72 status $prog
73}
74
75rh_status_q() {
76 rh_status >/dev/null 2>&1
77}
78
79
80case "$1" in
81 start)
82 rh_status_q && exit 0
83 $1
84 ;;
85 stop)
86 rh_status_q || exit 0
87 $1
88 ;;
89 restart|configtest)
90 $1
91 ;;
92 reload)
93 rh_status_q || exit 7
94 $1
95 ;;
96 force-reload)
97 force_reload
98 ;;
99 status)
100 rh_status
101 ;;
102 condrestart|try-restart)
103 rh_status_q || exit 0
104 ;;
105 *)
106 echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
107 exit 2
108esac
Cambiamos sus permisos
1
chmod 755
Registramos el servicio
1
chkconfig --add nginx
Configuramos el sevicio nginx para que se levante al arrancar la máquina
1
sudo chkconfig nginx on
Arrancamos ‘nginx’
1
sudo service nginx start

Configuración de Passenger en Nginx para correr aplicaciones Ruby On Rails

Necesitamos configurar dos variables:

  • passenger_root: Le decimos a Nginx dónde tenemos instalado Passenger, de tal manera que el módulo que hemos incorporado pueda encontrarlo.
  • passenger_ruby: Le decimos a Nginx cuál es la versión de Ruby y gemas instaladas que debe emplear para ejecutar determinada aplicación Ruby On Rails.
Consultamos el path de Passenger. La [salida] nos servira para configurar passenger_root en el paso siguiente.
1
2
3
4
passenger-config --root
[salida]
/home/david/.rvm/gems/ruby-2.2.3/gems/passenger-5.1.5
Creamos /usr/local/nginx/conf/passenger.conf con el siguiente contenido
1passenger_root /home/david/.rvm/gems/ruby-2.2.3/gems/passenger-5.1.5;
2passenger_max_pool_size 5;
3passenger_min_instances 5;
Configuramos Nginx editando el archivo /usr/local/nginx/conf/nginx.conf.
1
2worker_processes 8;
3
4events {
5 worker_connections 1024;
6}
7
8
9http {
10 include /usr/local/nginx/conf/passenger.conf;
11 include mime.types;
12 default_type application/octet-stream;
13
14 sendfile on;
15 keepalive_timeout 65;
16
17 server {
18 listen 80;
19 server_name localhost;
20
21 root /var/www/alfredoruiz/production/current/public;
22
23 passenger_ruby /home/david/.rvm/gems/ruby-2.2.3@garageerp/wrappers/ruby;
24 passenger_enabled on;
25
26 rails_env production;
27
28 client_max_body_size 50M;
29 }
30}

Las configuraciones destacables que hemos realizado son las siguientes:

  • Hemos incluido el fichero passenger.conf en la directiva http para que pueda ser leído.
  • Hemos creado un servidor con passenger habilitado (passenger_enabled on).
  • Hemos apuntado a la carpeta public de nuestra aplicación Ruby On Rails (root).
  • Hemos configurado a variable passenger_ruby apuntando al entorno que necesita nuestra aplicación Ruby On Rails para funcionar.

En nuestro caso estamos empleando RVM para tener multiples versiones de Ruby funcionando con diferentes conjuntos de gemas, una práctica esencial para poder tener varias aplicaciones Ruby On Rails funcionando a la vez. En este caso nuestra aplicación funciona con la versión 2.2.3 de ruby y un gemset llamado garageerp. El hecho de usar RVM nos obliga a emplear los wrappers en vez de apuntar directamente a los binarios de ruby.

Notas propias para el despliegue

Las siguienes notas puede que no te sean de utilidad. Son pequeñas pasos que he realizado tras desplegar algunas apicaciones Ruby On Rails por primera vez.

Clonamos la aplicación por primera vez con git
1
git clone ssh://git@202.122.234.090:27/~/repositorios/mySuperApp.git
Evito la instalación de documentación cada vez que instalo nuevas gemas de ruby. Para ello creo un archivo en ~/.gemrc con el siguiente contenido
1gem: --no-rdoc --no-ri
En la raiz de mi aplicación creo un archivo ruby-version con la versión de Ruby a emplear entre las instaladas en RVM.
12.2.3
En la raiz de mi aplicación creo un archivo ruby-gemset con el gemset a emplear.
1garageerp
Instalo bundle. Desde la raiz de la aplicación ejecuto:
1
gem install bundle
Instalo todas las dependencias. Desde la raiz de la aplicación ejecuto:
1
bundle install
Instalo nuevo requerimientos de acuerdo a los fallos de bundle
1
yum install mysql-devel

Instalamos NVM y Node

Las aplicaciones Ruby On Rails necesitan motores javascript para poder compilar las assets. Instalaremos Node para tal fin, pero lo haremos a través del Node Version Manager (NVM) para poder gestionar varias versiones de Node a la vez.

Descargamos y ejecutamos el script de instalación de NVM.
1
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash

Cerramos y abrimos el terminal.

Comprobamos la instalación. Tras ejecutar este comando debe aparecer: ‘nvm’
1
command -v nvm
Instalamos node
1
nvm install node
Lo activamos
1
nvm use node
Precompilo los assets de Ruby on Rails para producción.
1
rake assets:precompile RAILS_ENV=production

Fin

Rearrancamos nuestro servidor Nginx y debería funcionar correctamente

Rearrancamos ‘nginx’
1
sudo service nginx restart

Y como los debería no siempre se cumplen porque este mundo de servidores, programación y demás tiene una gran complejidad debido a los conceptos que se barajan y múltiples versiones de todo con las que se trabaja, no te preocupes si las cosas fallan. Es parte del camino del aprendizaje. El siguiente paso será consultar los logs de errores para seguir tirando del hilo. ¡Suerte!

Consulta de logs por si existieran errores en el arranque.
1
sudo vi /usr/local/nginx/logs/error.log