5. Servidor web en la DMZ

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

    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

    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

    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

    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

    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

#!/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

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))