Configurando NGINX, como un servidor independiente para una aplicación (Nginx como Proxy).

Brevario de configuración mínima de un servidor NGINX, que sirva con el propósito de ser un servidor web para otra aplicación.

Imaginate el siguiente escenario. Has terminado de desarrollar tu aplicación python usando CherryPy y acabas de hacer que responda en dos puertos para darle mayor disponibilidad. Pero quieres que tenga mayor seguridad, que use  un esquema de balanceo, que sea transparente para el usuario final y lo mejor de todo que responda como si fuera un servidor independiente. Bueno esta es una guia de como hacer que ese desmadre funcione.

Una de las cosas importantes al configurar una aplicación web es definir si queremos que ésta esté respondiendo a las peticiones en el puerto 80 de HTTP o, que por seguridad, deseamos que lo haga en otro puerto. Para esto podemos hacer que nuestra aplicación responda directamente en el puerto 80.

Esto nos provoca un serio problema en cuanto a si deseamos compactar la respuesta, manejar los distintas tipos de peticiones, entender todos los headers y básicamente programar todo lo que implica la definicion del RFC referente al protocolo HTTP. Sin embargo hay otras soluciones una de ellas usar un servidor web completo como apache o nginx.

En este tema vamos a ver como configurar un nginx que nos sirva con el proposito de publicar nuestra aplicación sin preocuparnos por todo el protocolo HTTP.

 

Instalando NGINX.

 Este es uno de los pasos más fáciles del mundo, sólo hay que confiar en el siempre fiable apt-get

$ sudo apt-get -u install nginx

Un repaso rápido a los directorios y archivos de NGINX.

Una vez instalado hay que reconocer la funcionalidad de dos directorios /etc/nginx/sites-available/ y /etc/nginx/sites-enabled/. El primero nos sirve para poner nuestros archivos de configuración y que sean identificados más no interpretados por nginx y el segundo sirve para que todo archivo ahí forma parte de la configuración de nginx al momento de que este servicio esté en funcionamiento.

Ahora bien vamos a darle una mirada al archivo de configuración principal con:

$ sudo vi /etc/nginx/nginx.conf

 

Y si modicaremos dicho archivo no esta de más siempre hacer una copia

$ sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bckp.20160423164554

 (Un poco de orden no le hace daño a nadie)

La verdad es que casí nunca vamos a modificar el archivo de configuración principal, pero siempre es bueno tener un poco de cuidado por si  la cagamos o cometemos un error.  La verdad hay muchas cosas, como la seguridad de los certificados, que definir aqui así que prefiero hacerlo después con más calma en otro documento, pero de momento con esto estará más que bien.

 

Como siempre andamos perdidos moviendonos entre tanto directorio es importante recordar donde andamos trabajando así que te recuerdo el comando para recordar la ruta donde estamos trabajando.

$ pwd

Configurando nuestro proyecto en NGINX

Bueno una vez que explicamos de forma breve como funciona nginx, vamos a darle sus putazos para hacer que funcione nuestro proyecto.

$ sudo vi /etc/nginx/sites-available/app.example.com.conf

 Nuestro archivo de configuración estará definido de la siguiente forma:

 ## This adds security headers
#add_header X-Frame-Options "SAMEORIGIN";
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
#add_header X-XSS-Protection "1; mode=block";
#add_header X-Content-Type-Options "nosniff";
##add_header Content-Security-Policy "default-src 'self'; img-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'";
#add_header Content-Security-Policy-Report-Only "default-src 'self'; img-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'";

# This specifies which IP and port the application is running on.
# The default is 127.0.0.1:8080
upstream app {
    ip_hash;
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}


# Redirect all www-less traffic to the www.site.com domain
# (you could also do the opposite www -> non-www domain)
#server {
#    listen 80;
#    server_name example.com;
#    rewrite ^/(.*) http://app.example.com/$1 permanent;
#}

server {

    listen 80;
    server_name app.example.com;
    access_log /var/log/nginx/app.example.com.access.log;
    error_log /var/log/nginx/app.example.com.error.log;

    # Note that domain name spelling in VirtualHostBase URL matters
    # -> this is what the application sees as the "real" HTTP request URL.
    # "app" in the URL is your site id (case sensitive)
    location / {
#          proxy_pass http://app.example.com/application/;
          proxy_pass http://app/VirtualHostBase/http/app.example.com:80/application/VirtualHostRoot/;
          proxy_set_header X-Real-IP    $remote_addr;
          proxy_set_header  Host  $http_host;
    }
    gzip on;
    gzip_types  text/css;
    gzip_types  text/xml;
    gzip_types  application/javascript;
    gzip_types  application/x-javascript;
    gzip_types  application/json;
}

 

Hay algunas cuestiones de seguridad que por no ser de este tema no estoy tomando en cuenta uno tiene que ver con los famosos iframes, sin embargo dejo comentadas las primeras líneas para quien desee retomar el tema después.

  En las líneas

server 127.0.0.1:8080;
server 127.0.0.1:8081;

Nos indica que es donde actualmente está funcionando nuestra aplicación que desarrollaste con CherryPy. Tu definiras en tu aplicación en que puertos deseas que respondan.

 

Y la línea con

proxy_pass http://app/VirtualHostBase/http/app.example.com:80/application/VirtualHostRoot/;

 

nos indica lo siguiente:

Que la aplicación definida en http://127.0.0.1:8080/application y http://127.0.0.1:8081/application y todos sus componentes se mapearan como si fuera un sólo servidor el cual estará definido en http://app.example.com/ ¿A verdad? ¡Eso si no lo esperaban! La verdad es que ami me tomó algo de tiempo entenderle a ese pedo y no me quedó la configuración a la primera.

Ya por último lo siguiente.

ip_hash

Esta pequeña línea hace la magia de que las peticiones se balanceen correctamente y que si la petición vaya al puerto 8080 no vaya a mandar las siguientes peticiones del HTTP al puerto 8081.  Nos dice literalmente la página de NGINX de carga y balanceo.

"ip-hash — a hash-function is used to determine what server should be selected for the next request (based on the client’s IP address)."

¡Aja! por eso es que no se hace bolas con las peticiones.

 Configurar diferentes subdominios en Nginx

Ahora bien, ¿Que pasa si deseamos configurar en otro subdominio otra funcionalidad de la applicación desarrollada en CherryPy pero que está en otra ruta?

Lo único que hay que hacer es definir el subdominio con un nuevo archivo y en donde dice.

upstream app {

Poner otro nombre de aplicación como por ejemplo:

upstream jsonapp {

y tambien donde dice

proxy_pass http://app/VirtualHostBase/http/app.example.com:80/application/VirtualHostRoot/;

sustituirlo por:

proxy_pass http://app/VirtualHostBase/http/jsonapp.example.com:80/application/VirtualHostRoot/;

y eso es todo.

Redireccionando el trafico entre dominios con nginx

En el supuesto que requirieramos que un dominio adicional redireccionara a nuestro dominio, tendriamos que crear el archivo de configuración de ese nuevo dominio y sólo dar de alta la redirección en nginx con la siguiente configuración.

# Redirect all www-less traffic to the www.site.com domain
# (you could also do the opposite www -> non-www domain)
server {
    listen 80;
    server_name app1.otherdomain.com;
    rewrite ^/(.*) http://app.example.com/$1 permanent;
}

 

Más sencillo, ni hervir agua.

Ya está configurado mi proyecto en NGINX ¿Como interpreta NGINX mi archivo de configuración?

Hay que ligar entonces el archivo de configuración creando un enlace simbólico para habilitar la configuración y que el servicio de nginx lo tome al momento de echarse a andar.

$ sudo ln -s /etc/nginx/sites-available/app.example.com.conf /etc/nginx/sites-enabled/

Verificando la configuración de NGINX

una vez que tenemos todo listo hay que verificar que nuestra configuracion de nginx funciona, para ello ejecutamos:

$ sudo /etc/init.d/nginx configtest

[ ok ] Testing nginx configuration:.

Si el resultado es el presentado en la segunda línea entonces quiere decir que ya chingamos y está correctamente todo configurado, si no sólo bastará rectificar la configuración y se vuelve a verificar nuevamente.

Echar a andar el servidor de NGINX

Ya por último sólo hay que poner en funcionamiento nuestro servidor de nginx y verificarlo para ello sólo bastará con usar los comandos


$ service nginx restart
$ service nginx status
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
   Active: active (running) since Sun 2016-04-24 00:17:10 CEST; 12s ago
  Process: 18540 ExecStop=/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid (code=exited, status=0/SUCCESS)
  Process: 18544 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
  Process: 18542 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Main PID: 18549 (nginx)
   CGroup: /system.slice/nginx.service
           ├─18549 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
           ├─18550 nginx: worker process
           ├─18551 nginx: worker process
           ├─18552 nginx: worker process
           └─18553 nginx: worker process

Apr 24 00:17:10 servername systemd[1]: Started A high performance web server and a reverse proxy...ver.
Hint: Some lines were ellipsized, use -l to show in full.

 

Ahora si, a partir de aqui sólo tendrás que configurar los servidores de DNS para que apunten a la dirección app.example.com que es este mismo equipo.

Con esto ya habrás configurado tu aplicación para que sea nginx quien atienda todas las peticiones web y les dé el tratamiento más adecuado, ya eres una verdura e instalaste tu primer servidor nginx.

Referencias de NGINX:

Aqui encontraras una serie de recursos que te haran entender (o te haran más bolas) como configurar tu servidor de NGINX, además de como otros elementos de la configuración te serviran para optimizar y acelerar NGINX y las peticiones HTTP.

  1. NGINX Beginner’s Guide.
  2. Using nginx as HTTP load balancer.
  3. Minimal Nginx front end configuration for Plone on Ubuntu/Debian Linux using virtual hosts.
  4. Nginx como proxy HTTP.
  5. Compression and Decompression.
  6. Página para verificar el desempeño de nuestra applicación web, ¿Que le falta por configurar a nuestro servidor NGINX?
  7. Creating NGINX Rewrite Rules.
  8. How to redirect single url in nginx?.
  9. NGINX