
Mantener un VPS en línea bajo DDoS
Tres ataques bastante distintos comparten el nombre DDoS, y casi todo lo que se lee al respecto falla porque los trata como si fueran uno solo: responde a un enlace ascendente saturado con una directiva de nginx, o a una inundación de capa 7 con un servidor más grande. La pregunta útil nunca es “cómo bloqueo esto”, sino “en qué capa se puede detener esto físicamente, y quién controla esa capa”. Esta página responde a eso para una máquina Linux alquilada — lo que la red por encima de usted absorbe antes de que usted lo vea siquiera, lo que realmente ayuda dentro de la máquina, y por qué el movimiento más eficaz suele ser, sencillamente, dejar de ser direccionable.
La mitigación volumétrica en esta red está siempre activa y no hay nada que usted deba habilitar: las inundaciones por debajo de 10 Gbps se absorben en silencio, entre 10 y 100 Gbps se depuran en el proveedor de tránsito, y todo lo que supera eso se anuncia por una ruta de depuración dedicada — los umbrales están escritos en la documentación y no dejados como un adjetivo de marketing. Ese es el límite honesto de lo que un proveedor de hosting puede ofrecerle. Y también es, para el tráfico que realmente tumba a los servidores pequeños, la mitad menos interesante del problema.
Porque los ataques que matan de forma fiable a un VPS de 5 dólares no son los monstruos de 340 Gbps que salen en las noticias. Son 40.000 paquetes por segundo de pequeños SYN que llenan una tabla de estados que usted nunca ha mirado, o 300 solicitudes por segundo a la única URL de su sitio que ejecuta una consulta a la base de datos — tráfico que llega a una interfaz perfectamente sana, por un enlace que ni de lejos está lleno, y que ningún sistema de depuración aguas arriba puede distinguir de sus usuarios. Esos son los que le tocan a usted, y se resuelven con unas veinte líneas de configuración, siempre que primero averigüe cuál de los tres tiene delante.
Lo que sigue asume Debian 13 o Ubuntu 24.04, nftables y nginx, y asume que usted ya ha hecho el endurecimiento de la primera hora — un servidor que todavía responde en puertos que no ofrece no está listo para ser defendido.
Tres ataques, un mismo nombre
“DDoS” describe una intención, no un mecanismo, y los mecanismos no tienen casi nada en común entre sí. Clasificarlos correctamente no es pedantería: es todo el trabajo, porque cada uno se puede detener en exactamente una capa y es invisible en las demás.
Las inundaciones volumétricas apuntan a su ancho de banda. La amplificación UDP — DNS, NTP, memcached y, últimamente, cualquier cosa que responda a una pregunta pequeña con una respuesta grande — permite a un atacante convertir 1 Gbps de su propia capacidad en 50 Gbps dirigidos contra usted. El objetivo es el enlace, no el servidor. Su CPU se aburrirá durante todo el proceso.
Los ataques de protocolo y de estado apuntan a una tabla finita de su kernel. Una inundación SYN intenta agotar la cola de aceptación; una inundación genérica de paquetes pequeños intenta agotar el seguimiento de conexiones. Ambos se miden en paquetes por segundo, no en bits por segundo, y ambos pueden matar una máquina en un enlace inactivo en un noventa y siete por ciento. Esta es la clase que tumba a los servidores pequeños, y la que se saltan la mayoría de las guías.
Las inundaciones de capa de aplicación apuntan a su CPU o a su base de datos, usando solicitudes indistinguibles de las reales porque son reales. Cien solicitudes por segundo a un endpoint de búsqueda no son nada para una red y son letales para una aplicación PHP. Ningún sistema de depuración aguas arriba puede filtrar esto por usted: visto desde fuera, es exactamente igual que el éxito.
Hay una cuarta cosa que llega disfrazada de las tres anteriores y que no es un ataque en absoluto: un enlace que le ha ido bien en algún sitio, un cliente propio que se está portando mal, o un rastreador sin modales. Descartar esto primero no cuesta nada, y da vergüenza lo a menudo que resulta ser la explicación.
La parte que no puede arreglar desde dentro de la máquina
Si dirigen 60 Gbps contra su dirección y su puerto es de 1 Gbps, la decisión sobre esos paquetes se toma en un router aguas arriba de usted, varios saltos antes de nada que usted administre. Su firewall nunca los ve. No puede: se descartaron para proteger un enlace que no es suyo. Este es el hecho estructural más importante sobre los ataques volumétricos, y la razón por la que “endurezca su firewall contra el DDoS” es, en la mayoría de los casos, una tontería.
Así que las únicas preguntas que importan son qué hace su proveedor de forma automática y dónde están sus umbrales. Los nuestros están publicados, no solo prometidos: por debajo de 10 Gbps se absorbe sin efecto visible, entre 10 y 100 Gbps se depura en el proveedor de tránsito y puede notar un pequeño aumento de latencia, y por encima de 100 Gbps el prefijo se anuncia por una ruta de depuración dedicada — la latencia sube de forma más perceptible, pero el servicio se mantiene accesible. El null-routing de una dirección solo se plantea para ataques sostenidos que amenacen al PoP en su conjunto, y se lo comunicamos en cuestión de minutos si llega a ocurrir. No hay nada que comprar ni nada que activar.
Hay dos cosas sobre la depuración que vale la pena saber y que los proveedores rara vez cuentan por voluntad propia. La primera es que a usted lo protege el vecindario, no solo sus propias defensas: un ataque contra un cliente que comparte su /20 aguas arriba se absorbe antes de que llegue al prefijo de nadie — una inundación de ~340 Gbps dirigida contra un rango vecino en París pasó sin impacto medible en el nuestro, que es exactamente el resultado que nadie nota. La segunda es que los sistemas de depuración son heurísticas, y las heurísticas a veces se equivocan: en esta misma red, un sistema de depuración llegó a pasar nueve minutos emitiendo resets TCP contra conexiones legítimas mientras filtraba un ataque contra un vecino. Ambos incidentes están en el registro público de incidentes. Si sus sesiones mueren de una forma que se parece más a un reset activo que a un timeout durante el ataque de otra persona, eso es un fallo real y merece reportarse en lugar de depurarlo localmente durante una hora.
Noventa segundos de medición, antes de cambiar nada
Toda respuesta equivocada a un DDoS empieza con un cambio hecho antes de que nadie supiera qué estaba pasando. Obtenga primero cuatro cifras. Caben en una sola pantalla y le dicen la capa por usted.
# 1. bits vs packets — which axis is saturated?
sar -n DEV 1 5 # or: ifstat -i eth0 1
# 2. socket states — SYN-RECV piling up means a SYN flood
ss -s
ss -tan state syn-recv | wc -l
# 3. kernel drop counters (these are the ones that matter)
nstat -az | grep -E 'ListenDrops|ListenOverflows|SyncookiesSent|TCPReqQFullDrop'
dmesg -T | tail -20 # look for: nf_conntrack: table full, dropping packet
# 4. connection tracking headroom
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_maxLéalas juntas. Muchos bits por segundo, pocos paquetes por segundo, poca CPU es un ataque volumétrico, y su trabajo es confirmarlo y dejar de teclear. Muchos paquetes por segundo, pocos bits por segundo — muchísimos paquetes diminutos — es un ataque de estado; mire de inmediato SyncookiesSent y el contador de conntrack. Tráfico modesto en ambos ejes con la CPU al límite es capa 7, y la respuesta está en su servidor web y su base de datos, no en su firewall.
Vale la pena interiorizar una lectura contraintuitiva: durante una inundación volumétrica genuina, su interfaz puede parecer casi tranquila. Lo que ve son los supervivientes — lo que cabe por un enlace que ya está lleno, o lo que el sistema de depuración aguas arriba ha dejado pasar. Una interfaz que marca 900 Mbps en un puerto de 1 Gbps mientras los usuarios reportan una inalcanzabilidad total no es una prueba en contra de un ataque. Es la forma que tiene uno.
Después, compruebe que el tráfico no sea simplemente real. Aplique tail -f a su log de accesos durante diez segundos: una única ruta repetida por miles de direcciones distintas sin referrer es un ataque; una variedad de rutas normales desde navegadores normales es una audiencia, y limitarle la tasa le hará el trabajo al atacante gratis.
Reduzca el blanco antes del ataque, no durante él
Cada puerto abierto es una cola que un atacante puede llenar, y cada paquete que su instancia tiene que mirar le cuesta CPU y una entrada de conntrack incluso cuando lo descarta. El paquete más barato es el que su máquina nunca recibe, y por eso filtrar por encima de la instancia vale más que filtrar dentro de ella.
Aquí hay dos capas, y no son lo mismo. El filtro de borde es opcional, se configura por servidor, mantiene estado y deniega por defecto, y se ejecuta en el hipervisor — el tráfico que rechaza ahí nunca llega siquiera a su NIC virtual, así que no le cuesta CPU, ni memoria, ni una entrada en la tabla de estados. El firewall de la instancia — su conjunto de reglas de nftables — es enteramente suyo y nosotros nunca lo tocamos. El patrón que sobrevive al contacto con un ataque es expresar en el borde la verdad tosca y estable de la capa 4 (“esta máquina sirve 80, 443 y SSH desde estas direcciones, y no existe nada más”) y reservar el conjunto de reglas de la instancia para el trabajo fino que cambia con su aplicación. Ambos se describen en la documentación del firewall.
Después, reduzca lo que queda. Restringir SSH a las direcciones desde las que administra de verdad no es aquí un simple detalle de endurecimiento — elimina de su máquina toda una clase de ataque de agotamiento de conexiones. Una base de datos vinculada a 127.0.0.1 o a una dirección WireGuard no se puede inundar en absoluto desde internet. Y si expone un plano de control puramente interno, colóquelo detrás de una interfaz WireGuard en lugar de un puerto público con una contraseña.
Inundaciones SYN y la cola de aceptación
Una inundación SYN explota el handshake: el atacante envía un flujo de solicitudes de conexión y nunca las completa, y cada una ocupa un hueco en la cola SYN del kernel hasta que expira. Si llena la cola, los handshakes legítimos se descartan — su servicio está activo, escuchando, e inalcanzable.
Linux tiene una respuesta limpia desde los años noventa, y está activa por defecto. Las SYN cookies permiten que el kernel deje de reservar memoria para conexiones semiabiertas por completo: codifica el estado de la conexión en el número de secuencia que devuelve, y lo reconstruye si el cliente completa el handshake. Confírmelo en lugar de darlo por hecho, y dele a las colas margen suficiente para aguantar una ráfaga:
# /etc/sysctl.d/99-flood.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 8192
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_abort_on_overflow = 0
sysctl --systemtcp_synack_retries = 2 importa más de lo que parece: el valor por defecto de cinco hace que un handshake falsificado ocupe el kernel durante unos tres minutos, y ponerlo en dos lo reduce a unos siete segundos. Subir somaxconn es solo la mitad del trabajo — la profundidad real de la cola es el mínimo entre ese valor y lo que pidió la aplicación, así que nginx necesita listen 443 ssl backlog=8192; y una recarga antes de que el ajuste del kernel signifique algo. Este es el caso clásico de un sysctl que parece aplicado y no hace nada.
Si quiere detener la inundación antes de que llegue siquiera a la aplicación, nftables puede completar los handshakes en nombre del kernel y entregar solo las conexiones que resulten ser reales:
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iif lo accept
tcp dport { 80, 443 } ct state new synproxy mss 1460 wscale 7 timestamp sack-perm
tcp dport { 80, 443 } accept
ip protocol icmp icmp type echo-request limit rate 5/second accept
}
}Pruebe synproxy en una máquina a la que todavía pueda acceder por consola antes de confiar en él; mal configurado, es una forma excelente de dejarse fuera de su propio servidor a firewall limpio. Para la mayoría, el bloque de sysctl anterior basta, y el orden honesto de prioridades es: primero syncookies, después el backlog, y synproxy solo si ha medido que los dos primeros no bastaban.
La tabla que nadie mira hasta que se llena
Esta es la que sorprende hasta a la gente con experiencia. Un firewall con estado tiene que recordar cada flujo que ha visto, y esa memoria es nf_conntrack, una tabla hash de tamaño fijo elegido al arrancar. Una vez llena, el kernel descarta las conexiones nuevas — todas, tanto las del atacante como las del cliente — y registra una única línea en dmesg que nadie está mirando:
nf_conntrack: table full, dropping packetEl motivo de que sea tan eficaz es puramente aritmético. Una tabla por defecto en un VPS pequeño contiene del orden de unas pocas decenas de miles de entradas, y cada paquete de una dirección de origen nueva crea una — incluidos los paquetes UDP, incluidos los paquetes que usted descarta, incluida la propia inundación. Veinte mil paquetes por segundo desde direcciones falsificadas la llenan en menos de dos segundos, en un enlace que transporta unos pocos megabits. Su gráfica de ancho de banda no mostrará absolutamente nada.
# /etc/sysctl.d/99-conntrack.conf
net.netfilter.nf_conntrack_max = 262144
net.netfilter.nf_conntrack_buckets = 65536
net.netfilter.nf_conntrack_tcp_timeout_established = 3600
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20
net.netfilter.nf_conntrack_udp_timeout = 20Los timeouts hacen más bien que el tamaño. La vida por defecto de un flujo TCP establecido es de cinco días, lo que significa que un servidor que lleva una semana encendido sigue guardando estado de conexiones que terminaron el martes; una hora es de sobra para cualquier cosa que no sea una sesión SSH inactiva, y net.ipv4.tcp_keepalive_time = 600 mantiene esas vivas correctamente en lugar de por accidente. Al dimensionar, calcule unos 300 bytes de memoria del kernel por entrada: 262.144 entradas son unos 80 MB, lo cual está bien en una máquina de 4 GB y no está nada bien si lo pone en diez millones porque lo dijo un foro.
Si ejecuta algo genuinamente sin estado y de alto volumen — un servidor DNS autoritativo, un servidor de juego público, un repetidor de Tor — la mejor respuesta es dejar de rastrearlo por completo. El seguimiento de conexiones para un servicio que no tiene conexiones con sentido es puro coste:
table ip raw {
chain prerouting {
type filter hook prerouting priority raw; policy accept;
udp dport 51820 notrack
tcp dport 9001 notrack
}
}Recuerde que ese tráfico entonces se salta sus reglas de ct state established, así que necesita reglas explícitas de aceptación en la cadena de filtrado. Ese es el trato: renuncia al seguimiento de estado para ese puerto y a cambio obtiene una tabla que no se puede llenar.
Capa 7: la inundación que se parece exactamente a sus clientes
El ataque más eficiente contra un servidor pequeño no es una inundación en absoluto. Son unos pocos cientos de solicitudes HTTP bien elegidas por segundo, cada una perfectamente válida, cada una golpeando el único endpoint que ejecuta una consulta sin índice o renderiza una página sin caché. La economía es brutal: la solicitud le cuesta al atacante unos pocos cientos de bytes y a usted le cuesta 200 milisegundos de CPU y una conexión a la base de datos. Esa carrera la pierde a cualquier volumen que pueda permitirse servir.
El instinto es bloquear al atacante. Contra una red de bots repartida entre miles de direcciones residenciales, cada una enviando dos solicitudes por segundo, bloquear por IP es puro teatro — ningún límite de tasa por dirección que permita pasar a sus usuarios reales llegará jamás a activarse, y se pasará toda la caída añadiendo reglas mientras el sitio sigue abajo. La jugada ganadora es cambiar el coste, no la cuenta.
Ponga caché primero, y guarde en caché también el fallo. Una caché de página completa convierte una solicitud costosa en una lectura de memoria, y la directiva que más importa durante un ataque es la que impide que mil fallos simultáneos se conviertan en mil consultas simultáneas a la base de datos:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app:64m max_size=2g inactive=60m;
server {
location / {
proxy_cache app;
proxy_cache_valid 200 301 302 10m;
proxy_cache_lock on; # one origin request per key, not a thousand
proxy_cache_lock_timeout 5s;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on; # serve stale, refresh behind it
add_header X-Cache $upstream_cache_status always;
proxy_pass http://127.0.0.1:8080;
}
}proxy_cache_lock y use_stale son las dos líneas que deciden si un pico de tráfico se puede sobrevivir. Sin ellas, en el momento en que expira una clave caliente, cada solicitud en curso se convierte en una solicitud al origen — la estampida que convierte un ataque manejable en una caída. Con ellas, su backend sirve una solicitud por clave y por intervalo, y todos los demás reciben una página ligeramente desactualizada, lo cual es el trato correcto en cualquier situación donde la alternativa sea no servir página en absoluto.
Después, limite la tasa específicamente de las rutas costosas, con generosidad, y de una forma que falle de manera visible:
limit_req_zone $binary_remote_addr zone=general:16m rate=20r/s;
limit_req_zone $binary_remote_addr zone=costly:16m rate=2r/s;
limit_conn_zone $binary_remote_addr zone=conn:16m;
limit_req_status 429;
limit_conn_status 429;
server {
limit_req zone=general burst=40 nodelay;
limit_conn conn 24;
location /search { limit_req zone=costly burst=5 nodelay; proxy_pass http://127.0.0.1:8080; }
location /login { limit_req zone=costly burst=3 nodelay; proxy_pass http://127.0.0.1:8080; }
}burst sin nodelay pone en cola las solicitudes que sobran en lugar de rechazarlas, lo que durante un ataque significa que nginx mantiene educadamente miles de conexiones abiertas en su nombre — ha convertido una inundación de solicitudes en una inundación de conexiones. Use nodelay, devuelva 429 de inmediato, y deje que el cliente se las arregle. Y detrás de cualquier proxy, recuerde que $binary_remote_addr es el proxy a menos que haya configurado correctamente set_real_ip_from y real_ip_header; un límite de tasa basado en la dirección de su propio frontal bloqueará a todos los usuarios a la vez la primera vez que se dispare.
Los ataques de estilo Slowloris — muchas conexiones, cada una goteando una solicitud un byte cada vez — apenas molestan al modelo de eventos de nginx, pero de todas formas vale la pena apretar los timeouts: client_header_timeout 8s; client_body_timeout 8s; send_timeout 10s; reset_timedout_connection on;. Combinado con limit_conn, esa es toda la defensa.
Por qué fail2ban no es una herramienta contra el DDoS
fail2ban es genuinamente útil, y apunta a un problema distinto. Lee archivos de log, decide tras N fallos en M minutos, e inserta una regla de firewall. Cada parte de eso tiene la forma equivocada para una inundación.
Es demasiado lento: una ráfaga que dura cuarenta segundos termina antes de que se cierre la ventana de baneo. Lee logs, así que el ataque ya le ha costado el precio completo de cada solicitud — el análisis ocurre después del daño. Banea direcciones individuales, así que contra diez mil fuentes, o bien no hace nada, o bien inserta diez mil reglas lineales, momento en el cual el propio firewall se convierte en el cuello de botella y usted ha completado el ataque en nombre de su atacante. Y depende de sus logs, así que una inundación lo bastante grande como para llenar un disco con líneas de log puede tumbar el servidor por una vía que nunca contempló.
Si quiere bloqueo dinámico, hágalo en el plano de datos, donde la búsqueda es un hash y la expiración es automática. Un conjunto dinámico de nftables es O(1) sin importar el tamaño, y se olvida solo:
table inet filter {
set flooders {
type ipv4_addr
flags dynamic, timeout
timeout 10m
size 65535
}
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iif lo accept
ip saddr @flooders drop
tcp dport { 80, 443 } ct state new add @flooders { ip saddr limit rate over 50/second burst 100 packets } drop
tcp dport { 80, 443 } accept
}
}Lea la regla con atención, porque la negación confunde a la gente: la dirección se añade al conjunto y se descarta solo cuando la tasa está por encima del límite. Reserve fail2ban para aquello en lo que es bueno — la adivinación lenta de credenciales contra SSH y contra logins de aplicaciones, donde un baneo a escala humana sobre una dirección concreta es exactamente lo correcto.
No sea un arma: la amplificación que está alojando
Todo ataque volumétrico grande funciona gracias a servidores cuyos operadores no sabían que estaban participando. El mecanismo es un servicio UDP que responde a una pequeña solicitud falsificada con una respuesta grande: un resolutor DNS abierto devuelve 50 veces lo que se le pidió, NTP y memcached mal configurados son peores todavía, y cualquier protocolo que responda antes de poder verificar quién pregunta es candidato.
Las consecuencias le caen a usted antes que a la víctima. Su enlace ascendente se llena con sus propias respuestas salientes, su proveedor ve tráfico abusivo sostenido saliendo de su puerto, y los proveedores de tránsito que lo reciben empiezan a aplicar null-routing a los rangos de donde viene — por eso la política de uso aceptable traza una línea infranqueable en el origen de ataques y la amplificación, mientras permite esencialmente todo lo demás. Ser un reflector involuntario es la forma más rápida de perder una dirección que no tiene nada que ver con lo que usted quería ejecutar.
# bind a recursive resolver to localhost, never 0.0.0.0
# unbound: interface: 127.0.0.1 + access-control: 0.0.0.0/0 refuse
# what is actually listening on a public address?
ss -ulpn
ss -tlpn
# from another machine, confirm you do not answer strangers
dig @your.server.ip example.com +short # must time out
ntpq -c rv your.server.ip # must failSi ejecuta un servicio UDP público a propósito — un servidor de juego, un servidor de nombres autoritativo, un endpoint WireGuard — la regla es la misma que en todas partes: limite la tasa de la respuesta, nunca de la solicitud. Tanto bind como knot implementan limitación de tasa de respuesta; úsela, porque es la diferencia entre servir a sus usuarios y transportar el ataque de otro.
La defensa más eficaz es no ser localizable
Todo lo anterior es control de daños para un ataque que ya ha encontrado su dirección. Vale la pena hacerlo, y es la segunda mejor opción. Un origen que nadie puede nombrar no es atacable en absoluto en la capa 3 ni en la 4, y separar la dirección que sirve el tráfico de la dirección que el mundo conoce es lo que más rinde de toda esta página.
Las direcciones de origen casi nunca se filtran por ataques ingeniosos. Se filtran por historia y por descuido, en una lista corta y bien conocida. Los registros DNS antiguos son el culpable habitual: los archivos de DNS pasivo recuerdan para siempre el registro A que tenía antes de poner en marcha un frontal. Los logs de transparencia de certificados son públicos y permanentes, así que un certificado emitido para un nombre de host que apuntaba directamente al origen es un registro firmado y con marca de tiempo de dónde vivía usted antes. El correo saliente estampa la dirección del servidor remitente en las cabeceras de cada mensaje. Y el silencioso: su servidor web respondiendo en su IP desnuda, que permite que cualquiera que escanee el espacio de direcciones buscando el HTML de su sitio le encuentre por contenido en una tarde.
Ese último es una corrección de dos líneas y casi nadie la aplica. Haga que el servidor por defecto rechace todo lo que no llegue con un nombre de host que usted sirva:
server {
listen 80 default_server;
listen 443 ssl default_server;
ssl_reject_handshake on; # nginx 1.19.4+: no certificate, no fingerprint
return 444; # close without a response
}Después, elija un frontal. Una CDN comercial es la respuesta obvia y viene con un coste real que aquí importa: está añadiendo una empresa que termina su TLS, ve su tráfico en claro, conoce su origen, y puede recibir un requerimiento legal en una jurisdicción que usted no eligió — lo cual deshace buena parte de la razón por la que el servidor se pagó en cripto sin un nombre asociado. Si aun así lo hace, entienda que el origen no debe haber sido nunca público, y que todo el montaje falla en el momento en que alguien encuentra un registro antiguo.
La alternativa que conserva la propiedad por la que pagó es ser su propio frontal. Una instancia de 5 dólares en una segunda región, ejecutando nginx como proxy inverso, con el filtro de borde del origen aceptando tráfico solo desde esa única dirección, le da una dirección sacrificable que puede renumerar en cinco minutos y un plano de control que solo le responde a usted. Es la misma arquitectura, menos el tercero. Y allí donde la audiencia pueda usarlo, un servicio onion de Tor elimina la IP de la ecuación por completo — no hay dirección que inundar, aunque los servicios onion tienen su propia superficie de ataque en los puntos de introducción, que es precisamente por lo que el Tor moderno incorpora una defensa de prueba de trabajo para esto exactamente.
Bloquear países, ASN y la forma del tráfico
Tarde o temprano alguien propone bloquear un país. Es una medida burda, ocasionalmente acertada, y sobre todo una forma de sentirse ocupado.
Es defendible cuando su servicio tiene una audiencia genuinamente acotada — un servidor de juego regional, una herramienta interna, un panel de control — y usted está dispuesto a asumir los falsos positivos, que incluyen a sus propios usuarios de viaje y a cualquiera con un enrutamiento raro. Contra una botnet moderna es casi inútil, porque está distribuida entre conexiones residenciales de todos los países, incluido el suyo, y es activamente perjudicial para cualquier cosa pública: perderá gente real en silencio y nunca verá a los que se fueron.
Bloquear por ASN es más preciso. El tráfico de ataque que se origina en un puñado de proveedores de hosting — rangos de VPS baratos alquilados por hora — se puede descartar por prefijo con muchas menos víctimas colaterales que un bloqueo por país, porque los usuarios normales no navegan desde un centro de datos. Los rangos de centros de datos son también, convenientemente, de donde vienen el scraping y el credential stuffing.
Pero la versión duradera de esta idea no tiene nada que ver con la geografía: es filtrar por la forma del tráfico en lugar de por su origen. Un ataque suele compartir algo estructural — el mismo user agent, la misma cabecera ausente, la misma URL con el mismo parámetro de consulta, la misma huella TLS, una ausencia total de la segunda solicitud que siempre hace un navegador real. Encuentre la propiedad compartida y escriba una única regla que no cuesta nada y que sobrevive a que el atacante cambie de direcciones, cosa que hará más rápido de lo que usted pueda enumerarlas.
# in an attack: what do these requests have in common?
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 # addresses
awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 # user agents
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 # pathsSi un único user agent representa el noventa por ciento de las solicitudes, está a noventa segundos de una solución. Si las veinte direcciones principales representan un dos por ciento del tráfico cada una, deje de buscar direcciones — eso es un ataque distribuido, y la respuesta es la caché y los límites de tasa.
Cuando la dirección está quemada
A veces el ataque es dirigido, persistente y va contra usted personalmente y no contra una dirección al azar, y la respuesta correcta es dejar de defender la dirección y abandonarla. Esto no es una derrota; para un servicio pequeño suele ser el desenlace más barato posible, y solo duele si no lo ha ensayado.
Lo que lo hace rápido se decide de antemano. Mantenga los TTL de DNS en 300 segundos como postura permanente — el coste es insignificante y el beneficio es que puede mudarse en cinco minutos en lugar de un día. Mantenga su despliegue reproducible, porque un servidor que puede reconstruir es un servidor que puede mudar; si reconstruirlo significa recordar qué hizo usted en marzo, no tiene un plan, tiene un rehén. Mantenga una copia de seguridad restaurable en una región distinta, y sepa por un simulacro real cuánto tarda una restauración.
Entonces la mudanza en sí es corta: despliegue en otra región, restaure, verifique en la nueva dirección forzando el hostname antes de tocar el DNS, cambie el registro, y mantenga el servidor viejo funcionando el tiempo suficiente para que los últimos resolutores se pongan al día. La guía de migración cubre bien la secuencia, y es la misma tanto si se muda por rendimiento como si se muda porque alguien está enfadado.
El modelo de facturación hace que el ensayo sea prácticamente gratis: los cargos se prorratean a diario contra su saldo, así que una segunda máquina que despliegue, pruebe y destruya en una tarde cuesta centavos, y no hay contrato, ni tarjeta, ni renovación que cancelar. No hay ninguna razón para que su primera renumeración ocurra durante un ataque.
Lo que nada de esto le da
Dos notas finales honestas, porque el resto de esta página es optimista por construcción.
La primera es que ningún proveedor lo absorbe todo, y cualquiera que afirme lo contrario está vendiendo. La capacidad es finita, la capacidad de depuración lo es todavía más, y a suficiente escala, el acto económicamente racional para una red que protege a miles de clientes es dejar de anunciar una dirección. Nosotros tratamos eso como último recurso contra ataques sostenidos que amenacen al PoP en su conjunto, y se lo comunicamos en lugar de dejar que usted lo descubra depurando por su cuenta — pero una promesa de que eso nunca puede pasar sería una mentira, y debería desconfiar de cualquier proveedor que la haga.
La segunda es que la represalia no está sobre la mesa. Los servicios de booter y stresser son ataques por encargo disfrazados de herramientas de prueba, son ilegales en la mayoría de las jurisdicciones que importan, están vigilados de cerca, y aquí le terminarán el servidor bajo una política que permite casi todo lo demás. La misma asimetría que hace atractivo el DDoS para un atacante lo vuelve inútil para quien se defiende: no puede ganarle a inundaciones a alguien que no tiene nada que perder. Absorba, ponga en caché, múdese, y deje que se vuelva aburrido — que, para cualquiera que pague por el tráfico que envía, tarde o temprano se vuelve.
- Nombre la capa en noventa segundos
Antes de cualquier cambio de configuración, obtenga los dos ejes y los dos contadores. Bits altos y paquetes bajos es volumétrico; paquetes altos y bits bajos es un ataque de estado; ambos modestos con la CPU al límite es capa 7.
sar -n DEV 1 5 # bits/s and packets/s per interface ss -s # socket summary; watch synrecv nstat -az | grep -E 'ListenDrops|ListenOverflows|SyncookiesSent' cat /proc/sys/net/netfilter/nf_conntrack_count dmesg -T | grep -i conntrack | tailDespués, descarte el éxito y el autodaño: revise por encima el log de accesos durante diez segundos. Si las rutas parecen un sitio web en uso normal, tiene una audiencia o un bug, no un atacante.
- Haga que el kernel absorba inundaciones a bajo coste
Dos archivos, una recarga. Son seguros en cualquier servidor de propósito general y eliminan las dos formas más comunes en que se cae una máquina pequeña.
cat > /etc/sysctl.d/99-flood.conf <<'EOF' net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 8192 net.core.somaxconn = 8192 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_keepalive_time = 600 net.netfilter.nf_conntrack_max = 262144 net.netfilter.nf_conntrack_buckets = 65536 net.netfilter.nf_conntrack_tcp_timeout_established = 3600 net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20 EOF sysctl --system sysctl net.ipv4.tcp_syncookies net.netfilter.nf_conntrack_max # verify, do not assumeDespués, haga que la aplicación esté a la altura: nginx necesita
listen 443 ssl backlog=8192;, o la cola del kernel que acaba de agrandar queda limitada por el número más pequeño que pidió el proceso. - Cierre todo lo que no ofrezca, por encima de la instancia
Enumere qué está escuchando de verdad, decida qué pertenece a una dirección pública, y suba las reglas gruesas hasta el filtro de borde del hipervisor para que el tráfico nunca llegue a su NIC virtual.
ss -tlpn; ss -ulpn # every public listener, with the process that owns itEn Server → Network → Firewall, configure el filtro de borde para denegar por defecto y permitir solo los puertos que ofrece, con SSH restringido a las direcciones desde las que administra. Mantenga el conjunto de reglas de
nftablesde la instancia como su segunda capa — cinturón y tirantes, no lo uno o lo otro — y vincule bases de datos e interfaces de administración a127.0.0.1o a una dirección WireGuard en lugar de poner un puerto público tras un firewall. - Ponga una caché delante de la ruta costosa
Este es, con diferencia, el cambio de mayor valor para cualquier cosa que renderice páginas. Añada
proxy_cacheconproxy_cache_lock onyproxy_cache_use_stale, para que mil fallos simultáneos se conviertan en una sola solicitud al origen y todos los demás reciban una página ligeramente antigua.nginx -t && systemctl reload nginx curl -sI https://example.com/ | grep -i x-cache # MISS, then HITVerifique la tasa de aciertos antes de creérsela. Una caché que nunca acierta por culpa de un
Set-Cookieen cada respuesta es la falsa sensación de seguridad más común de todo este ejercicio — compruébelo concurl -sIdos veces y leaX-Cache. - Limite la tasa de las rutas que le cuestan a usted, no al visitante
Aplique un límite global generoso y uno estricto en los endpoints que tocan una base de datos. Siempre
nodelay, siempre con un código de estado, nunca una cola silenciosa.limit_req_zone $binary_remote_addr zone=general:16m rate=20r/s; limit_req_zone $binary_remote_addr zone=costly:16m rate=2r/s; limit_req_status 429;Si nginx está detrás de algún proxy, configure primero
set_real_ip_fromyreal_ip_header. Un límite basado en la dirección de su frontal no frena a un atacante — frena a todo el mundo a la vez, la primera vez que se dispara. - Saque la dirección de origen de la vista pública
Haga que la IP desnuda sea inútil, y luego decida qué la antepone. El rechazo son dos líneas, y cierra para siempre la vía de escanear internet en busca del HTML de su sitio.
server { listen 80 default_server; listen 443 ssl default_server; ssl_reject_handshake on; return 444; }Después, audite las filtraciones en el orden en que suelen ocurrir: registros A históricos en archivos de DNS pasivo, nombres de host en logs de transparencia de certificados que en algún momento resolvieron al origen, y cabeceras de correo saliente. Si alguna de ellas todavía nombra la dirección, un frontal no le salvará — primero renumere, después anteponga el frontal.
- Avise al operador de red, con cifras
La mitigación volumétrica es automática y no necesita ticket, pero un reporte que incluya evidencia le permite a una persona confirmar lo que hizo la automatización y detectar los modos de fallo que esta no puede ver — un sistema de depuración reseteando sesiones legítimas, por ejemplo.
Envíe la dirección de destino, la hora de inicio en UTC, el protocolo y los puertos de destino, la tasa en ambos ejes tal como la midió, y si sus propios contadores muestran los paquetes llegando o desapareciendo aguas arriba. Cincuenta líneas de
tcpdump -ni eth0 -c 200valen más que un párrafo de descripción. “El sitio va lento” no es accionable; “185.x.x.x, 14:02 UTC, UDP al 443, ~1,2 Mpps, la interfaz muestra 40 Kpps entrando” sí lo es. - Ensaye la renumeración mientras nada va mal
Ponga hoy mismo los TTL de DNS en 300 segundos y déjelos ahí. Después, haga el simulacro una vez, de principio a fin, en una máquina que destruirá una hora después.
# deploy a second instance in another region, restore, verify by hostname override curl --resolve example.com:443:<new-ip> https://example.com/ -sIAnote cuánto le costó en minutos. Esa cifra es su verdadero plan contra el DDoS — más que cualquier regla de esta guía — porque es la que dice cuánto tiempo puede mantenerle fuera de línea un ataque dirigido. Los cargos se prorratean a diario contra su saldo, así que todo el ensayo cuesta centavos.
Dónde se puede detener de verdad cada ataque
| Capa | Detiene | No puede detener | Qué le cuesta | Quién la controla |
|---|---|---|---|---|
| Depuración aguas arriba | Inundaciones volumétricas — absorbidas por debajo de 10 Gbps, depuradas hasta 100, desviadas por BGP por encima | Todo lo que cabe dentro de volúmenes de tráfico normales: ataques de estado, capa 7 | Nada. Siempre activa, sin ticket, latencia ocasional durante un desvío | Nosotros, de forma automática |
| Filtro de borde del hipervisor | Todo lo dirigido a un puerto cerrado, antes de que llegue a su NIC virtual — sin CPU, sin entrada de estado | Ataques contra puertos que debe mantener abiertos | Nada más que las reglas que usted escriba; mantiene estado, deniega por defecto | Usted, por servidor |
| Firewall de la instancia (nftables) | Inundaciones SYN con synproxy, tasas de paquetes por origen, protocolos no deseados | Tráfico que ya llenó el enlace por encima de usted — nunca llega a este punto | CPU y una entrada de conntrack por cada paquete, incluidos los descartados | Usted, por completo |
| Ajuste del kernel (sysctl) | Agotamiento de la cola de aceptación y de conntrack — el clásico asesino de servidores pequeños | Cualquier cosa que sea una conexión válida y completada | Unos 80 MB de RAM con un tamaño de conntrack razonable. Dos archivos | Usted, por completo |
| Aplicación (caché + límite de tasa) | Inundaciones de capa 7, estampidas de solicitudes, endpoints costosos | Ataques a nivel de paquete — nunca llegan al servidor web | Páginas ligeramente desactualizadas, y 429 para los usuarios que juzgó mal | Usted, por completo |
| Frontal de proxy inverso | Ataques directos contra el origen — no hay dirección pública a la que apuntar | Ataques contra el propio frontal, y cualquier cosa después de que su IP de origen se haya filtrado | 5 dólares al mes y una máquina más que mantener parcheada | Usted, si lo gestiona usted mismo |
| CDN comercial | Ataques grandes de capa 3/4 y de capa 7, a gran escala, con una cola de soporte | Un origen que en algún momento fue público, o que responde en su IP desnuda | Terminación de TLS por parte de un tercero que sabe quién es usted y puede recibir un requerimiento legal | Ellos |
| Servicio onion de Tor | Todo ataque basado en IP — no hay dirección en el protocolo | La inundación de los puntos de introducción, por lo que el Tor moderno incorpora una defensa de prueba de trabajo | Latencia, y una audiencia dispuesta a usar Tor | Usted y la red |
Preguntas que vale la pena responder
¿Tengo que activar la protección DDoS en mi servidor?
No. La mitigación volumétrica se sitúa aguas arriba de los PoP y está siempre activa — no hay ningún producto que comprar ni ningún interruptor que accionar. Por debajo de 10 Gbps se absorbe sin efecto visible; entre 10 y 100 Gbps se depura en el proveedor de tránsito, donde puede notar un breve aumento de latencia; por encima de 100 Gbps el prefijo se anuncia por una ruta de depuración dedicada, la latencia sube de forma más perceptible y el servicio se mantiene accesible. Los umbrales están publicados en la documentación. Lo que no es automático es todo lo que está por encima de la capa 4: el agotamiento de la tabla de estados y las inundaciones de capa de aplicación parecen tráfico normal visto desde aguas arriba, y hay que gestionarlos en su máquina.
¿Me aplicarán null-routing a la IP si sufro un ataque?
Solo como último recurso, y solo para ataques sostenidos que amenacen al PoP en su conjunto y no solo a su servidor — y se lo comunicamos en cuestión de minutos si llega a ocurrir, en lugar de dejar que usted lo descubra por su cuenta. Cualquier proveedor que prometa que esto nunca puede pasar está describiendo marketing, no una red: a suficiente escala, proteger a miles de clientes significa, tarde o temprano, retirar una dirección. La protección realista consiste en convertirse en un blanco poco atractivo — mantenga sin publicar la dirección de origen, mantenga un plan de renumeración ensayado, y conozca su tiempo de restauración.
Mi sitio está caído pero la gráfica de ancho de banda parece normal. ¿Qué está pasando?
Casi con toda seguridad, agotamiento de estado — el caso clásico es una tabla nf_conntrack llena. Veinte mil paquetes pequeños por segundo desde direcciones falsificadas llenan una tabla por defecto en segundos usando apenas unos megabits, así que la gráfica no muestra nada y cada conexión nueva se descarta. Compruebe dmesg -T | grep conntrack en busca de “table full, dropping packet” y compare nf_conntrack_count con nf_conntrack_max. La otra posibilidad es la lectura contraria: el enlace que tiene por encima ya está lleno, así que su interfaz le está mostrando a los supervivientes y no al ataque.
¿Un plan más grande sobrevive a un ataque que uno pequeño no puede?
A veces, y no por la razón que la gente espera. Más vCPU y más RAM ayudan de verdad contra las inundaciones de capa 7 y el agotamiento de estado, porque esos ataques agotan CPU, memoria y espacio de tabla. Contra una inundación volumétrica, el plan es casi irrelevante — los paquetes se descartan aguas arriba de su puerto sea lo que sea lo que haya detrás, y un puerto de 2,5 Gbps no le salva de 40 Gbps. Arregle la caché y el dimensionado de conntrack antes de mejorar de plan; sale más barato y, casi siempre, resulta haber sido el problema real.
¿Puedo poner Cloudflare u otra CDN delante de un VPS sin KYC?
Técnicamente sí, y funciona bien. Entienda la contrapartida antes de asumirla: la CDN termina su TLS y ve su tráfico en claro, conoce su dirección de origen, mantiene una cuenta que le identifica por correo electrónico y a menudo por método de pago, y puede recibir un requerimiento legal en una jurisdicción que usted no eligió. Para un servidor comprado sin un nombre asociado, eso reintroduce exactamente al actor que el montaje pretendía evitar. Si su modelo de amenaza es el tiempo de inactividad y no la exposición, es una elección razonable — pero el origen no debe haber sido nunca público, o un registro DNS antiguo lo echa todo a perder. Si su modelo de amenaza incluye quién sabe dónde está usted, ejecute en su lugar su propio proxy inverso en una segunda instancia, y haga que el origen solo acepte tráfico desde él.
¿Basta fail2ban para detener un DDoS?
No, y no es que sea una herramienta débil, es que es la herramienta equivocada. Reacciona a escala humana después de analizar los logs, así que las solicitudes ya le han costado todo lo que iban a costarle; banea una dirección cada vez, lo cual no sirve de nada contra diez mil fuentes y convierte su firewall en un escaneo lineal si le deja intentarlo; y depende de unos logs que un atacante puede inundar. Úsela para aquello en lo que es excelente — la adivinación lenta de credenciales contra SSH y formularios de login — y use un conjunto dinámico de nftables con timeout para todo lo que ocurra a velocidad de inundación.
¿Debería bloquear países enteros o ASN?
Bloquear por país solo es defendible cuando su audiencia está genuinamente acotada y usted acepta perder a los usuarios que viajan y a los que tienen un enrutamiento raro. Contra una botnet moderna es casi inútil, porque está repartida entre conexiones residenciales de todas partes, incluido su propio país. Bloquear ASN de centros de datos es más preciso — la gente normal no navega desde un rango de hosting — y de paso atrapa el scraping y el credential stuffing. El instinto más acertado es filtrar por la forma del tráfico: un user agent compartido, una cabecera ausente, una ruta repetida. Esa regla sigue funcionando después de que el atacante cambie de direcciones, cosa que hará en cuestión de minutos.
¿Ejecutar un servicio onion de Tor me hace inmune?
Inmune a los ataques basados en IP, sí — no hay dirección en el protocolo a la que apuntar una inundación, lo cual es una postura de seguridad genuinamente distinta y no una simple mejora incremental. No es inmune en general: los servicios onion se pueden atacar en sus puntos de introducción, que es precisamente por lo que el Tor moderno incorpora una defensa de prueba de trabajo que encarece la inundación para el cliente. También cuesta latencia y le limita a una audiencia dispuesta a usar Tor. Mucha gente ejecuta ambos a la vez — un frontal en la clearnet para alcance, y una dirección onion que sigue funcionando cuando la de clearnet está bajo ataque.
Keep exploring
Endurecer un VPS nuevo en la primera hora
El requisito previo para esta página: cerrar los puertos que no ofrece elimina toda una clase de ataque antes de que ajuste nada.
Migrar un VPS sin tiempo de inactividad
El simulacro de renumeración completo, con la secuencia de DNS que decide cuánto tiempo le deja fuera de línea una dirección quemada.
VPS para servidores de juegos
La carga de trabajo que más atrae esto, y el ajuste específico de UDP que acompaña a un puerto de juego público.
Deploy your offshore server.
Elige una región. Elige un plan. Pega una clave. Paga. Los próximos 47 segundos corren de nuestra cuenta.