# Configuración Catch‑All en Nginx

- Link: https://binariocero.com/linux/configuracion-catch-all-en-nginx
- Published: 2025-08-18T02:38:43+02:00
- Author: Juan José Fernández Durán

![Loading](https://binariocero.com/wp-content/plugins/page-views-count/ajax-loader-
2x.gif)

Guía técnica para capturar y controlar todo el tráfico destinado a hosts no declarados
o rutas por defecto, tanto en HTTP como en HTTPS, con ejemplos de archivos de configuración
listos para producción.

## 1. ¿Qué es un _catch‑all_ en Nginx?

Un _catch‑all_ es un bloque `server` que actúa como **destino por defecto** cuando:

 * El `Host` solicitado no coincide con ningún `server_name` declarado.
 * El puerto solicitado no tiene un bloque más específico.

Su uso típico es:

 * Redirigir tráfico desconocido hacia un dominio canónico.
 * Responder con **códigos de control** (p. ej., `444` para cortar conexiones indeseadas,`
   404/410`).
 * Mostrar una **página de mantenimiento** o banner legal.
 * Proteger el _origin_ de un _reverse proxy_ público.

> Clave: se implementa con la directiva `default_server` en la **escucha del puerto**(`
> listen`).

## 2. Diseño recomendado

 * **Separar HTTP y HTTPS**: define un _catch‑all_ para `:80` y otro para `:443`
   con TLS.
 * **Usar **`**server_name _;**`: el guion bajo es un patrón que no coincidirá con
   dominios reales y documenta la intención.
 * **Respuestas claras**: `return` es preferible a `rewrite` cuando la lógica es
   simple.
 * **Registro (logs) mínimo** en el _catch‑all_ para evitar ruido, con rotación 
   y formato propio.

## 3. Estructura de ficheros

    ```wp-block-code
    /etc/nginx/
    ├── nginx.conf
    └── sites-available/
        ├── 00-catch-all-http.conf
        ├── 00-catch-all-https.conf
        └── ... (otros sitios)
    └── sites-enabled/ -> enlaces simbólicos
    ```

> En distribuciones sin `sites-available/sites-enabled` (p. ej., Alpine por defecto),
> incluye los _server blocks_ directamente en `nginx.conf` o crea tu propia convención
> y `include`.

## 4. Ejemplo: _catch‑all_ HTTP (80)

**Archivo:** `/etc/nginx/sites-available/00-catch-all-http.conf`

    ```wp-block-code
    server {
        listen 80 default_server reuseport;
        listen [::]:80 default_server;

        server_name _;

        # Opciones de seguridad y rendimiento mínimas
        keepalive_timeout 10;
        client_body_timeout 10;
        client_header_timeout 10;

        # Logs específicos y discretos
        access_log /var/log/nginx/catch-all.access.log main if=$log_catch_all;
        error_log  /var/log/nginx/catch-all.error.log warn;

        # Flag para reducir ruido en logs
        set $log_catch_all 0;

        # Política por defecto: redirigir todo a dominio canónico (HTTP -> HTTPS)
        # Reemplaza ejemplo.com por tu dominio público
        return 301 https://ejemplo.com$request_uri;
    }
    ```

**Notas:**

 * `default_server` garantiza que este bloque maneje cualquier `Host` no declarado
   en :80.
 * Cambia la política si prefieres **cerrar** en lugar de redirigir (ver sección
   6).

## 5. Ejemplo: _catch‑all_ HTTPS (443) con TLS

**Archivo:** `/etc/nginx/sites-available/00-catch-all-https.conf`

    ```wp-block-code
    server {
        listen 443 ssl http2 default_server reuseport;
        listen [::]:443 ssl http2 default_server;

        server_name _;

        # Certificado barajado por defecto (comodín o cert genérico). Puede ser un "dummy".
        ssl_certificate     /etc/nginx/ssl/catch-all/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/catch-all/privkey.pem;

        # Perfil TLS razonable
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;

        # Logs discretos
        access_log /var/log/nginx/catch-all-https.access.log main if=$log_catch_all;
        error_log  /var/log/nginx/catch-all-https.error.log warn;

        set $log_catch_all 0;

        # Política por defecto: redirigir a dominio canónico en HTTPS
        return 308 https://ejemplo.com$request_uri;
    }
    ```

**Notas:**

 * En TLS, Nginx elige el _default\_server_ cuando **no hay coincidencia SNI**.
 * Usa un certificado válido (comodín o SAN) si quieres evitar avisos del cliente
   cuando la conexión caiga aquí.

## 6. Políticas alternativas (sustituye `return` del ejemplo)

### 6.1 Rechazar tráfico desconocido sin respuesta (desechar)

    ```wp-block-code
    return 444;  # Corta la conexión sin payload
    ```

### 6.2 Responder 404/410 (ocultar superficie)

    ```wp-block-code
    return 404;  # o 410 si quieres indicar recurso definitivamente inexistente
    ```

### 6.3 Página de mantenimiento simple

    ```wp-block-code
    root /var/www/catch-all;
    location = / {
        try_files /index.html =503;
    }
    error_page 503 /maintenance.html;
    location = /maintenance.html { internal; }
    ```

### 6.4 Bloquear por _Source IP_ o ASN (ejemplo básico)

    ```wp-block-code
    # Permite sólo una red interna (ej., para origins detrás de WAF)
    allow 10.0.0.0/8;
    deny  all;
    return 444;
    ```

## 7. Variables, mapas y formato de log para depurar _Host_ desconocidos

Amplía `nginx.conf` con un `map` para activar logs sólo cuando el `Host` no coincida
con los tuyos.

**Fragmento para **`**http**`** en **`**nginx.conf**`**:**

    ```wp-block-code
    http {
        # ... otras directivas ...

        # Enumera tus dominios "legítimos" para silenciar logs en ellos
        map $host $log_catch_all {
            default 1;                 # Log por defecto
            ejemplo.com 0;
            www.ejemplo.com 0;
            api.ejemplo.com 0;
        }

        log_format main '$remote_addr - $host $request "$status" $body_bytes_sent "$http_referer" "$http_user_agent"';

        # include de sitios
        include /etc/nginx/sites-enabled/*.conf;
    }
    ```

## 8. Activación, validación y recarga

    ```wp-block-code
    # Crear enlaces simbólicos
    ln -s /etc/nginx/sites-available/00-catch-all-http.conf  /etc/nginx/sites-enabled/
    ln -s /etc/nginx/sites-available/00-catch-all-https.conf /etc/nginx/sites-enabled/

    # Validar sintaxis
    ginx -t

    # Recargar sin cortar conexiones
    nginx -s reload
    # o
    systemctl reload nginx
    ```

## 9. Escenarios comunes y _pitfalls_

 1. **Orden de evaluación:** Nginx selecciona `server` por puerto y SNI; dentro de 
    los candidatos, elige el más específico. Asegúrate de tener `default_server` sólo
    en tu catch‑all.
 2. **Certificado inválido en catch‑all:** si devuelves 308/301 a dominio válido, los
    navegadores pueden mostrar aviso antes de seguir. Considera usar un comodín (p.
    ej., `*.ejemplo.com`) o devolver `444` en su lugar.
 3. **Bucles de redirección:** valida que el dominio canónico no apunte a este _server
    block_.
 4. **Proxy inverso/WAF delante:** define _allow/deny_ y cabeceras (`X-Forwarded-For`,`
    Real-IP`) si tu catch‑all está expuesto al público.
 5. **Multitenant:** si alojas muchos `server_name`, revisa periódicamente el log del
    catch‑all para detectar _typos_ DNS o intentos maliciosos.

## 10. Variante: catch‑all como _sinkhole_ anti‑escaneo

    ```wp-block-code
    server {
        listen 80 default_server;
        server_name _;

        add_header Connection close;
        return 444;
    }
    ```

> Minimiza consumo y visibilidad; útil en _origins_ no pensados para tráfico directo.

## 11. Variante: redirección canónica multi‑dominio

    ```wp-block-code
    server {
        listen 80 default_server;
        server_name _;

        # Si llega desde un conjunto de dominios antiguos, redirige a su equivalencia
        if ($host ~* "^(old1\.com|old2\.net)$") { return 301 https://nuevo.com$request_uri; }

        # Resto, 404
        return 404;
    }
    ```

## 12. Apéndice: plantilla completa combinada

    ```wp-block-code
    # /etc/nginx/nginx.conf (extracto)
    user  nginx;
    worker_processes auto;

    error_log /var/log/nginx/error.log warn;
    pid       /var/run/nginx.pid;

    events { worker_connections 4096; }

    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;

        # Map para logging selectivo del catch‑all
        map $host $log_catch_all {
            default 1;
            ejemplo.com 0;
            www.ejemplo.com 0;
            api.ejemplo.com 0;
        }

        log_format main '$remote_addr - [$time_local] "$request" $status $body_bytes_sent '
                         '"$http_referer" "$http_user_agent" host=$host';

        include /etc/nginx/sites-enabled/*.conf;
    }
    ```

    ```wp-block-code
    # /etc/nginx/sites-available/00-catch-all-http.conf
    server {
        listen 80 default_server reuseport;
        listen [::]:80 default_server;
        server_name _;

        access_log /var/log/nginx/catch-all.access.log main if=$log_catch_all;
        error_log  /var/log/nginx/catch-all.error.log warn;

        return 301 https://ejemplo.com$request_uri;
    }
    ```

    ```wp-block-code
    # /etc/nginx/sites-available/00-catch-all-https.conf
    server {
        listen 443 ssl http2 default_server reuseport;
        listen [::]:443 ssl http2 default_server;

        server_name _;

        ssl_certificate     /etc/nginx/ssl/catch-all/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/catch-all/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;

        access_log /var/log/nginx/catch-all-https.access.log main if=$log_catch_all;
        error_log  /var/log/nginx/catch-all-https.error.log warn;

        return 308 https://ejemplo.com$request_uri;
    }
    ```

## 13. Verificación rápida

 1. Resolver un `Host` aleatorio a tu IP pública y ejecutar:
    `curl -I http://IP --header'
    Host: noexiste.tld' curl -I https://IP --header 'Host: noexiste.tld' -k`
 2. Confirmar que responde según tu política (301/308/404/444).
