mrwick/notebook

drag or arrow keys to move · scroll to zoom · esc to exit

Per-IP limits instead of a CDN

This blog runs on my own VPS. A CDN would hide the server behind another company’s network. I chose not to do that. I added per-IP limits on the public ports instead.

What the rules do

The rules cover ports 80, 443 and 853. Port 853 is DNS over TLS.

The mechanism

The rules use iptables and ip6tables. Two match modules do the work:

The IPv6 rules use a mask of 128, and the IPv4 rules use 32. Each limit then applies to a single address.

Why DOCKER-USER

My services run in Docker. Docker publishes ports through NAT, and those packets skip the normal INPUT chain. Rules there never see them. Docker gives one chain for this case, DOCKER-USER, and it runs before Docker’s own rules. My script puts a jump to its own EDGE-LIMITS chain there, only for the public network interface.

The script is idempotent. It creates the chain or flushes it, then adds the rules. It adds the jump only if the jump does not exist. A systemd one-shot unit runs it after Docker starts. Docker restarts re-run it too.

What it does not do

A single source cannot flood the server any more. But the rules cannot stop a flood that fills the network link. By then the packets have already arrived. Only an upstream provider can stop that.

Still open

I picked the numbers 100 and 50 as sensible limits, not from measurement. I would watch the counters for a few weeks and then tune them. A busy office behind one shared address could also hit the limits. I have not tested that.