---
title: "Restringe el acceso a un servidor y pon un WAF delante de tu aplicación"
description: "erpc worker restringe el acceso a un servidor desde el primer despliegue, y una tabla en erpc.toml pone un WAF delante de una API pública. Qué hace y qué no."
canonical: "https://erpc.global/es/doc/erpc-cli/worker-firewall-and-waf/"
locale: "es"
---

# Restringe el acceso a un servidor y pon un WAF delante de tu aplicación

Desde el primer despliegue, `erpc worker` permite SSH solo desde tu dirección y descarta todas las demás conexiones entrantes. Una tabla `[waf]` pone un proxy de filtrado delante de tu API.

Esta página describe ERPC CLI `v0.1.0-rc.4`, una versión preliminar.

## El firewall

Un despliegue configura el firewall del servidor antes de que la aplicación arranque por primera vez:

- SSH solo desde `firewall.ssh_allow` y desde la dirección de la que procede el despliegue;
- todas las demás conexiones entrantes descartadas, excepto `run.port` desde `firewall.app_allow`; para una aplicación detrás de un WAF, el puerto del WAF en su lugar, y solo donde el WAF del servidor ya aplica las reglas que `[waf]` define ahora ([más abajo](https://erpc.global/es/doc/erpc-cli/worker-firewall-and-waf/#poner-un-waf-delante-de-tu-aplicación)).

Cada cambio se ejecuta con un temporizador de rollback de 120 segundos y solo se conserva una vez que una conexión nueva consigue entrar, así que un cambio erróneo no puede dejarte fuera.

Sin embargo, la lista blanca sobrevive a la dirección desde la que se creó: si cambia la dirección de tu casa, la forma de volver a entrar es el soporte de ERPC para un servidor de ERPC, o la consola del proveedor para un servidor propio. Mantén en `firewall.ssh_allow` una segunda dirección desde la que puedas llegar al servidor (una oficina, una salida de VPN) antes de confiar en la de tu casa.

Si tu dirección cambia, añade todas las direcciones fijas que usan tus administradores:

```bash
erpc worker firewall allow --to ssh 203.0.113.10 198.51.100.7
```

| Comando | Qué hace |
| --- | --- |
| `erpc worker firewall list` | Muestra quién puede llegar al servidor: `erpc.toml` junto a la tabla del servidor |
| `erpc worker firewall allow --to ssh\|app <addresses>` | Permite la entrada a las direcciones y lo aplica. SSH se permite desde direcciones individuales; una red solo se acepta con `--to app` |
| `erpc worker firewall deny --to ssh\|app <addresses>` | Deja de permitirles la entrada |
| `erpc worker firewall sync` | Hace que el firewall del servidor vuelva a ser lo que dice `erpc.toml` |

## Poner un WAF delante de tu aplicación

Añade una tabla a `erpc.toml`:

```toml
[waf]
port = 8080
```

Después, `erpc worker deploy` ejecuta un proxy inverso HTTP en el servidor, en una unidad systemd propia (`erpc-waf-<app>-<env>`): un usuario dinámico sin privilegios, sin clave, sin secreto y sin nada del worker, limitado a 1 GiB de memoria. Escucha en `waf.port`, lee cada solicitud antes que la aplicación, rechaza lo que nombran sus reglas y reenvía el resto a la aplicación en `127.0.0.1:<run.port>`.

- **La aplicación se queda en el loopback.** Su propio puerto nunca se abre desde fuera. `erpc worker api` y la comprobación de salud llegan a la aplicación por el loopback, sin pasar por el WAF.
- **Quién puede conectarse sigue siendo la lista del firewall**, y el puerto del WAF es el único sitio donde esa lista puede decir «todos»:

  ```sh
  erpc worker firewall allow --to app 0.0.0.0/0     # and ::/0
  ```

  Si no hay nadie en la lista, el WAF escucha y no se deja entrar a nadie, y el despliegue lo indica.
- **El puerto se abre una vez que el WAF escucha en él**, nunca antes. Un despliegue cuyo WAF no arranca falla y dice por qué, con la aplicación todavía en ejecución.
- **Cuando cambias `[waf]`,** el puerto no se abre a nadie nuevo hasta que un despliegue haya dejado aplicadas las reglas nuevas.
- **Quitar `[waf]`** de `erpc.toml` y desplegar elimina el WAF del servidor.

## Ajustes del WAF

Solo `port` es obligatorio. Todas las claves, con su valor predeterminado:

```toml
[waf]
port = 8080          # the public port, 1024 or above; the app keeps [run] port
methods = ["GET", "POST", "PUT", "DELETE"]
allow_paths = []     # every path
deny_paths = []
max_body_bytes = 1048576
max_header_bytes = 16384
rate = { per_second = 50, burst = 100 }
max_connections_per_address = 32
ban = { after = 100, window_secs = 60, for_secs = 600 }
block_probes = true
header_timeout_secs = 10
body_timeout_secs = 30
upstream_timeout_secs = 30
new_connections = { per_second = 50, burst = 100 }
```

| Clave | Qué hace | Qué recibe lo rechazado |
| --- | --- | --- |
| `methods` | Los métodos que se reenvían, en mayúsculas (16 como máximo; nunca `CONNECT`) | 405, con `Allow` |
| `allow_paths` | Las rutas que se reenvían; si no se indica ninguna, son todas las rutas. Un patrón es una ruta, o todo lo que hay bajo un prefijo cuando termina en `*`: `/api/*` es `/api` y todo lo que hay debajo. Se compara con la ruta una vez decodificada por porcentaje, distinguiendo mayúsculas y minúsculas | 404 |
| `deny_paths` | Las rutas que se rechazan, escritas de la misma forma y comprobadas primero | 403 |
| `max_body_bytes` | El cuerpo de solicitud más grande, hasta 64 MiB | 413 |
| `max_header_bytes` | El tamaño máximo de la línea de solicitud y las cabeceras juntas, de 1024 a 65.536 | 431 |
| `rate` | Las solicitudes por segundo desde una dirección, y cuántas a la vez antes de que se aplique la tasa | 429, con `Retry-After` |
| `max_connections_per_address` | Las conexiones que una dirección mantiene a la vez | La conexión se cierra, sin respuesta |
| `ban` | Tras `after` solicitudes bloqueadas dentro de `window_secs`, la dirección se rechaza durante `for_secs` (hasta 30 días) | Sus conexiones se cierran, sin respuesta |
| `block_probes` | Rechaza lo que piden los escáneres (`/.env`, `/.git`, `/wp-login.php` y similares) | 403 |
| `header_timeout_secs` | Cuánto tiempo tiene un cliente para enviar la cabecera de una solicitud, de 1 a 120. También cuánto se espera a un cliente que se ha detenido a mitad de un cuerpo o que ha dejado de recibir su respuesta | 408 para la cabecera; 400 para un cuerpo que se detuvo; la conexión se cierra para una respuesta que no se recibe |
| `body_timeout_secs` | Cuánto puede tardar en total el cuerpo de una solicitud, de 1 a 600, sin contar el tiempo que el WAF espera a la aplicación | 408 |
| `upstream_timeout_secs` | Cuánto tiempo tiene la aplicación para aceptar la conexión y empezar a responder, de 1 a 600 | 504; 502 cuando la aplicación no está escuchando |
| `new_connections` | El límite propio del firewall de conexiones TCP nuevas por segundo desde una dirección al puerto del WAF, que nftables descarta antes de que el proxy las vea. Mientras el conjunto de direcciones de nftables está lleno, una dirección que no está en él no se cuenta, así que este límite no se le aplica hasta que el conjunto vuelva a tener espacio; los límites propios del proxy (`rate`, `max_connections_per_address`, `ban`) se siguen aplicando | El paquete se descarta |

`rate`, `max_connections_per_address`, `ban` y `new_connections` se desactivan con `false` (`ban = false`), y una clave omitida toma su valor predeterminado. `erpc worker check` indica qué hará la tabla `[waf]`, y qué tiene de incorrecto, antes de cualquier despliegue.

## Lo que el WAF hace sin necesidad de ajustes

- Una solicitud que no se lee como una única solicitud HTTP/1 inequívoca recibe 400, y lo mismo una ruta que no está en forma normal.
- Una solicitud para cambiar de protocolo (`Upgrade`) recibe 501.
- Cada rechazo cuenta para el veto, y cada rechazo cierra su conexión.
- Una dirección es una dirección IPv4, o un `/64` de IPv6.
- El WAF no reenvía las cabeceras de la conexión del cliente con el proxy (`Connection` y las cabeceras que nombra, `Keep-Alive`, `Proxy-Authenticate`, `Proxy-Authorization`, `Proxy-Connection`, `TE`, `Trailer`), `Expect`, las cabeceras cuyo nombre lleva un guion bajo, ni las cabeceras `Forwarded`, `X-Real-IP` y `X-Forwarded-Proto` que envía el propio cliente. Establece `X-Real-IP` en la dirección de la que vino la conexión y añade esa dirección al final de `X-Forwarded-For`; solo la última entrada de `X-Forwarded-For` procede del proxy.

## Ver lo que hace el WAF

| Comando | Muestra |
| --- | --- |
| `erpc worker status` | El puerto del WAF, adónde reenvía, desde cuándo y los recuentos desde entonces |
| `erpc worker firewall list` | Quién puede llegar al puerto del WAF y qué se ha bloqueado, por regla |
| `erpc worker logs --waf` | Cada solicitud bloqueada: la regla, el estado, la dirección del cliente, el método y los primeros 200 bytes del destino |

Una solicitud reenviada no deja ninguna línea en el log, y nunca se registra ninguna cabecera ni ningún cuerpo; la consulta de una solicitud bloqueada sí, hasta donde alcanzan los 200 bytes. Lo que envía un cliente no puede escribir en tu terminal: el WAF escribe su journal como ASCII imprimible.

## Lo que el WAF no hace

- **Sin TLS.** Habla HTTP/1.1 sin cifrar en su puerto.
- **Sin HTTP/2:** le responde con 400.
- **Sin WebSocket**, ni ningún otro `Upgrade`: 501.
- **No mira dentro de los cuerpos.** Un cuerpo se mide, nunca se lee. La lista de sondeos es corta y es un filtro de ruido, no una garantía: la aplicación sigue encargándose de comprobar su entrada.
- **Sin autenticación.** Quién puede llamar a la aplicación lo decide la aplicación, y la lista del firewall.
- **Una dirección es un cliente.** Los clientes detrás de un mismo NAT, proxy o CDN comparten una tasa y un veto; un cliente con muchas direcciones tiene tantas tasas como direcciones.
- **Los vetos y los recuentos se olvidan** cuando el WAF se reinicia.
- **Recuerda como máximo 8192 direcciones** y mantiene como máximo 1024 conexiones a la vez.
- **Solo escucha en IPv4,** así que una entrada IPv6 en `app_allow` todavía no llega a nada.
- **Una ruta se compara como los bytes a los que se decodifica.** A una aplicación que lee las rutas de forma más laxa (sin distinguir mayúsculas y minúsculas, con parámetros `;`, decodificando dos veces) se puede llegar con un nombre que `deny_paths` no cubre. `allow_paths` no tiene ese hueco: lo que no está en la lista no se reenvía.
- **A un lector lento se le sirve hasta el final.** A un cliente que sigue recibiendo una respuesta, por lento que sea, se le sirve hasta el final.
- **Una avalancha puede cortar una subida grande.** El WAF se ejecuta en un solo hilo, así que una avalancha puede cortar una subida grande con 408. Una aplicación que acepta cuerpos grandes sube `body_timeout_secs` junto con `max_body_bytes`.

[La guía del worker](https://github.com/elsoul/erpc-cli/blob/v0.1.0-rc.4/docs/worker.md) tiene todas las reglas, incluido cuándo un cambio en `app_allow` se retiene hasta el siguiente despliegue.
