Nginx

Typically used as a reverse proxy server, though it can certainly be used to serve up static content or use PHP or any other plugin.

Test-and-reload

A quick and convenient one-liner to safely reload nginx:

sudo nginx -t && sudo systemctl reload nginx

Reverse Proxy

server {
    listen 80;
    listen [::]:80;
    server_name mycooldomain.net; 
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name mycooldomain.net; 

    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_http_version 1.1;
        proxy_pass http://localhost:8080;
    }
}

With Caching

proxy_cache_path  /var/www/cache levels=1:2 keys_zone=static-cache:8m max_size=99m inactive=600m;
proxy_temp_path /var/www/cache/tmp; 

server {
    listen 80;
    listen [::]:80;
    server_name mycooldomain.net; 
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name mycooldomain.net; 

    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_http_version 1.1;
        proxy_pass http://localhost:8080;
        proxy_cache static-cache;
        proxy_cache_valid  200 302  300s;
        proxy_cache_valid  404      60s;
    }
}

PHP-FPM

Install php goodies (Usually needed for LEMP stack):

sudo apt install php7.4 php7.4-fpm php7.4-mbstring php7.4-json php7.4-xml php-mysql php7.4-mysql php7.4-gd php7.4-zip php7.4-curl
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name mycooldomain.net; 

    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
    ssl_protocols TLSv1.2 TLSv1.3;

    root           /var/www/myapp/public;
    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Authentication

htpasswd authentication

Install apache utils, which allows creation of the auth file

sudo apt install apache2-utils

Create the basic auth file

sudo htpasswd /etc/nginx/htpasswd myuser

Add authentication to an endpoint in the proxy config:

    location / {
        auth_basic           "Restricted Access";
        auth_basic_user_file /etc/nginx/htpasswd; 
        proxy_http_version 1.1;
        proxy_pass http://localhost:8008;
    }

PAM authentication

Install the PAM module:

sudo apt install libnginx-mod-http-auth-pam

Create the PAM config at /etc/pam.d/nginx

auth       include      common-auth
account    include      common-account

Allow nginx to read the shadow file:

usermod -aG shadow www-data

Add lines to the proxy config:

    location / {
        auth_pam "secure";
        auth_pam_service_name "nginx";
        proxy_http_version 1.1;
        proxy_pass http://localhost:8008;
    }

The Go-Away-Vhost

Default vhost to discourage spam. This should be added to the bottom of /etc/nginx/nginx.conf

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    server_name_in_redirect off;

    location /healthz {
        return 200;
        access_log off; 
    }

    location / {
        return 301 http://$remote_addr$request_uri;
        access_log /var/log/nginx/spam.log; 
    }
}

server {
    listen 443 ssl  default_server;
    listen [::]:443 ssl default_server;
    server_name _;
    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
    ssl_protocols TLSv1.3 TLSv1.2;
    server_name_in_redirect off;

    location /healthz {
        return 200;
        access_log off; 
    }

    location / {
        return 301 http://$remote_addr$request_uri;
        access_log /var/log/nginx/spam.log; 
    }
}

This configuration also provides a /health endpoint that returns an empty success response, which helps keep monitoring tools happy.

Monitoring

Enable a stub_status page:

server {
    listen 127.0.0.1:8080;
    location /stub_status {
        stub_status;
    }
}

Install the prometheus exporter:

sudo apt install prometheus-nginx-exporter

The listener on port 9113/tcp will expose the metrics.

This can also be scraped by fluent-bit:

[INPUT]
    name prometheus_scrape
    host 127.0.0.1
    port 9113
    tag  metrics.nginx
    scrape_interval 30s 

PHP-FPM

Uncomment the line in /etc/php/7.4/fpm/www.conf

pm.status_path = /status

Check the config:

$ sudo /usr/sbin/php-fpm7.4 -t

[28-Oct-2022 20:09:04] NOTICE: configuration file /etc/php/7.4/fpm/php-fpm.conf test is successful

Reload the service

sudo systemctl restart php7.4-fpm.service

Download the exporter binary:

sudo wget https://github.com/bakins/php-fpm-exporter/releases/download/v0.6.1/php-fpm-exporter.linux.amd64 -O /usr/local/bin/php-fpm-exporter
sudo chmod +x /usr/local/bin/php-fpm-exporter

Create a service: /etc/systemd/system/prometheus-php-fpm-exporter.service

[Unit]
Description=PHP-FPM Prometheus Exporter
Documentation=https://github.com/bakins/php-fpm-exporter
After=network.target php7.4-fpm.service

[Service]
Restart=on-failure
User=root
ExecStart=/usr/local/bin/php-fpm-exporter --addr=127.0.0.1:9222 --fastcgi=unix:///run/php/php-fpm.sock

[Install]
WantedBy=multi-user.target