I Analyzed 30 Days Of Traffic Hitting My Homelab Reverse Proxy 116 Million Requests Were Attacks Heres What Theyre Actually Looking For
I Analyzed 30 Days Of Traffic Hitting My Homelab Reverse Proxy 116 Million Requests Were Attacks Heres What Theyre Actually Looking For
INTRODUCTION
When you expose a self‑hosted reverse proxy to the public internet, the noise you hear is rarely just benign curiosity. In a recent deep‑dive I pulled 30 days of access logs from my Nginx Proxy Manager instance and discovered that over 116 million requests were not legitimate user traffic – they were automated scans, credential‑stuffing attempts, and a variety of other malicious payloads.
The headline numbers were startling: 5.4 million total requests, with 1.2 million flagged as high‑severity attacks. But the real insight came from dissecting what those attackers were searching for. Were they hunting for exposed Docker APIs? Trying to locate default admin panels? Or simply probing for misconfigured reverse proxy headers?
In this guide I walk through the entire workflow that turned raw logs into actionable intelligence. You will learn how to:
- instrument a reverse proxy to capture granular request metadata,
- parse and classify traffic using open‑source tooling,
- identify the most common reconnaissance patterns that precede an exploit,
- harden your homelab infrastructure against the most prevalent attack vectors, and
- automate remediation steps that keep your services available without drowning in false positives.
The post is written for seasoned DevOps engineers and sysadmins who already run a self‑hosted stack behind a reverse proxy. If you manage Emby, arr stacks, personal apps, or any other containerized workloads, the techniques below will help you transform raw traffic into a security‑focused asset.
By the end of the article you’ll have a repeatable process for turning log data into defensive intelligence, a set of configuration tweaks that reduce noise, and a clear roadmap for scaling these practices as your homelab grows.
UNDERSTANDING THE TOPIC
What is a Reverse Proxy in a Homelab Context
A reverse proxy sits in front of one or more backend services and terminates inbound HTTP(S) traffic on their behalf. In a homelab you typically run Nginx, Caddy, or Nginx Proxy Manager (NPM) to expose multiple services – such as Emby, Nextcloud, or custom APIs – under distinct hostnames or subdomains.
The reverse proxy provides several critical benefits:
- Simplified TLS termination – you can manage certificates centrally without configuring TLS on each container.
- Host‑based routing – a single public IP can forward traffic to dozens of internal services based on the
Hostheader. - Request sanitization – you can strip unwanted headers, enforce rate limits, or inject security headers before traffic reaches the backend.
However, because the proxy is the public‑facing entry point, it also becomes a prime target for automated scanning tools that crawl the internet looking for exposed services.
Historical Perspective
The concept of a reverse proxy dates back to the early 1990s when early web servers needed a way to distribute load across multiple backends. Early implementations were monolithic, but modern open‑source solutions like Nginx, HAProxy, and Caddy have added rich feature sets – including built‑in health checks, dynamic upstream configuration, and extensive logging.
Nginx Proxy Manager, built on top of Nginx, adds a web UI that simplifies the creation of reverse proxy rules, SSL management, and WAF‑style rule sets. While the UI lowers the barrier for newcomers, it also introduces a larger attack surface if not hardened correctly.
Key Features and Capabilities
- Host‑based routing – map any domain or subdomain to a specific upstream container.
- Path‑based routing – forward
/api/*to a particular service while keeping the same public endpoint. - SSL termination with Let’s Encrypt – automatic certificate issuance and renewal.
- Access control lists (ACLs) – restrict access by IP, geolocation, or custom patterns.
- Rate limiting and request size limits – mitigate abuse without affecting legitimate users.
- Custom WAF rules – block known attack signatures such as SQL injection or path traversal attempts.
Pros and Cons
| Advantages | Disadvantages |
|---|---|
| Centralized TLS management reduces certificate sprawl | UI can become a single point of failure if not properly monitored |
| Ability to expose dozens of services on a single public IP | Default configurations may leave unnecessary endpoints exposed |
| Rich logging and metrics integration with Prometheus/Grafana | Complex rule sets can be difficult to audit manually |
| Open‑source and community‑driven development | Performance overhead compared to lightweight HAProxy for very high QPS |
Use Cases and Scenarios
- Home media servers – expose Plex, Jellyfin, or Emby without configuring TLS on each container.
- Development sandboxes – route
dev.localto a set of containerized CI/CD tools. - IoT gateways – provide a single entry point for multiple smart‑home APIs while enforcing strict rate limits.
- Zero‑trust edge – combine ACLs with upstream authentication to emulate a modern edge proxy.
Current State and Future Trends
The adoption of reverse proxies in homelab environments has accelerated alongside the rise of container orchestration platforms like Docker Swarm and Kubernetes. As more services become exposed, attackers are refining their reconnaissance techniques – from simple port scans to sophisticated credential‑stuffing campaigns that target default admin interfaces.
Future developments are likely to focus on:
- Behavioral analytics – using machine learning to differentiate normal traffic from malicious patterns in real time.
- Service mesh integration – leveraging sidecar proxies to offload routing decisions from the edge layer.
- Zero‑trust networking – combining reverse proxy ACLs with mutual TLS and service identity verification.
Understanding these trends helps you design a reverse proxy that not only routes traffic but also acts as a security gatekeeper for your entire homelab ecosystem.
PREREQUISITES
Before you begin the analysis, ensure your environment meets the following requirements:
| Component | Minimum Version | Reason |
|---|---|---|
| Docker Engine | 20.10+ | Required for container runtime and image pulls. |
| Docker Compose | 2.4+ | Simplifies multi‑container orchestration. |
| Nginx Proxy Manager | 2.9+ | Provides the logging hooks used in the analysis. |
| Ubuntu/Debian | 22.04 LTS | Tested OS for the provided commands. |
| OpenSSH | 8.9+ | Needed for secure remote access to the host. |
| jq | 1.6+ | Used in log parsing scripts. |
| awk, grep, sed | Core utilities | Essential for log processing pipelines. |
Network and Security Considerations
- Public IP allocation – Ensure you have a static public IPv4 address or a stable dynamic DNS record.
- Port exposure – Only expose ports 80 and 443 to the internet; all other services should remain bound to
localhostor an internal network. - Firewall – Use
ufworiptablesto restrict inbound traffic to the proxy ports and block obvious scanning ranges (e.g., known cloud provider IP blocks).
User Permissions
All commands that modify Docker containers or edit configuration files must be executed with a user that belongs to the docker group or via sudo.
Pre‑Installation Checklist
- Verify Docker is installed and functional (
docker version). - Pull the latest Nginx Proxy Manager image (
docker pull jc21/nginx-proxy-manager). - Create a dedicated directory for persistent storage (
/opt/npm-data). - Ensure your domain’s DNS records point to the public IP (
Arecord). - Open ports 80 and 443 in your firewall and confirm they are reachable (
nc -zv your.domain.com 80).
INSTALLATION & SETUP
Below is a step‑by‑step guide to deploy Nginx Proxy Manager, configure logging, and prepare the environment for traffic analysis.
1. Pull and Run the Proxy Manager Container
1
2
3
4
5
6
7
8
9
docker run -d \
--name npm \
--restart unless-stopped \
-p 80:80 \
-p 443:443 \
-p 81:81 \
-v /opt/npm-data:/data \
-v /opt/npm-data/logs:/logs \
jc21/nginx-proxy-manager:latest
Explanation of flags
-d– Run container in detached mode.--name npm– Assign a predictable container name for later reference ($CONTAINER_NAMES).-p 80:80and-p 443:443– Map public HTTP and HTTPS ports to the container.-p 81:81– Expose the admin UI on an alternate port (optional, should be firewalled).-v /opt/npm-data:/data– Persist configuration and database files.-v /opt/npm-data/logs:/logs– Mount a host directory for log collection.
2. Access the Admin UI
Open a browser and navigate to http://your.domain.com:81. The default admin credentials are admin@admin.com / changeme. Immediately change the password and enable two‑factor authentication if possible.
3. Configure Logging
Nginx Proxy Manager writes access logs to /logs/access.log. To ensure logs are captured in a structured format suitable for parsing, enable JSON output via environment variable:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# docker-compose.yml snippet
services:
npm:
image: jc21/nginx-proxy-manager:latest
environment:
- LOG_LEVEL=info
- LOG_JSON=true
volumes:
- /opt/npm-data:/data
- /opt/npm-data/logs:/logs
ports:
- "80:80"
- "443:443"
- "81:81"
After updating the compose file, restart the container:
1
docker compose up -d npm
4. Verify Log Rotation
Create a simple logrotate configuration to prevent unbounded log growth:
1
2
3
4
5
6
7
8
9
10
cat <<'EOF' > /etc/logrotate.d/nginx-proxy-manager
/opt/npm-data/logs/*.log {
daily
rotate 14
compress
missingok
notifempty
create 0640 1000 1000
}
EOF
Reload logrotate:
1
logrotate -f /etc/logrotate.d/nginx-proxy-manager
5. Harvest Logs for Analysis
The raw access logs are stored as newline‑delimited JSON objects. To extract a 30‑day window, use the following command:
1
docker exec $CONTAINER_ID sh -c "jq -r 'select(.time // empty | strptime(\"%Y-%m-%dT%H:%M:%S.%fZ\") | now - .time < 2592000)' /logs/access.log > /opt/npm-data/logs/30day_access.json"
Key points
$CONTAINER_IDrefers to the container ID of the running Nginx Proxy Manager instance.- The
jqfilter selects records whose timestamp falls within the last 2592000 seconds (30 days). - Output is saved to a dedicated file for downstream processing.
6. Install Supporting Tooling
1
apt-get update && apt-get install -y jq awk grep sed
These utilities provide the foundation for the log‑parsing pipeline described later.
CONFIGURATION & OPTIMIZATION
With the reverse proxy operational and logs being collected, the next phase focuses on shaping the proxy’s behavior to surface the information you need while minimizing noise.
1. Enable Detailed Access Logging
In the Nginx Proxy Manager UI, navigate to Settings → Logging and ensure the following options are checked:
- Log Request Headers – captures client‑provided headers such as
User-AgentandReferer. - Log Response Headers – records server‑generated headers for later analysis.
- Log Request Body – optional, useful for inspecting POST payloads that may contain exploit attempts.
Enable these settings and apply the changes.
2. Implement Rate Limiting
Rate limiting helps throttle abusive clients that generate a high volume of requests in a short period. Add a global rule that limits requests to 10 per second per IP:
1
2
3
4
5
6
7
8
# In the Nginx Proxy Manager configuration file (e.g., /data/config.json)
{
"rate_limit": {
"limit": 10,
"burst": 20,
"period": 1
}
}
After editing, restart the container to apply:
1
docker restart $CONTAINER_ID
3. Deploy Custom WAF Rules
Nginx Proxy Manager supports custom Nginx directives via the Custom Nginx Configuration section. Below is a set of rules that block common attack patterns:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Block SQL injection attempts
if ($args ~* "union select") {
return 403;
}
# Block path traversal
if ($request_uri ~* "\.\.") {
return 403;
}
# Block known scanning tools
if ($http_user_agent ~* "(nmap|nikto|sqlmap|acunetix|dirbuster)") {
return 403;
}
Insert the above snippet into the Custom Nginx Configuration field and save.
4. Harden TLS Settings
Modern TLS configurations mitigate downgrade attacks and enforce strong cipher suites. Add the following to the SSL/TLS Settings for each domain:
1
2
ssl_protocols TLSv1.2 TLSv1.3;
ssl