Add TCPShield / Proxy Protocol support
Adds enforced Proxy Protocol config and docs: a patch-set (config/patches/patch-set.json) that enables proxy protocol, whitelists TCPShield, and sets proxy/direct IPs; exposes PATCH_DEFINITIONS and mounts ./config/patches in docker-compose.yml; adds a featured "Proxy Protocol Support" entry to the dashboard mods page; and adds docs/tcpshield.md describing setup, verification, security model, and first-boot behavior.
This commit is contained in:
1 parent
b043f03d28
commit
dff2b5a9c4
4 files changed
+139
No files matched your search
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"patches": [
|
||||||
|
{
|
||||||
|
"file": "/data/config/proxy_protocol_support.json",
|
||||||
|
"file-format": "json",
|
||||||
|
"ops": [
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"path": "$.enableProxyProtocol",
|
||||||
|
"value": true,
|
||||||
|
"value-type": "bool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"path": "$.whitelistTCPShieldServers",
|
||||||
|
"value": true,
|
||||||
|
"value-type": "bool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"path": "$.proxyServerIPs",
|
||||||
|
"value": ["127.0.0.1"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"path": "$.directAccessIPs",
|
||||||
|
"value": [
|
||||||
|
"127.0.0.1",
|
||||||
|
"::1",
|
||||||
|
"10.0.0.0/8",
|
||||||
|
"172.16.0.0/12",
|
||||||
|
"192.168.0.0/16"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -59,6 +59,13 @@ const FEATURED = [
|
|||||||
description:
|
description:
|
||||||
"Pre-generates the world around spawn so nobody lags exploring new chunks. Run `chunky radius 2000` then `chunky start` in Console.",
|
"Pre-generates the world around spawn so nobody lags exploring new chunks. Run `chunky radius 2000` then `chunky start` in Console.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
slug: "proxy-protocol-support",
|
||||||
|
emoji: "🛡",
|
||||||
|
title: "Proxy Protocol Support",
|
||||||
|
description:
|
||||||
|
"Using TCPShield (or another proxy)? This restores players' real IPs so the Security page and IP bans work. Config is auto-enforced — see docs/tcpshield.md.",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function ModsPage() {
|
export default function ModsPage() {
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ services:
|
|||||||
# Modpack support (leave empty for lean Fabric; see docs/mods-and-modpacks.md)
|
# Modpack support (leave empty for lean Fabric; see docs/mods-and-modpacks.md)
|
||||||
MODRINTH_MODPACK: ${MODRINTH_MODPACK:-}
|
MODRINTH_MODPACK: ${MODRINTH_MODPACK:-}
|
||||||
|
|
||||||
|
# Enforce mod configs on every boot (proxy-protocol/TCPShield settings —
|
||||||
|
# see docs/tcpshield.md). Mods that rewrite their own config files can't
|
||||||
|
# clobber these: patches re-apply before each server start.
|
||||||
|
PATCH_DEFINITIONS: /patches/patch-set.json
|
||||||
|
|
||||||
TZ: ${TZ:-UTC}
|
TZ: ${TZ:-UTC}
|
||||||
ports:
|
ports:
|
||||||
- "${MC_PORT:-25565}:25565"
|
- "${MC_PORT:-25565}:25565"
|
||||||
@@ -52,6 +57,7 @@ services:
|
|||||||
- "${MAP_PORT:-8100}:8100"
|
- "${MAP_PORT:-8100}:8100"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/mc:/data
|
- ./data/mc:/data
|
||||||
|
- ./config/patches:/patches:ro
|
||||||
mem_limit: ${MC_CONTAINER_MEM_LIMIT:-7g}
|
mem_limit: ${MC_CONTAINER_MEM_LIMIT:-7g}
|
||||||
|
|
||||||
# ── Scheduled world backups (itzg/mc-backup) ─────────────────────────────
|
# ── Scheduled world backups (itzg/mc-backup) ─────────────────────────────
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# TCPShield (DDoS protection + real player IPs)
|
||||||
|
|
||||||
|
[TCPShield](https://tcpshield.com) sits in front of the server: players connect to
|
||||||
|
your TCPShield domain, and your real server IP stays hidden and DDoS-protected.
|
||||||
|
The catch: without extra setup, every connection appears to come from TCPShield's
|
||||||
|
proxies, so the Security page, IP bans, and connection logs are useless.
|
||||||
|
|
||||||
|
TCPShield's own RealIP plugin is Bukkit/Bungee/Velocity-only — it does not exist
|
||||||
|
for Fabric. The working path for this stack is **PROXY protocol v2** plus the
|
||||||
|
**Proxy Protocol Support** Fabric mod.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. **TCPShield panel** → your backend → enable **Proxy Protocol**.
|
||||||
|
2. **Mods page** → Recommended → add **Proxy Protocol Support** → Apply
|
||||||
|
(or append `proxy-protocol-support` to `MODRINTH_PROJECTS` in `.env` and
|
||||||
|
`docker compose up -d mc`).
|
||||||
|
3. Nothing else — the mod's configuration is **enforced automatically on every
|
||||||
|
boot** by `config/patches/patch-set.json` (see below). Restart once after
|
||||||
|
installing so the patch applies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose restart mc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verifying it works
|
||||||
|
|
||||||
|
Watch the startup log (`docker compose logs -f mc`). You must see all three:
|
||||||
|
|
||||||
|
```
|
||||||
|
Proxy Protocol Support is enabled!
|
||||||
|
TCPShield integration enabled! Fetching official IPs...
|
||||||
|
Successfully added 2 TCPShield IPs to the trusted proxy list.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then join through your TCPShield domain — the console shows your **real IP**, and
|
||||||
|
`docker compose ps` shows `mc` **healthy**.
|
||||||
|
|
||||||
|
## How the config is managed (don't hand-edit!)
|
||||||
|
|
||||||
|
The mod rewrites `config/proxy_protocol_support.json` at every startup, which
|
||||||
|
silently clobbers hand edits. Instead, the server image applies
|
||||||
|
`config/patches/patch-set.json` from this repo **before every server start**,
|
||||||
|
enforcing:
|
||||||
|
|
||||||
|
| Setting | Value | Why |
|
||||||
|
|---|---|---|
|
||||||
|
| `enableProxyProtocol` | `true` | decode PROXY protocol headers |
|
||||||
|
| `whitelistTCPShieldServers` | `true` | auto-fetch TCPShield's proxy IP ranges — no hardcoding, survives their infra changes |
|
||||||
|
| `proxyServerIPs` | `127.0.0.1` | (TCPShield's ranges are added automatically at runtime) |
|
||||||
|
| `directAccessIPs` | localhost (`127.0.0.1`, `::1`) + private ranges (`10/8`, `172.16/12`, `192.168/16`) | container healthcheck + LAN/panel access |
|
||||||
|
|
||||||
|
To change a value, edit the patch file in the repo and `docker compose up -d mc`.
|
||||||
|
|
||||||
|
**First-boot note:** on a brand-new install the mod's config file doesn't exist
|
||||||
|
yet when patches run, so the very first boot uses mod defaults; every boot after
|
||||||
|
that is patched. One `docker compose restart mc` after first install settles it.
|
||||||
|
|
||||||
|
## Security model
|
||||||
|
|
||||||
|
PROXY protocol headers carry no signature, so anyone who finds your raw server IP
|
||||||
|
could spoof client IPs — the mod prevents this with default-deny:
|
||||||
|
|
||||||
|
- PROXY headers are only accepted from **TCPShield's published ranges** (auto-fetched)
|
||||||
|
- Direct, header-less connections are only accepted from **localhost + LAN**
|
||||||
|
- Everything else → `REJECTED unauthorized direct connection` in the log
|
||||||
|
|
||||||
|
So occasional `REJECTED` lines from random public IPs are the wall working —
|
||||||
|
that's scanner bots hitting your raw IP and bouncing. A `REJECTED ... /0:0:0:0:0:0:0:1`
|
||||||
|
(IPv6 localhost) every few seconds means the container healthcheck is being
|
||||||
|
blocked — that's exactly what the `::1` entry in the patch prevents; if you see
|
||||||
|
it, the patch didn't apply (check `docker compose logs mc | head -50`).
|
||||||
|
|
||||||
|
For belt-and-braces, also enable TCPShield's Advanced Firewall (panel → Network →
|
||||||
|
Firewall), and consider host-firewalling port 25565 to TCPShield's ranges
|
||||||
|
(`curl tcpshield.com/v4`) once everything works.
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
- **Friends must connect via the TCPShield domain** — direct-IP connections from
|
||||||
|
outside your LAN are rejected by design once this is active.
|
||||||
|
- If real players start bouncing with `REJECTED`, TCPShield may have changed
|
||||||
|
their IP ranges *and* the auto-fetch failed at boot — restart the server so it
|
||||||
|
re-fetches.
|
||||||
Reference in new issue
Block a user