Firewall Web Services
The source material this page replaces covers HTTP and HTTPS port forwarding for a Calibre ebook content server, with the traffic rules section left entirely empty. This page covers the same ground properly: the port forwarding entries, the firewall rules, the HTTP-to-HTTPS redirect pattern, and the considerations that apply to any web service exposed to the public internet.
The ebook library is the concrete example, but the pattern applies equally to any self-hosted web service: a Nextcloud instance, a Jellyfin server, a Bitwarden vault, a personal website, or any other HTTPS service.
The web services architecture
For this network, web services accessible from the internet are served by a reverse proxy on the homelab server. The reverse proxy (nginx) listens on ports 80 and 443, handles TLS termination, and forwards requests to the appropriate backend service based on the hostname.
This means:
- A single HTTPS port forward to the reverse proxy covers all publicly accessible web services
- TLS certificates are managed centrally by the reverse proxy
- Backend services (Kavita, Nextcloud, Jellyfin, etc.) listen only on internal addresses and ports
- Adding a new public web service requires updating the reverse proxy configuration, not the firewall
The alternative, a separate port forward for each service on a different port, is messier and exposes internal service architecture to the internet. The reverse proxy approach is cleaner.
The reverse proxy server address is on the Core VLAN. Replace 10.1.0.x throughout this page with the actual address of the homelab server running nginx.
Port forwarding
Navigate to Settings > Firewall & Security > Port Forwarding > Add Port Forward.
HTTP (port 80) - redirect to HTTPS
HTTP connections are forwarded to the reverse proxy, which immediately redirects them to HTTPS. This ensures links and bookmarks using http:// still work without serving any content unencrypted.
| Field | Value |
|---|---|
| Name | HTTP to reverse proxy |
| Enabled | Yes |
| From | Any |
| Port | 80 |
| Forward IP | 10.1.0.x |
| Forward Port | 80 |
| Protocol | TCP |
| Enable NAT Loopback | Yes |
HTTPS (port 443)
All actual web service traffic arrives on port 443.
| Field | Value |
|---|---|
| Name | HTTPS to reverse proxy |
| Enabled | Yes |
| From | Any |
| Port | 443 |
| Forward IP | 10.1.0.x |
| Forward Port | 443 |
| Protocol | TCP |
| Enable NAT Loopback | Yes |
Firewall rules
Navigate to Settings > Firewall & Security > Firewall Rules.
Allow HTTP inbound (WAN In)
| Field | Value |
|---|---|
| Name | Allow HTTP inbound |
| Enabled | Yes |
| Action | Accept |
| IPv4 Protocol | TCP |
| Source | Any |
| Destination | IP Address: 10.1.0.x, Port: 80 |
Allow HTTPS inbound (WAN In)
| Field | Value |
|---|---|
| Name | Allow HTTPS inbound |
| Enabled | Yes |
| Action | Accept |
| IPv4 Protocol | TCP |
| Source | Any |
| Destination | IP Address: 10.1.0.x, Port: 443 |
IPv6
If the homelab server has a public IPv6 address, create IPv6 equivalents of both rules. IPv6 devices are directly reachable without NAT, so port forwarding is not needed, but the WAN In firewall rules are still required.
For IPv6, the destination is the server’s full IPv6 address rather than the internal RFC 1918 address.
NAT loopback
NAT loopback (also called hairpin NAT) is enabled on both port forwards. This allows devices on the internal network to access the publicly accessible services using the external domain name rather than the internal IP address. Without it, https://books.yourdomain.net would only resolve correctly from outside the network.
UniFi enables NAT loopback per port forward rule. Verify it is checked for both the HTTP and HTTPS forwards.
Ebook library: specific configuration
The source material targets a Calibre content server. For this network, Kavita is the recommended ebook and manga server. It is actively maintained, has a cleaner interface than Calibre-Web, and is designed as a dedicated media server rather than adapted from a desktop application.
Kavita runs on an internal port (default 5000) and is not directly exposed to the internet. The nginx reverse proxy handles external access:
server {
listen 80;
server_name books.yourdomain.net;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name books.yourdomain.net;
ssl_certificate /etc/ssl/certs/books.yourdomain.net.crt;
ssl_certificate_key /etc/ssl/private/books.yourdomain.net.key;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support for Kavita
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
The TLS certificate used here is signed by your public-facing CA (Let’s Encrypt) rather than the internal CA. External clients cannot trust your internal CA. The server section covers obtaining and renewing Let’s Encrypt certificates.
Access control considerations
Before making any web service publicly accessible, consider whether it genuinely needs to be public or whether WireGuard VPN access is sufficient.
Case for public access: services that need to be accessible without VPN configuration, shared with people who will not set up VPN, or accessed from devices where VPN is not practical (e-readers, smart TVs).
Case for VPN-only access: services with sensitive data, admin interfaces, services with limited authentication options, services that are not designed with public exposure in mind.
The ebook library is a reasonable candidate for public access: the content is not sensitive, sharing with family members is convenient, and e-readers typically cannot use a WireGuard VPN. Most other self-hosted services belong behind the VPN.
Rate limiting and access logs
Any service exposed to the public internet will receive automated scanning attempts. The nginx reverse proxy should implement rate limiting to slow down credential stuffing and scanner traffic:
# Rate limiting zone in the http block of nginx.conf
limit_req_zone $binary_remote_addr zone=web:10m rate=10r/s;
# Apply in server blocks
limit_req zone=web burst=20 nodelay;
Enable access logging and review it periodically:
access_log /var/log/nginx/books.yourdomain.net.access.log;
error_log /var/log/nginx/books.yourdomain.net.error.log;
The server section covers fail2ban configuration to automatically block IPs that trigger repeated authentication failures.
DNS records
For external access to work, the domain name must resolve to the WAN IP address. Add an A record (and AAAA for IPv6) to your public DNS:
books.yourdomain.net A your.wan.ip.address
books.yourdomain.net AAAA your::ipv6::address
If the WAN IP changes (dynamic IP), configure DDNS to keep the record current. The router section covers DDNS configuration.
Testing
Test from outside the network (a mobile phone with WiFi disabled, or via a VPN to a different exit point):
# Test HTTP redirect
curl -I http://books.yourdomain.net
# Should return 301 redirect to https://
# Test HTTPS
curl -I https://books.yourdomain.net
# Should return 200 and the service response headers
# Test TLS certificate
echo | openssl s_client -connect books.yourdomain.net:443 2>/dev/null | \
openssl x509 -noout -dates
Test NAT loopback from the internal network:
# From the desktop (internal network)
curl -I https://books.yourdomain.net
# Should work the same as from outside
Every service exposed to the public internet is a potential attack surface. Keep services updated, implement rate limiting, use strong authentication, and review access logs regularly. The firewall rules here are the outermost layer of protection, not the only one.