mirror of https://github.com/msgbyte/tailchat
Merge pull request #3 from STC-Worldwide/docs/runbook-sync
Sync deploy runbook with live VPS statepull/314/head
commit
5b106eb64b
@ -0,0 +1,97 @@
|
||||
#!/usr/sbin/nft -f
|
||||
# STC baseline firewall — 152.53.82.15
|
||||
# applied 2026-08-28, revised same day to be safely re-appliable.
|
||||
#
|
||||
# This file replaces ONLY the `inet filter` table. It deliberately does NOT
|
||||
# use `flush ruleset`, because that would also delete fail2ban's `f2b-table`
|
||||
# and silently drop every active ban. `destroy` is delete-if-exists and does
|
||||
# not error when the table is absent (needs nft >= 1.0.4; this host is 1.1.3).
|
||||
#
|
||||
# Safe to re-apply at any time: nft -f /etc/nftables.conf
|
||||
# or: systemctl reload nftables
|
||||
|
||||
destroy table inet filter
|
||||
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority filter; policy drop;
|
||||
|
||||
iif lo accept comment "loopback"
|
||||
ct state established,related accept
|
||||
ct state invalid drop
|
||||
|
||||
# ICMPv6 is NOT optional: dropping it breaks neighbour discovery
|
||||
# and the box loses IPv6 entirely.
|
||||
meta l4proto ipv6-icmp accept comment "ND / PMTU (v6)"
|
||||
ip protocol icmp accept comment "ping / PMTU (v4)"
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# SERVICE PORTS — add new services HERE, then:
|
||||
# nft -c -f /etc/nftables.conf (check)
|
||||
# nft -f /etc/nftables.conf (apply)
|
||||
# A service not listed here is unreachable. That is intentional.
|
||||
# ---------------------------------------------------------------
|
||||
tcp dport 22 accept comment "ssh"
|
||||
|
||||
# Tailscale. The tailnet is the trust boundary for anything served
|
||||
# here, so the interface is accepted rather than each port -- but note
|
||||
# that is exactly what it means: everything bound on tailscale0 is
|
||||
# reachable by every node on the tailnet.
|
||||
iifname "tailscale0" accept comment "tailnet"
|
||||
udp dport 41641 accept comment "tailscale direct (else it falls back to DERP relay)"
|
||||
tcp dport { 80, 443 } accept comment "web"
|
||||
|
||||
counter comment "dropped by policy"
|
||||
}
|
||||
|
||||
# TCP MSS clamping for the tailnet.
|
||||
#
|
||||
# The direct tailnet path here runs over IPv6, whose minimum MTU is 1280 -
|
||||
# the same number Tailscale uses for its own inner MTU. Add WireGuard and
|
||||
# IPv6 headers and the largest inner packets no longer fit, so they are
|
||||
# dropped in silence. Ordinary traffic is unaffected, which is why ping and
|
||||
# small requests look perfectly healthy; it is the big ones that die.
|
||||
#
|
||||
# It first showed up as `ssh` hanging at SSH2_MSG_KEX_ECDH_REPLY, because
|
||||
# OpenSSH now negotiates mlkem768x25519-sha256 and that reply carries a
|
||||
# ~1184-byte ciphertext plus host key and signature. A TLS handshake with a
|
||||
# real certificate chain is the same shape, so this would have hit the web
|
||||
# interface too.
|
||||
#
|
||||
# Clamping the advertised MSS makes both directions size their segments to
|
||||
# something that survives the tunnel.
|
||||
chain tailnet_mss_out {
|
||||
type filter hook output priority mangle; policy accept;
|
||||
oifname "tailscale0" tcp flags syn tcp option maxseg size set 1160
|
||||
}
|
||||
|
||||
# Both directions are needed, and this is the half that actually fixed it.
|
||||
# Clamping only on output rewrites the MSS this host *advertises*, which
|
||||
# limits what the peer sends us. The packet that was dying went the other
|
||||
# way - server to client - and its size is bounded by the MSS the CLIENT
|
||||
# advertised in its SYN. Rewriting that on the way in is what constrains
|
||||
# our own sends.
|
||||
chain tailnet_mss_in {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
iifname "tailscale0" tcp flags syn tcp option maxseg size set 1160
|
||||
}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
|
||||
# Docker (added 2026-08-29 for Tailchat): container traffic on the
|
||||
# compose bridges (br-*) and the default bridge. Docker's own
|
||||
# ip-filter FORWARD chain still filters behind this, so this only
|
||||
# restores what Docker expects - it does not turn the host into a
|
||||
# general router.
|
||||
ct state established,related accept
|
||||
iifname "docker0" accept
|
||||
oifname "docker0" accept
|
||||
iifname "br-*" accept
|
||||
oifname "br-*" accept
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority filter; policy accept;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue