# Nginx como proxy inverso y balanceador

Nginx ha demostrado ser una solución integral para muchos servicios utiles de servidores e infraestructura TIC. En esta ocasión nos centraremos en dos, proxy inverso y balanceador de carga:

{% hint style="info" %}
Un **proxy inverso** es un servidor que actúa como intermediario entre los clientes y los servidores de backend, ocultando la infraestructura interna del servidor y gestionando las solicitudes de los clientes antes de enviarlas al servidor adecuado. Sus funciones principales incluyen:

* **Seguridad**: Oculta la IP del servidor backend y puede manejar SSL/TLS.
* **Cacheo**: Almacena contenido estático para mejorar el rendimiento.
* **Redirección**: Reenvía solicitudes a diferentes servidores según la configuración.
  {% endhint %}

{% hint style="warning" %}
Un **balanceador de carga** es un sistema que distribuye las solicitudes entrantes de manera equilibrada entre múltiples servidores de backend para mejorar el rendimiento, la disponibilidad y la tolerancia a fallos.
{% endhint %}

***

## **Pasos para Configurar el Proxy Inverso**

1. **Pre-requisitos:**
   * Instalar y ejecutar un servidor backend simple.
     * Por ejemplo, si usas Python con Flask:

       <pre class="language-bash"><code class="lang-bash"><strong>pip install flask
       </strong></code></pre>

       Si no tienes instalado pip o python puedes hacerlo con `sudo apt install python3-pip`
     * Luego crea un archivo llamado `app.py` con la IP de tu servidor y el puerto deseado:

       ```python
       from flask import Flask
       app = Flask(__name__)

       @app.route("/")
       def hello():
           return "Respuesta del servidor backend"

       if __name__ == "__main__":
           app.run(host="10.0.0.5", port=5000)
       ```

       Ejecuta el servidor:

       ```bash
       python3 app.py
       ```
     * Para más comodidad, puedes lanzar la aplicación como un proceso en segundo plano añadiendo & al final, veamos el proceso:

```bash
python3 app.py & #Envia el proceso a segundo plano
bg #Vuelve al shell
jobs o ps#Lista los trabajos en segundo plano
fg %1 #Recupera en primer plano el trabajo [1]
kill %1 #Mata el proceso 1
```

* Ahora el servidor estará escuchando en `http://10.0.0.5:5000`, puedes comprobarlo a través de un equipo cliente.

2. **Configura Nginx como Proxy Inverso:**

* Ahora toca configurar l proxy como si fuera un host normal, crea y edita el archivo de configuración del sitio web (por ejemplo, `/etc/nginx/sites-available/proxy`):

  ```nginx
  server {
      listen 80;
      server_name localhost;

      location /api {
          proxy_pass http://10.0.0.5:5000; # Dirección del backend
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
  }
  ```
* **Explicación:**
  * `proxy_pass`: Redirige las peticiones a la URL del backend.
  * `proxy_set_header`: Transfiere encabezados adicionales para que el backend tenga información del cliente original.
* A partir de aquí, son los[ mismos pasos que con un virtualhost](https://apuntes-alex.gitbook.io/apuntes-sistemas-y-redes/web/nginx/virtualhosts#paso-4-habilitar-el-archivo-de-configuracion).

3. **Habilita la configuración:**

* Crea un enlace simbólico para habilitar el sitio:

  ```bash
  sudo ln -s /etc/nginx/sites-available/proxy /etc/nginx/sites-enabled/
  ```
* Recarga o reinicia Nginx:

  <pre class="language-bash"><code class="lang-bash"><strong>sudo systemctl reload nginx
  </strong></code></pre>

4. **Prueba la configuración:**

* Envía una petición al proxy inverso:

  ```bash
  curl http://localhost
  ```
* Deberías recibir la respuesta del backend: `"Respuesta del servidor backend"`.

***

## **Pasos para Configurar el Balanceo de Carga**

### Round Robin

En este caso crearemos un balanceador que seguirá un esquema de **Round Robin** por defecto, este es un algoritmo de balanceo de carga utilizado en entornos de redes y servidores para distribuir las solicitudes o tareas entre un conjunto de recursos. La idea básica detrás del algoritmo es bastante simple: asigna cada solicitud o tarea al siguiente recurso disponible en una lista circular.

En este enfoque, las solicitudes se distribuyen secuencialmente a través de la lista  y cada servidor recibe una solicitud en secuencia, independientemente de su carga actual. Este método es simple pero no tiene en cuenta la carga actual de cada servidor.

Para ponerlo en práctica realizaremos algo muy simple:

1. **Pre-requisitos:**
   * Ejecutamos dos instancias del servidor backend en diferentes puertos tal y como hemos visto anteriormente cambiándoles el puerto:
     * Por ejemplo, utilizando Flask:
       * En el puerto `5000`:

         ```bash
         from flask import Flask
         app = Flask(__name__)

         @app.route("/")
         def hello():
             return "Respuesta del servidor 1"

         if __name__ == "__main__":
             app.run(host="10.0.0.5", port=5000)
         ```
       * En el puerto `5001`:

         ```bash
         from flask import Flask
         app = Flask(__name__)

         @app.route("/")
         def hello():
             return "Respuesta del servidor 2"

         if __name__ == "__main__":
             app.run(host="10.0.0.5", port=5001)
         ```

2. **Configura el Balanceador de Carga:**
   * Abre o crea un archivo de configuración para el balanceador (por ejemplo, `/etc/nginx/sites-available/balanceador`):

     ```nginx
     upstream backend_servers {
         server 127.0.0.1:5000;
         server 127.0.0.1:5001;
         server 127.0.0.1:5002 backup;
     }

     server {
         listen 80;
         server_name localhost; #Nombre del servidor

         location / {
             # Del bloque upstream
             proxy_pass http://backend_servers;
             
             #
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             
             #♥Configuración de límites de tiempo
             proxy_connect_timeout 5s;
             proxy_read_timeout 10s;
             proxy_send_timeout 10s;
         }
     }
     ```
   * **Explicación:**

     * El bloque `upstream` define un grupo de servidores backend.
     * Nginx distribuye las peticiones entre estos servidores utilizando el algoritmo **round-robin** por defecto.

3. **Habilita la Configuración:**
   * Crea un enlace simbólico:

     ```bash
     sudo ln -s /etc/nginx/sites-available/balanceador /etc/nginx/sites-enabled/
     ```
   * Recarga Nginx:

     ```bash
     sudo systemctl reload nginx
     ```

4. **Prueba el Balanceo de Carga:**

   * Envía múltiples peticiones al servidor balanceador:

     ```bash
     curl http://localhost/
     ```
   * Observa que las respuestas alternan entre las instancias de backend.

5. **Verifica los Logs:**
   * Inspecciona los logs de acceso para validar que las peticiones se distribuyen entre los servidores:

     ```bash
     tail /var/log/nginx/access.log
     ```

## :construction: NGINX proxy manager

{% embed url="<https://github.com/NginxProxyManager/nginx-proxy-manager>" %}

Referencia: <https://claudiu.psychlab.eu/post/homelab-4-install-and-configure-nginx-proxy-manager-with-ssl-wildcard-certs/>

<https://www.linuxtrainingacademy.com/http-load-balancing-nginx-video-cheatsheet-vagrantfile/>
