Empezando a ver Nginx

19 min

language: ja bn en es hi pt zh-cn zh-tw

Hola, el título es un juego de palabras. Es solo una canción que recordé de repente.

La razón de las actualizaciones de artículos inusualmente frecuentes últimamente es simplemente que una vez que me intereso en algo, no puedo parar, y este es ese período.

Nginx

Hasta ahora, lo había configurado como un proxy inverso y servidor de caché, pero con la compatibilidad con IPv6, me preocupé y revisé la configuración, incluyendo la refactorización.

Estructura de archivos

Algunas partes están ocultas, pero se ve así:

├── http.d
│   ├── bot_rate_limit.conf
│   ├── gzip.conf
│   ├── proxy_cache_zones.conf
│   └── proxy_common.conf
├── mime.types
├── mime.types-dist
├── nginx.conf
├── scgi_params
├── selfsigned.crt
├── selfsigned.key
├── sites-enabled
│   ├── 1btc.love.conf
│   ├── btclol.xyz.conf
│   ├── damepo.jp.conf
│   ├── git.soulminingrig.com.conf
│   ├── soulminingrig.com.conf
│   ├── starlink.soulminingrig.com.conf
│   ├── stg.api.1btc.love.conf
├── snippets
│   ├── common_error_pages.conf
│   ├── proxy_headers.conf
│   └── ssl_common.conf
├── uwsgi_params
└── win-utf

Estaba un poco indeciso sobre qué nombre de carpeta usar para administrar los archivos conf cargados por directiva location, pero después de consultar con ChatGPT, quedó así. Estoy bastante satisfecho con http.d porque estos son los archivos includeidos desde la directiva http en nginx.conf.

Sin embargo, pensé que snippets era un poco sutil, pero supongo que está bien.

Veamos cada elemento de configuración.

http.d/bot_rate_limit.conf

Los rastreadores de Meta eran demasiado agresivos, así que decidí imponer restricciones no solo con fail2ban sino también por User-Agent.

En cuanto a feed/RSS, recibí un contacto cortés, pero aplicar restricciones a ellos no tiene sentido de todos modos, y casi siempre se sirven desde la caché, por lo que es poco probable que supongan una gran carga para el servidor de origen. Por lo tanto, hice una excepción para ellos.

# Aplicar límite de tasa solo a bots y rastreadores de expansión de enlaces
map $http_user_agent $is_bot {
    default 0;
    ~*bot 1;
    ~*crawler 1;
    ~*spider 1;
    ~*facebookexternalhit 1;
    ~*slackbot 1;
    ~*discordbot 1;
    ~*twitterbot 1;
    ~*linkedinbot 1;
    ~*embedly 1;
    ~*quora 1;
    ~*skypeuripreview 1;
    ~*whatsapp 1;
    ~*telegrambot 1;
    ~*applebot 1;
    ~*pingdom 1;
    ~*uptimerobot 1;
}
# stg.api.1btc.love es para fines de prueba, por lo que los bots están exentos del límite de tasa
# Si la clave está vacía, no se cuenta en limit_req_zone
map $server_name $bot_limit_host_key {
    stg.api.1btc.love "";
    default $binary_remote_addr;
}
# feed.xml / feed.json están exentos del límite de tasa incluso para bots
map $uri $is_feed_path {
    default 0;
    ~*feed\.(xml|json)$ 1;
}
# Usar la clave por IP solo cuando es un bot Y NO es feed.xml / feed.json
map "$is_bot:$is_feed_path" $bot_limit_key {
    default "";
    "1:0" $bot_limit_host_key;
}
limit_req_zone $bot_limit_key zone=bot:10m rate=1r/s;
limit_req_status 429;
limit_req zone=bot burst=5 nodelay;

Por supuesto, dado que se aplica a la directiva http, básicamente se aplica a todo, pero me aseguré de permitir excepciones mínimas. Considero que, idealmente, debería estar habilitado por defecto.

Si alguien está realizando claramente un ataque DoS falsificando su User-Agent o navegador, será bloqueado por fail2ban y tratado como drop, impidiéndole enviar solicitudes por un tiempo, por lo que es un enfoque de dos niveles.

http.d/gzip.conf

En el pasado, soportaba brotli, pero lo dejé porque se volvía problemático compilarlo por separado al actualizar versiones. La ventaja de poder actualizar con pkg/apt es significativa.

gzip on;
gzip_vary off;
gzip_proxied any;
gzip_min_length 1024;
gzip_comp_level 7;
gzip_http_version 1.1;
gzip_types text/plain
text/xml
text/css
text/javascript
image/gif
image/png
image/svg+xml
application/javascript
application/json
application/xml
application/x-javascript
application/font-woff
application/font-woff2
application/font-ttf
application/octet-stream;

No hay mucho que decir, no incluía gzip_min_length en el pasado, pero comencé a incluirlo hace unos años. Fue entonces cuando pensé que podría ser un desperdicio comprimir de manera ineficiente y decidí incluirlo correctamente.

http.d/proxy_cache_zones.conf

Puede que notes que la sangría está sutilmente rota, pero es una restricción del formateador.

Eliminé cosas innecesarias, y los números de zone comienzan desde 4 o están dispersos, pero bueno...

En cuanto a inactive, si no ha sido accedido durante 7 días, se eliminará. Para use_temp_path, estoy almacenando en caché directamente en la ruta de caché. Parece que se vuelve más rápido al almacenar en caché directamente sin pasar por una configuración como proxy_temp_path /tmp/nginx;
.

proxy_cache_path /tmp/nginx/zone4 levels=1:2 keys_zone=zone4:10m
inactive=7d
max_size=3g
use_temp_path=off;
proxy_cache_path /tmp/nginx/posts levels=1:2 keys_zone=posts:10m inactive=7d max_size=2g use_temp_path=off; proxy_cache_path /tmp/nginx/git levels=1:2 keys_zone=git:10m inactive=7d max_size=2g use_temp_path=off; proxy_cache_path /tmp/nginx/static levels=1:2 keys_zone=static_cache:10m inactive=7d max_size=1g use_temp_path=off; proxy_cache_path /tmp/nginx/1btc_cache levels=1:2 keys_zone=1btc_cache:10m inactive=7d max_size=512m use_temp_path=off;

http.d/proxy_common.conf

proxy_cache_valid se establece como una regla común, y el resto se gestiona para ser sobrescrito en el lado de la directiva location.

De esta manera, se puede operar el caché incluso sin tener una configuración de caché.

Al configurar proxy_cache_bypass $http_cookie, se evita que las solicitudes con cookies, por ejemplo, después de iniciar sesión, puedan mostrar la pantalla anterior al inicio de sesión.

Además, hacer que el caché responda a redirecciones, errores y any es una medida contra ataques. Al hacer esto, el caché responderá al menos, lo que previene accesos anómalos al Origin.

Aunque para proxy_temp_path sería preferible una ruta que permita la persistencia, como en mi uso no hay tal situación, lo he configurado a /tmp como destino. Si se hace esto en un sitio con un tráfico considerable, aunque había una opción que no se usaba, probablemente todos los cachés se borrarán al reiniciar el servidor, aumentando la carga en el Origin y el riesgo de fallos.

proxy_buffering on;
proxy_cache_bypass $http_cookie;
proxy_cache_background_update on;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_revalidate on;
proxy_cache_use_stale updating;
proxy_connect_timeout 60;
proxy_no_cache $http_cookie;
proxy_read_timeout 90;
proxy_send_timeout 60;
proxy_temp_path /tmp/nginx;
proxy_cache_valid 200 201 60s;
proxy_cache_valid 301 1d;
proxy_cache_valid 302 3h;
proxy_cache_valid 304 1d;
proxy_cache_valid 404 1m;
proxy_cache_valid any 5s;
proxy_cache_lock on;

nginx.conf

No hay mucho que decir, ya que solo se configura para devolver un error específico cuando se accede directamente a la IP del registro A.

multi_accept está activado porque es una instancia pequeña que no tiene especificaciones muy altas, funcionando como mi servidor de proxy inverso y caché.

Originalmente, las configuraciones que estaban escritas directamente en la directiva http, al ser include por propósito, ha mejorado mucho la visibilidad.

worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
events {
    multi_accept on;
    worker_connections 65535;
}
http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    types_hash_max_size 4096;
    client_max_body_size 16M;
    # MINE
    include mime.types;
    default_type application/octet-stream;
    include ./http.d/bot_rate_limit.conf;
    include ./http.d/proxy_common.conf;
    include ./http.d/proxy_cache_zones.conf;
    include ./http.d/gzip.conf;
    server {
        listen 80;
        listen [::]:80;
        server_name 163.44.113.145 91.98.169.80 2400:8500:2002:3317:163:44:113:145;
        include snippets/common_error_pages.conf;
        return 444;
    }
    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name 163.44.113.145 91.98.169.80 2400:8500:2002:3317:163:44:113:145;
        ssl_certificate ./selfsigned.crt;
        ssl_certificate_key ./selfsigned.key;
        include snippets/common_error_pages.conf;
        # Denegar acceso a la dirección IP
        return 444;
    }
    ### Damepo.jp
    include ./sites-enabled/damepo.jp.conf;
    ### Soulminingrig My Blog
    include ./sites-enabled/soulminingrig.com.conf;
# ~~~Omitido~~~~
}

sites-enabled/soulminingrig.com.conf

A continuación, se presenta solo un ejemplo de site-enabled. Esta es la configuración de este sitio.

Además, no he creado enlaces simbólicos porque solo quiero poder eliminar rápidamente lo que no necesito.

De hecho, hay algunas partes que permanecen codificadas, pero por favor, comprenda que todavía estoy en proceso de revisión.

Por cierto, recientemente lo cambié a www.soulminingrig.com, pero antes de eso, se servía desde el dominio raíz sin www. Por lo tanto, actualmente todavía lo acepto desde el dominio raíz sin redirección.

Durante el período de verificación, he configurado las respuestas de encabezado para que sea fácil ver si la caché del servidor o la caché del cliente respondieron.

Y, mientras pienso si puedo mejorar un poco las reglas de caché para imágenes, fuentes, CSS, etc., me quedo pensando... ¿No hay forma de arreglar esto...?

upstream está configurado para poder responder rápidamente si aumenta el número de destinos de backend. Bueno, aunque actualmente solo hay uno, al estar en la parte superior, es fácil ver a qué destino de backend apunta la configuración.

upstream backend_sm {
    server 10.1.0.228:8888 max_fails=3 fail_timeout=3s;
    keepalive 16;
    keepalive_timeout 30s;
}
map $uri $static_cache {
    ~\.(jpg|jpeg|png|webp|gif|mp4|css|js|ico|woff2)(\?.*)?$ "public, max-age=604800";
    ~\.html$ "public, max-age=600";
    default "public, max-age=600";
}
map $upstream_cache_status $server_cache_status {
    default $upstream_cache_status;
    "" "NONE";
}
map "$http_if_none_match:$http_if_modified_since" $client_cache_request {
    default "MISS";
    "~.+:.+" "REVALIDATE";
    "~.+:" "REVALIDATE";
    "~:.+" "REVALIDATE";
}
server {
    listen 80;
    listen [::]:80;
    server_name soulminingrig.com www.soulminingrig.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl reuseport backlog=65535 rcvbuf=256k sndbuf=256k fastopen=256 so_keepalive=on;
    listen [::]:443 ssl reuseport backlog=65535 rcvbuf=256k sndbuf=256k fastopen=256 so_keepalive=on ipv6only=on;
    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;
    http2 on;
    http3 on;
    server_name soulminingrig.com www.soulminingrig.com;
    client_max_body_size 50M;
    location ~* \.(jpg|jpeg|png|webp|gif|ico|mp4|js|css|woff2)(\?.*)?$ {
        proxy_pass http://backend_sm;
        include snippets/proxy_headers.conf;
        proxy_http_version 1.1;
        proxy_redirect off;
        proxy_cache static_cache;
        proxy_cache_valid 200 301 302 7d;
        proxy_cache_valid 404 1m;
        proxy_cache_revalidate on;
        proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
        proxy_cache_background_update on;
        proxy_cache_lock on;
        proxy_connect_timeout 3s;
        proxy_read_timeout 15s;
        expires 7d;
        add_header X-Cache-Status $upstream_cache_status always;
        add_header X-Server-Cache-Status $server_cache_status always;
        add_header X-Client-Cache-Request $client_cache_request always;
        add_header X-Client-Cache-Policy "public, max-age=604800" always;
        add_header Cache-Control "public, max-age=604800" always;
    }
    location / {
        proxy_pass http://backend_sm/;
        include snippets/proxy_headers.conf;
        proxy_http_version 1.1;
        proxy_redirect off;
        proxy_cache posts;
        proxy_cache_key $scheme$host$request_uri;
        proxy_cache_valid 200 10m;
        proxy_cache_valid 301 1h;
        proxy_cache_valid 404 1m;
        proxy_cache_revalidate on;
        proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504 http_403 http_404;
        proxy_cache_background_update on;
        proxy_cache_lock on;
        proxy_connect_timeout 3s;
        proxy_read_timeout 15s;
        expires $static_cache;
        add_header X-Cache-Status $upstream_cache_status always;
        add_header X-Server-Cache-Status $server_cache_status always;
        add_header X-Client-Cache-Request $client_cache_request always;
        add_header X-Client-Cache-Policy $static_cache always;
        add_header Cache-Control $static_cache always;
    }
    include snippets/common_error_pages.conf;
    include snippets/ssl_common.conf;
    ssl_certificate /hoge/fullchain.pem; # managed by Certbot
    ssl_certificate_key /hoge/oulminingrig.com/privkey.pem;
    # managed by Certbot
}

Extra: enginxfmt.py

Esto es excelente.

Es un formateador, y siento que tiene la más alta calidad.

Está disponible en AUR.

yay -S nginx-config-formatter

El uso es enginxfmt.py example.conf lo formateará, así que

find . -name "*conf" | xargs -I{} nginxfmt.py {}

los formateará todos a la vez.

Hasta hace poco, estaba usando nginxbeautifier, pero la sintaxis de las redirecciones se rompía, así que cambié.

Related Posts