Monitorizar el tráfico de red de una web es una tarea habitual tanto en administración de sistemas como en laboratorios de ciberseguridad. Saber cuántos bytes entran y salen, qué protocolos se usan y desde qué IPs se conectan los clientes es información valiosa para detectar anomalías, dimensionar infraestructura o depurar problemas de conectividad.
En este artículo veremos cómo hacerlo con Python y Scapy, una de las bibliotecas más didácticas para manipular paquetes. Pero también seremos honestos sobre sus limitaciones: Scapy es excelente para aprender y para scripts puntuales, pero no es la herramienta adecuada para monitorización continua en producción. Al final del artículo encontrarás alternativas más robustas.
Si quieres profundizar en ciberseguridad desde una perspectiva más amplia, tienes nuestra guía completa de ciberseguridad.
1. ¿Dónde se ejecuta este script? La pregunta que hay que responder primero
Antes de escribir una sola línea de código, hay que tener claro un concepto que suele generar confusión: Scapy captura paquetes de la interfaz de red de la máquina donde se ejecuta. No es un monitor remoto. No «ve» internet de forma mágica. No existe una opción para poner una URL y que capture el tráfico de esa web desde fuera.
Por tanto, el script debe ejecutarse en:
- Tu ordenador personal (Windows, Linux o macOS), si quieres ver el tráfico que genera tu propia navegación hacia una web.
- Tu servidor, si quieres monitorizar el tráfico que entra y sale de ese servidor.
¿Se puede ejecutar desde Visual Studio Code?
Sí, pero con matices importantes:
- VS Code es solo el editor. El script se ejecuta en la terminal integrada o en una terminal externa, sobre tu sistema operativo real.
- Necesitas permisos de administrador. Scapy requiere acceso crudo a la red. En Linux necesitas
sudo. En Windows, ejecutar la terminal como Administrador y tener Npcap instalado. Sin esto,sniff()fallará. - El entorno virtual y los permisos no se llevan bien. Si usas un
venv(recomendado), al ejecutar consudoel intérprete de Python del venv no se carga automáticamente. La solución es:sudo env "PATH=$PATH" python tu_script.py. - Si usas WSL, puedes ejecutar VS Code conectado a WSL y lanzar el script con
sudodesde la terminal de WSL.
¿Captura todo el tráfico o solo el de una URL?
Depende del filtro que uses:
- Si usas
sniff(filter="tcp port 80"): capturas todo el tráfico HTTP de tu máquina, no solo el de una web concreta. Verás peticiones a cualquier sitio. - Si usas
sniff(filter="host 93.184.216.34"): capturas solo el tráfico hacia/desde esa IP. Pero ojo: si la web usa CDN, esa IP puede no ser la única, y el tráfico a otros recursos de la misma web puede ir a otras IPs. - El script de este artículo resuelve la URL a una IP con
socket.gethostbyname()y luego filtra por esa IP. Eso reduce el tráfico, pero no lo limita perfectamente a «esa web», porque una página carga recursos de múltiples dominios.
En resumen: el script no «monitoriza una URL» de forma remota. Monitoriza el tráfico de tu máquina que coincide con la IP de esa URL. Si quieres monitorizar el tráfico de un servidor, ejecuta el script en el servidor.
2. Requisitos previos
Antes de ejecutar los ejemplos necesitas:
- Python 3.7 o superior. Scapy 2.5+ requiere Python 3.7+. Python 2 está obsoleto desde 2020 y no recibe parches de seguridad.
- Scapy instalado:
pip install scapy - Permisos de captura. En Linux necesitas
sudoo la capabilityCAP_NET_RAW. En Windows, Npcap y terminal como Administrador. - Un entorno controlado. Monitoriza solo tu propio servidor o tu propia máquina. Interceptar tráfico ajeno sin autorización es ilegal en la mayoría de jurisdicciones.
3. El error conceptual más común: ¿qué es «entrante» y qué es «saliente»?
Un paquete con puerto destino 80 no siempre es «entrante». Depende de dónde estés capturando:
- Si capturas en el cliente (tu navegador): los paquetes con
dport=80/443son salientes (tú envías la petición), y los que tienensport=80/443son entrantes (el servidor responde). - Si capturas en el servidor: es al revés. Los paquetes con
dport=80/443son entrantes (el cliente te envía la petición), y los que tienensport=80/443son salientes (tu respuesta).
El código original de esta entrada confundía ambos casos. En los ejemplos siguientes, asumiremos que capturas en el cliente (tu máquina), que es el escenario más habitual para quien quiere entender el tráfico que genera una web.
4. Captura básica con Scapy (solo HTTP, puerto 80)
Este primer ejemplo es deliberadamente simple para que veas la mecánica. Captura tráfico HTTP clásico y distingue dirección desde el punto de vista del cliente.
from scapy.all import sniff, TCP, IP
def analizar_paquete(pkt):
if pkt.haslayer(TCP) and pkt.haslayer(IP):
tcp = pkt[TCP]
ip = pkt[IP]
# Desde el punto de vista del CLIENTE (tu máquina)
if tcp.dport == 80:
print(f"[SALIENTE] {ip.src} -> {ip.dst}:{tcp.dport} flags={tcp.flags}")
elif tcp.sport == 80:
print(f"[ENTRANTE] {ip.src}:{tcp.sport} -> {ip.dst} flags={tcp.flags}")
# store=0 evita acumular paquetes en memoria (importante en capturas largas)
sniff(filter="tcp port 80", prn=analizar_paquete, store=0)Qué hace bien este código:
- Usa
store=0para no consumir RAM innecesariamente. - Distingue dirección según el puerto, asumiendo captura en el cliente.
- El filtro BPF
tcp port 80es correcto y eficiente (se ejecuta en el kernel).
Limitación: solo captura HTTP. En 2026, casi todo es HTTPS (puerto 443). El contenido estará cifrado, pero sí podrás ver los metadatos: IPs, puertos, tamaño de paquetes y frecuencia. Eso sigue siendo útil para monitorización de volumen.
5. Captura para una web concreta (HTTP y HTTPS)
Si quieres filtrar por la IP de una web específica, puedes resolver el dominio y usar un filtro BPF más preciso.
import socket
from scapy.all import sniff, TCP, IP
def monitorizar_web(url):
try:
ip = socket.gethostbyname(url)
print(f"Resolviendo {url} -> {ip}")
print("Capturando tráfico hacia/desde esa IP (Ctrl+C para detener)...\n")
except socket.gaierror:
print(f"No se pudo resolver: {url}")
return
def callback(pkt):
if pkt.haslayer(TCP) and pkt.haslayer(IP):
tcp = pkt[TCP]
if tcp.dport in (80, 443):
print(f"[SALIENTE] -> {ip}:{tcp.dport} len={len(pkt)} bytes")
elif tcp.sport in (80, 443):
print(f"[ENTRANTE] <- {ip}:{tcp.sport} len={len(pkt)} bytes")
# Filtro BPF con paréntesis para evitar ambigüedad de precedencia
sniff(filter=f"host {ip} and (tcp port 80 or tcp port 443)",
prn=callback, store=0)
# Ejecutar en TU máquina (Linux: sudo env "PATH=$PATH" python script.py)
monitorizar_web("ejemplo.com")Nota sobre el filtro BPF: la expresión host X and (tcp port 80 or tcp port 443) usa paréntesis para evitar problemas de precedencia. La sintaxis BPF es la misma que usa tcpdump.
Importante sobre CDN: si la web usa una CDN (Cloudflare, Akamai, etc.), gethostbyname devuelve una sola IP de las muchas posibles. El script capturará solo el tráfico hacia esa IP concreta. Para una captura más completa, podrías resolver todas las IPs del dominio con socket.getaddrinfo() y construir un filtro con varias IPs, o simplemente capturar todo el tráfico y filtrar por dominio en el callback (menos eficiente).
6. ¿Y HTTP/3? El tráfico web ya no es solo TCP
HTTP/3 usa QUIC sobre UDP (normalmente puerto 443). Si solo filtras TCP, te pierdes una parte creciente del tráfico web moderno. Sin embargo, QUIC está cifrado por diseño, así que no podrás ver nada más allá de los metadatos (IPs, puertos, tamaño).
Si quieres incluir HTTP/3 en tu monitorización:
sniff(filter=f"host {ip} and (tcp port 80 or tcp port 443 or udp port 443)",
prn=callback, store=0)Pero ten en cuenta: el callback anterior solo procesa TCP. Para UDP necesitarías una rama adicional. Y aunque la proceses, el contenido de QUIC está cifrado y Scapy no puede descifrarlo sin las claves TLS.
Conclusión práctica: para monitorización de tráfico web real, Scapy te da volumen y metadatos, no contenido. Si necesitas contenido (URLs, payloads), necesitas otra aproximación (logs del servidor, proxies, o instrumentación de la aplicación).
7. Limitaciones reales de Scapy para monitorización
Scapy es una biblioteca excelente para aprender, prototipar y hacer análisis puntuales. Pero para monitorización continua en producción tiene problemas:
| Limitación | Implicación |
|---|---|
| Rendimiento | Scapy procesa paquetes en Python puro. En redes con mucho tráfico, pierde paquetes o consume CPU excesiva. |
| Sin persistencia | El código de ejemplo imprime en consola. Para métricas necesitas escribir a un fichero, base de datos o sistema de observabilidad. |
| Cifrado | HTTPS y HTTP/3 cifran el contenido. Solo ves metadatos. |
| Complejidad | Reimplementar contadores, agregaciones y alertas que otras herramientas ya dan hechas no tiene sentido. |
Alternativas profesionales:
tcpdump+ análisis posterior: captura a fichero PCAP con filtros BPF eficientes (en C, no en Python) y analiza después.iftop,nload,vnstat: monitorización de ancho de banda en tiempo real desde la terminal, sin escribir código.- Prometheus + Grafana + node_exporter: el estándar de facto para observabilidad de servidores.
node_exporterexpone métricas de red (node_network_receive_bytes_total,node_network_transmit_bytes_total) que puedes graficar y alertar. - Netdata: monitorización todo-en-uno con dashboards de red listos para usar.
- Wireshark: para análisis forense y depuración profunda de paquetes.
Si tu objetivo es monitorizar un servidor Linux, revisa también nuestra guía de optimización de rendimiento de servidores Linux, donde tratamos métricas de red en contexto.
8. Consideraciones legales y éticas
Monitorizar tráfico de red es legal en tu propia infraestructura o en entornos de laboratorio controlados. No es legal interceptar tráfico de terceros sin autorización expresa. Los ejemplos de este artículo están pensados para:
- Monitorizar tu propio servidor web.
- Analizar el tráfico que genera tu propia máquina.
- Laboratorios de ciberseguridad con máquinas virtuales aisladas.
Si necesitas un entorno de pruebas, cualquier hipervisor moderno te sirve. Tenemos guías específicas de Proxmox y de VirtualBox si quieres montar tu lab.
Conclusión
Scapy te permite entender cómo funciona la captura de paquetes y escribir scripts de monitorización en pocas líneas. Es una herramienta valiosa para aprender y para tareas puntuales. Pero si tu objetivo es monitorizar una web en producción, invierte el tiempo en tcpdump para capturas puntuales y en un stack de observabilidad (Prometheus + Grafana o Netdata) para monitorización continua.
Y recuerda: el script se ejecuta en la máquina que captura, no «en la URL». Si quieres ver el tráfico de tu servidor, ejecútalo en el servidor. Si quieres ver el tráfico que genera tu navegador, ejecútalo en tu ordenador. Y en 2026, el tráfico web es mayoritariamente HTTPS y cada vez más HTTP/3: monitorizar solo el puerto 80 es mirar una parte cada vez más pequeña de la realidad.
Caso practico:
1. Conéctate al servidor y crea el directorio
# Conéctate por SSH a tu servidor
ssh usuario@tu-servidor
# Crea un directorio para el proyecto
mkdir -p ~/monitor-trafico
cd ~/monitor-trafico
2. Crea y activa el entorno virtual (venv)
# Crear el entorno virtual
python3 -m venv venv
# Activarlo
source venv/bin/activateVerás que el prompt cambia y aparece (venv).
3. Instala Scapy
pip install --upgrade pip
pip install scapy
4. Crea el archivo Python
nano monitor.pyPega este código (versión mejorada del artículo, pensada para servidor):
#!/usr/bin/env python3
"""
Monitor de tráfico entrante/saliente en un servidor
Ejecutar con: sudo env "PATH=$PATH" python monitor.py
"""
from scapy.all import sniff, TCP, IP, UDP
import socket
from collections import defaultdict
from datetime import datetime
# Contadores simples
stats = defaultdict(lambda: {"paquetes": 0, "bytes": 0})
def analizar_paquete(pkt):
if not (pkt.haslayer(IP) and (pkt.haslayer(TCP) or pkt.haslayer(UDP))):
return
ip = pkt[IP]
proto = "TCP" if pkt.haslayer(TCP) else "UDP"
capa = pkt[TCP] if proto == "TCP" else pkt[UDP]
# En el SERVIDOR:
# - dport 80/443 → ENTRANTE (cliente nos habla)
# - sport 80/443 → SALIENTE (nosotros respondemos)
if capa.dport in (80, 443):
direccion = "ENTRANTE"
clave = f"{direccion} {ip.src} → {ip.dst}:{capa.dport}"
elif capa.sport in (80, 443):
direccion = "SALIENTE"
clave = f"{direccion} {ip.src}:{capa.sport} → {ip.dst}"
else:
return # Ignoramos otros puertos
tamaño = len(pkt)
stats[clave]["paquetes"] += 1
stats[clave]["bytes"] += tamaño
# Imprimir en tiempo real (puedes comentar esta línea si quieres menos ruido)
print(f"[{datetime.now().strftime('%H:%M:%S')}] [{direccion}] {proto} "
f"{ip.src}:{capa.sport} → {ip.dst}:{capa.dport} {tamaño} bytes flags={getattr(capa, 'flags', '-')}")
def mostrar_resumen():
print("\n" + "="*70)
print("RESUMEN DE TRÁFICO")
print("="*70)
for clave, datos in sorted(stats.items(), key=lambda x: x[1]["bytes"], reverse=True):
print(f"{clave}")
print(f" Paquetes: {datos['paquetes']:,} | Bytes: {datos['bytes']:,}")
print("="*70)
if __name__ == "__main__":
print("Iniciando captura de tráfico en el servidor...")
print("Filtro: host local + puertos 80 y 443 (HTTP/HTTPS)")
print("Pulsa Ctrl+C para detener y ver el resumen\n")
try:
# Captura todo el tráfico de los puertos web del servidor
# store=0 → no guarda los paquetes en memoria (importante)
sniff(
filter="tcp port 80 or tcp port 443 or udp port 443",
prn=analizar_paquete,
store=0
)
except KeyboardInterrupt:
mostrar_resumen()
print("\nCaptura detenida.")Guarda el archivo (Ctrl+O → Enter → Ctrl+X en nano).

5. Ejecutar el script (importante: con permisos)
Scapy necesita privilegios de red. No ejecutes solo python monitor.py.
Hazlo así:
# Con el venv activado:
sudo env "PATH=$PATH" python monitor.pyLa parte env «PATH=$PATH» es clave para que use el Python del entorno virtual y no el del sistema.

Resumen rápido de comandos
mkdir -p ~/monitor-trafico && cd ~/monitor-trafico
python3 -m venv venv
source venv/bin/activate
pip install scapy
nano monitor.py # pegas el código
sudo env "PATH=$PATH" python monitor.py
Notas importantes:
- El script está pensado para ejecutarse en el servidor (punto de vista del servidor: dport = entrante).
- Solo verás metadatos (IPs, puertos, tamaño, flags). El contenido HTTPS está cifrado.
- Para producción real se recomienda herramientas más robustas (vnstat, nload, Prometheus + node_exporter, Netdata, etc.), porque Scapy no es ideal para monitorización continua.






