Servidor web en la DMZ
=======================

.. toctree::
   :maxdepth: 2

El servidor 'webserver' está un una VLAN de Proxmox. El vtag es el **VLAN20** y éste es único servidor en la VLAN.
El sistema operativo está basado en la distribución **Fedora release 38**.
El servicio web está basado en **nginx** con las siguientes configuraciones.

.. note::

    | Para acceder al DMZ hay que parasr por el route pfSense
    | Para el ssh de acceso desde el exterior **ssh -p 2022 192.168.4.10**

**Directorio de trabajo /etc/nginx**

* Configuración para los logs. Fichero *nginx.conf*

    .. code-block:: cfg

        map $time_iso8601 $date {
            ~([^d]+) $1;
        }
        map $time_iso8601 $time {
            ~\d([0-9:]+)\+ $1;
        }
        
        client_max_body_size                200M;

        log_format          main  '[$date $time] $remote_addr $scheme $request $status $http_x_forwarded_for';
        access_log          /var/log/nginx/access.log main;
        error_log           /var/log/nginx/error.log;

* Configuración para las redirecciones hacia HTTPS (SSL). *Fichero nginx.conf*

    .. code-block:: cfg

        server {
            listen          80 default_server;
            server_name     dtremino.duckdns.org;

            if ($host = diegott.ddns.net) {
                    return 301 https://diegott.ddns.net$request_uri;
            }
            if ($host = dtremino.duckdns.org) {
                    return 301 https://dtremino.duckdns.org$request_uri;
            }
        }

* Apartado de certificados. *Fichero nginx.conf*

    .. code-block:: cfg

        server {
                listen       443 ssl http2 default_server;
                server_name  dtremino.duckdns.org;
                ssl_certificate /etc/letsencrypt/live/dtremino.duckdns.org/fullchain.pem;
                ssl_certificate_key /etc/letsencrypt/live/dtremino.duckdns.org/privkey.pem;
                ssl_session_cache shared:SSL:1m;
                ssl_session_timeout  10m;
                ssl_ciphers PROFILE=SYSTEM;
                ssl_prefer_server_ciphers on;
        }

* Endpoints para el servidor DMZ. *Fichero nginx.conf*

    .. code-block:: cfg

        location / {
            root /opt/html;
            index index.html;
        }
        location /favicon.ico {
            alias /opt/html/favicon.ico;
        }
        location /favicon {
            alias /opt/html/favicon.ico;
        }
        location /documentacion {
            alias /opt/html/documentacion;
            index index.html;
            auth_basic           "Authentication";
            auth_basic_user_file /opt/html/htpasswd;
        }
        location ~ ^/scripts/(.*)$ {
            auth_basic           "Authentication";
            auth_basic_user_file /opt/html/htpasswd;
            proxy_pass http://127.0.0.1:8081/scripts/$1;
        }

* Para el almacén de claves

    .. code-block:: bash

        htpasswd -c /opt/html/htpasswd nagiosadmin
        htpasswd /opt/html/htpasswd diego

.. note:: 
    El nginx solo sirve las página estáticas (html, css, js, iconos...) pero los scripts tipo CGI los ejecuta un lighttpd 
    instalado en este mismo servidor en el puerto 8081. Las peticiones desde internet para ejecutar scripts CGI tienen la estructura 
    *https://dtremino.duckdns.org/scripts/<script.py>*

    Ver el manual de instalación en la sección de CENTOS.

Este script en python3 es un CGI para lighttpd que guarda un fichero enviado mediante un POST en el directorio */tmp* 
y devuelve un JSON con los campos *result* y *error* según el resultado de la acción. *Fichero /opt/lighttpd/scripts/uploadFichero.py*

.. code-block:: python3

    #!/bin/python3

    import os, json, cgi
    import cgitb; cgitb.enable()

    toReturn = {
        'result': None,
        'error': None
    }
    try:
        form = cgi.FieldStorage()
        fileitem = form['filename']
        toReturn['result'] = fileitem
        if fileitem.filename:
            fn = os.path.basename(fileitem.filename)
            open('/tmp/' + fn, 'wb').write(fileitem.file.read())
            toReturn['result'] = 'The file "' + fn + '" was uploaded successfully'

    except Exception as e:
        toReturn['error'] = str(e)

    print ("Content-Type: application/json")
    print("")
    print(json.dumps(toReturn))


Este script en python3 es un CGI para lighttpd que devuelve el tiempo en un ciudad mediante el API de *Openwether*

.. code-block:: python3

    import cgi, cgitb, json
    import requests

    cgitb.enable()

    toReturn = {
        'result': None,
        'error': None
    }

    try:
        form = cgi.FieldStorage()
        ciudad = form['ciudad'].value
        url = "https://api.openweathermap.org/data/2.5/weather?appid=f0e003e915edafd6348ac731a98995db&units=metric&lang=sp&q=" + ciudad
        response = requests.get(url)
        toReturn['result'] = response.text
    except Exception as ex:
        toReturn['error'] = str(ex)

    print("Content-Type: application/json")
    print("")
    print(json.dumps(toReturn))
