iptables es el sistema de filtrado de paquetes del kernel Linux — potente pero con una sintaxis compleja. UFW (Uncomplicated Firewall) es una interfaz simplificada sobre iptables diseñada para ser usable por humanos. En Ubuntu, UFW es la herramienta recomendada para gestión diaria; iptables queda para casos avanzados.
# UFW actúa sobre iptables por debajo # Lo que escribís en UFW se traduce a reglas iptables # Ver las reglas iptables que UFW genera iptables -L -n --line-numbers iptables -L INPUT -n -v
UFW y iptables no son excluyentes — UFW gestiona las reglas principales y podés agregar reglas iptables manuales para casos que UFW no cubre.
UFW evalúa las reglas en orden, de arriba hacia abajo. La primera regla que coincide con el paquete gana. Al final se aplica la política por defecto.
Paquete entrante
↓
Regla 1: ¿coincide? → ALLOW / DENY / REJECT / LIMIT
↓ (no coincide)
Regla 2: ¿coincide? → ...
↓ (no coincide)
Política por defecto (DEFAULT) → ALLOW / DENY
La política más segura para un servidor público:
# Denegar todo el tráfico entrante por defecto ufw default deny incoming # Permitir todo el tráfico saliente ufw default allow outgoing # Luego agregar reglas específicas de lo que SÍ se permite
Nunca activar UFW sin haber permitido el puerto SSH primero. De lo contrario te quedás sin acceso al servidor.
| Puerto | Protocolo | Servicio |
|---|---|---|
| 22 | TCP | SSH — acceso remoto al servidor |
| 80 | TCP | HTTP — sitios web sin cifrar |
| 443 | TCP | HTTPS — sitios web cifrados |
| 3306 | TCP | MySQL / MariaDB — base de datos |
| 5432 | TCP | PostgreSQL — base de datos |
| 6379 | TCP | Redis — caché en memoria |
| 25 / 587 / 465 | TCP | SMTP — envío de emails |
| 143 / 993 | TCP | IMAP — recepción de emails |
| 53 | TCP/UDP | DNS — resolución de nombres |
| 21 | TCP | FTP — transferencia de archivos (evitar) |
| 8080 / 8443 | TCP | HTTP/HTTPS alt — apps y paneles |
| 60000-61000 | UDP | Mosh — SSH alternativo móvil |
Regla de oro: mantener cerrado todo lo que no se use. MariaDB, Redis y PostgreSQL nunca deben estar abiertos a internet — accedelos vía túnel SSH o solo desde localhost.
El orden importa. Seguí esta secuencia para no quedar afuera del servidor.
# PASO 1: Verificar estado actual ufw status verbose # PASO 2: Establecer políticas por defecto ufw default deny incoming ufw default allow outgoing # PASO 3: Permitir SSH ANTES de activar (crítico) ufw allow 22/tcp # Si usás puerto personalizado: ufw allow 2222/tcp # PASO 4: Agregar los demás servicios necesarios ufw allow 80/tcp ufw allow 443/tcp # PASO 5: Activar UFW ufw enable # PASO 6: Verificar reglas activas ufw status numbered
Si el proveedor (Donweb) tiene un firewall propio en el panel de control, coordiná las reglas — UFW actúa a nivel del OS, el firewall del panel actúa antes de llegar al servidor.
# Estado resumido ufw status # Estado completo con políticas por defecto ufw status verbose # Ver reglas numeradas (para borrar por número) ufw status numbered # Habilitar / deshabilitar UFW ufw enable ufw disable # Recargar reglas ufw reload # Resetear todo (borra TODAS las reglas) ufw reset
ufw reset elimina todas las reglas y deshabilita UFW. El servidor queda sin firewall hasta que lo reconfigures.
# Por número de puerto ufw allow 80 # TCP y UDP ufw allow 80/tcp # solo TCP ufw allow 443/tcp # Por nombre de servicio (de /etc/services) ufw allow ssh ufw allow http ufw allow https # Rango de puertos ufw allow 8000:8100/tcp # Desde una IP específica ufw allow from 190.55.100.200 ufw allow from 190.55.100.200 to any port 22 # Desde una red (subred) ufw allow from 192.168.1.0/24 ufw allow from 192.168.1.0/24 to any port 3306 # Hacia una interfaz específica ufw allow in on eth0 to any port 80
deny descarta el paquete silenciosamente. reject descarta el paquete y notifica al emisor. Para seguridad, deny es mejor — no revela que el puerto existe.
# Denegar un puerto ufw deny 3306 ufw deny 6379/tcp # Denegar desde una IP (bloquear atacante) ufw deny from 1.2.3.4 ufw deny from 1.2.3.4 to any # Denegar una red completa ufw deny from 10.0.0.0/8 # Reject (manda RST/ICMP al emisor) ufw reject 23/tcp # bloquear Telnet con aviso
# Ver reglas numeradas ufw status numbered # Output ejemplo: # To Action From # [ 1] 22/tcp ALLOW IN Anywhere # [ 2] 80/tcp ALLOW IN Anywhere # [ 3] 443/tcp ALLOW IN Anywhere # Borrar por número ufw delete 3 # Borrar por regla exacta ufw delete allow 80/tcp ufw delete allow from 1.2.3.4 # Borrar regla IPv6 también (si existe) ufw delete allow 80/tcp # UFW borra ambas versiones (v4 y v6) automáticamente
limit bloquea automáticamente IPs que hacen más de 6 intentos de conexión en 30 segundos. Ideal para SSH sin Fail2ban.
# Limitar intentos de conexión al puerto SSH ufw limit ssh ufw limit 22/tcp ufw limit 2222/tcp # Ver la regla generada ufw status verbose # → 2222/tcp LIMIT IN Anywhere
Para SSH es recomendable usar limit en vez de allow aunque tengas Fail2ban — son capas de protección complementarias.
UFW evalúa reglas en orden. Para que una regla específica tenga prioridad sobre una general, hay que insertarla antes.
# Ver reglas numeradas actuales ufw status numbered # Insertar regla en posición específica # Ejemplo: bloquear una IP antes de la regla general que permite todo ufw insert 1 deny from 5.6.7.8 # Resultado: la regla de deny queda primera # → [1] DENY 5.6.7.8 # → [2] ALLOW 22/tcp # → [3] ALLOW 80/tcp
Las reglas de deny de IPs específicas siempre deben ir antes que las reglas de allow generales, o serán ignoradas.
# Verificar que IPv6 está habilitado en UFW grep IPV6 /etc/default/ufw # → IPV6=yes (debe estar en yes) # Si está en no, editarlo nano /etc/default/ufw # IPV6=yes ufw disable && ufw enable # Las reglas con IPv6 activo se aplican a v4 y v6: # [ 1] 22/tcp ALLOW IN Anywhere # [ 2] 22/tcp (v6) ALLOW IN Anywhere (v6)
Con IPv6 habilitado, cada regla que agregás aplica a ambas versiones automáticamente — no hay que duplicar reglas.
Para casos que UFW no cubre directamente, se pueden agregar reglas iptables raw en /etc/ufw/before.rules. Se cargan antes que todas las reglas de UFW.
# /etc/ufw/before.rules # Agregar ANTES de la línea: *filter # Ejemplo: permitir ICMP (ping) — útil para diagnóstico *filter -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT # Ejemplo: nat para reenviar puertos (port forwarding) # Agregar al inicio del archivo, antes de *filter: *nat :PREROUTING ACCEPT [0:0] -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 COMMIT
# Recargar después de editar before.rules ufw reload
Las aplicaciones pueden registrar perfiles UFW que definen sus puertos. Así en vez de recordar números de puerto usás nombres.
# Ver perfiles disponibles ufw app list # → Available applications: # Nginx Full # Nginx HTTP # Nginx HTTPS # OpenSSH # Ver detalles de un perfil ufw app info "Nginx Full" # → Profile: Nginx Full # Title: Web Server (Nginx, HTTP + HTTPS) # Description: ... # Ports: 80,443/tcp # Usar perfil en regla ufw allow "Nginx Full" ufw allow "Nginx HTTP" ufw allow "Nginx HTTPS" ufw allow "OpenSSH" ufw delete allow "Nginx HTTP" # una vez que tenés SSL
Una vez configurado SSL, reemplazá Nginx Full por Nginx HTTPS y bloqueá el 80 (o dejá solo el redirect que maneja Nginx internamente).
Cualquier app puede tener su perfil. Crear el archivo en /etc/ufw/applications.d/
# /etc/ufw/applications.d/mi-app [MiApp] title=Mi Aplicación Web description=API y panel de administración ports=3000,3001/tcp [MiApp-Admin] title=Mi App — Panel Admin description=Solo panel admin ports=9000/tcp
# Actualizar la lista de perfiles ufw app update MiApp ufw app list # Usar el nuevo perfil ufw allow "MiApp"
iptables organiza las reglas en tablas y cadenas. Para un VPS web el foco está en la tabla filter.
Tablas principales:
filter → filtrado de paquetes (INPUT, OUTPUT, FORWARD)
nat → traducción de direcciones (PREROUTING, POSTROUTING)
mangle → modificar paquetes
Cadenas de filter:
INPUT → paquetes que llegan al servidor
OUTPUT → paquetes que salen del servidor
FORWARD → paquetes que pasan por el servidor (router)
Acciones (targets):
ACCEPT → permitir el paquete
DROP → descartar silenciosamente
REJECT → descartar y notificar
LOG → registrar en syslog y continuar
RETURN → volver a la cadena anterior
# Ver todas las reglas (tabla filter) iptables -L -n -v # Ver con números de línea iptables -L INPUT -n -v --line-numbers # Ver tabla NAT iptables -t nat -L -n -v # Formato más compacto (igual que las reglas se escriben) iptables -S iptables -S INPUT # IPv6 ip6tables -L -n -v
# Sintaxis básica # iptables -A CADENA -p PROTOCOLO --dport PUERTO -j ACCIÓN # Permitir SSH iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Permitir HTTP y HTTPS iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # Permitir conexiones establecidas (tráfico de respuesta) iptables -A INPUT -m state \ --state ESTABLISHED,RELATED -j ACCEPT # Permitir loopback (localhost) iptables -A INPUT -i lo -j ACCEPT # Bloquear IP específica iptables -A INPUT -s 1.2.3.4 -j DROP # Bloquear rango de IPs iptables -A INPUT -s 1.2.3.0/24 -j DROP # Eliminar regla por número de línea iptables -D INPUT 3 # Insertar regla en posición específica iptables -I INPUT 1 -s 1.2.3.4 -j DROP # Política por defecto (DROP todo lo que no coincida) iptables -P INPUT DROP
Las reglas iptables se pierden al reiniciar. Hay que persistirlas.
# Instalar el paquete de persistencia apt install iptables-persistent # Guardar reglas actuales netfilter-persistent save # Guarda en: # /etc/iptables/rules.v4 (IPv4) # /etc/iptables/rules.v6 (IPv6) # Recargar reglas guardadas netfilter-persistent reload # Guardar manualmente iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 # Restaurar manualmente iptables-restore < /etc/iptables/rules.v4
Si usás UFW, él se encarga de persistir sus reglas. Solo necesitás iptables-persistent para reglas manuales que agregues fuera de UFW.
# Activar logging (niveles: off, low, medium, high, full) ufw logging on # nivel low por defecto ufw logging medium # recomendado para producción ufw logging high # muy verboso, para debugging ufw logging off # deshabilitar # Los logs van a syslog y al archivo: tail -f /var/log/ufw.log # Ver logs en tiempo real con journald journalctl -f | grep UFW # Filtrar solo los bloqueados grep "UFW BLOCK" /var/log/ufw.log | tail -20 # Filtrar solo los permitidos grep "UFW ALLOW" /var/log/ufw.log | tail -20
Un registro típico en /var/log/ufw.log:
May 28 14:23:11 vps kernel: [UFW BLOCK] IN=eth0 OUT= MAC=... SRC=185.234.218.44 DST=192.168.1.10 PROTO=TCP SPT=54321 DPT=3306 ... Campos importantes: UFW BLOCK / UFW ALLOW → acción tomada SRC=185.234.218.44 → IP origen (atacante) DST=192.168.1.10 → IP destino (tu servidor) DPT=3306 → puerto destino atacado PROTO=TCP → protocolo
# IPs que más intentan conectar a puertos bloqueados grep "UFW BLOCK" /var/log/ufw.log \ | awk '{print $13}' \ | cut -d= -f2 \ | sort | uniq -c | sort -rn | head -15 # Puertos más atacados grep "UFW BLOCK" /var/log/ufw.log \ | grep -oP 'DPT=\K[0-9]+' \ | sort | uniq -c | sort -rn | head -10 # Bloquear manualmente una IP muy activa ufw insert 1 deny from 185.234.218.44
# Ver todas las conexiones activas ss -tulnp ss -tnp state established # Ver conexiones agrupadas por estado ss -s # Ver quién está conectado al puerto 80/443 ss -tnp sport = :80 ss -tnp sport = :443 # Contar conexiones por IP (detectar DDoS básico) ss -tn state established | awk '{print $5}' \ | cut -d: -f1 | sort | uniq -c | sort -rn | head -10 # Alternativa con netstat netstat -ntu | awk '{print $5}' \ | cut -d: -f1 | sort | uniq -c | sort -rn
Configuración lista para un VPS que sirve sitios web con Nginx, SSH en puerto personalizado, y bases de datos solo en localhost.
# 1. Políticas por defecto ufw default deny incoming ufw default allow outgoing # 2. SSH con rate limiting (puerto personalizado) ufw limit 2222/tcp # 3. Web ufw allow 80/tcp ufw allow 443/tcp # 4. Activar ufw enable ufw status numbered # Resultado esperado: # To Action From # [ 1] 2222/tcp LIMIT IN Anywhere # [ 2] 80/tcp ALLOW IN Anywhere # [ 3] 443/tcp ALLOW IN Anywhere
MariaDB, Redis y cualquier base de datos se dejan SIN regla en UFW — solo escuchan en 127.0.0.1 en su configuración propia. Acceso solo vía túnel SSH.
Si necesitás conectarte a la base de datos directamente sin túnel SSH (no recomendado, pero a veces necesario), restringilo a tu IP fija.
# Permitir MariaDB solo desde tu IP fija ufw allow from TU_IP_FIJA to any port 3306 # Denegar cualquier otra conexión al 3306 ufw deny 3306 # También asegurate de que MariaDB escucha en 0.0.0.0 # /etc/mysql/mariadb.conf.d/50-server.cnf # bind-address = 0.0.0.0 ← solo si necesitás acceso externo # Verificar ufw status numbered
La opción más segura sigue siendo el túnel SSH (ssh -L 3307:127.0.0.1:3306 donweb). Abrir el 3306 al exterior, aunque sea a una sola IP, aumenta la superficie de ataque.
Si los logs muestran ataques constantes desde un rango de IPs o región específica.
# Bloquear un rango de IPs conocido ufw insert 1 deny from 185.234.0.0/16 # Bloquear múltiples rangos ufw insert 1 deny from 45.155.204.0/24 ufw insert 1 deny from 193.32.162.0/24 # Para bloqueo por país, usar ipset (más eficiente) apt install ipset # Crear set de IPs ipset create blocklist hash:net ipset add blocklist 185.234.0.0/16 ipset add blocklist 1.2.0.0/16 # Bloquear el set con iptables iptables -I INPUT 1 -m set --match-set blocklist src -j DROP # Ver el set ipset list blocklist
# Limitar nuevas conexiones por IP (en before.rules o iptables) # Máximo 25 nuevas conexiones por IP en 60 segundos iptables -A INPUT -p tcp --dport 80 \ -m state --state NEW \ -m recent --set --name HTTP_LIMIT iptables -A INPUT -p tcp --dport 80 \ -m state --state NEW \ -m recent --update --seconds 60 --hitcount 25 \ --name HTTP_LIMIT -j DROP # Bloquear paquetes inválidos iptables -A INPUT -m state --state INVALID -j DROP # Proteger contra SYN flood iptables -A INPUT -p tcp --syn \ -m limit --limit 1/s --limit-burst 3 -j ACCEPT # Bloquear pings excesivos iptables -A INPUT -p icmp --icmp-type echo-request \ -m limit --limit 1/s -j ACCEPT iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
Para DDoS serio, estas reglas no son suficientes — necesitás un servicio como Cloudflare delante del servidor. Estas reglas protegen contra ataques pequeños y escaneos.
Si por error bloqueaste tu propia IP o el puerto SSH, opciones de recuperación:
# OPCIÓN 1: Consola VNC del panel de Donweb # Accedé al servidor por la consola web del panel # (no usa SSH, no está afectada por UFW) # Luego desde ahí: ufw disable ufw delete deny from TU_IP ufw allow 22/tcp ufw enable # OPCIÓN 2: Si tenés otra IP (ej: hotspot del celu) # Conectate desde esa IP diferente y corregí las reglas # OPCIÓN 3: Si el VPS tiene otra interfaz de red # ssh -i ~/.ssh/clave usuario@IP_ALTERNATIVA # Para identificar qué regla te bloqueó ufw status numbered iptables -L INPUT -n --line-numbers
La consola VNC del panel de Donweb es tu red de seguridad para situaciones de lockout — siempre sabé cómo acceder a ella antes de hacer cambios de firewall.