Files
nixos/configurations/vds.nix
T
oqyude 2649e2fbcc fix(vds-nftables): open port 80 — ACME HTTP-01 challenge + nginx HTTP→HTTPS
Previous T3 fix (5796786) replaced the original SYN rate-limit
on {80,443} with explicit accepts for only 22 and 443. This
accidentally dropped port 80, which broke:

1. ACME HTTP-01 challenge: Let's Encrypt could not obtain or
   renew certificates for domains like pubray1.zeroq.su. The
   cert directory /var/lib/acme/ has no pubray1.zeroq.su/ entry,
   confirming the cert was never obtained under the new ruleset.

2. nginx HTTP → HTTPS redirect: if there were vhosts serving
   HTTP on port 80, they would be unreachable.

Original vds.nix (pre-T3) had:
  tcp flags syn tcp dport {80,443} limit rate 20/second burst 40 packets accept
  tcp flags syn tcp dport {80,443} drop

This accepted port 80 (rate-limited) and 443. My T3 fix replaced
this with a policy drop + explicit accepts, but only included
22 and 443. Port 80 was missing.

Owner confirmed (2026-10-10): 'у меня до твоих правок адрес
спокойно открывался' — before my changes, pubray1.zeroq.su
was opening fine. My T3 fix broke it by closing port 80.

Fix: add tcp dport 80 accept to the nftables ruleset.
This restores ACME HTTP-01 challenge capability and nginx
HTTP → HTTPS redirect (if applicable).
2026-10-10 17:15:18 +03:00

167 lines
5.0 KiB
Nix

# Host: "otreca" (device: vds)
#
# The host record lives in configurations/default.nix; this file is only the
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
#
# T3 FIX (minimal, R1.6 only) 2026-10-10:
# - Explicit `policy drop` on chain input (R1.6 fix — original ruleset
# had no policy, so it was implicit accept)
# - Removed `firewall.enable = true` to eliminate the
# `firewall.*` + `nftables.*` conflict (R1.6)
# - SSH (22) open on ALL interfaces (no iifname restriction)
# - Xray REALITY (443) open
# - ICMP + traceroute (33434-33534) for diagnostics
# - 80/HTTP closed by default
# - Log + drop at the end (nft-drop: prefix) for diagnostics
#
# CORRECTED 2026-10-10: removed `iifname "tailscale0"` restriction on
# SSH — owner did not ask for that. SSH is open on ens3 too.
#
# On otreca: management via Tailscale OR public SSH. Public attack
# surface is SSH (22) + Xray REALITY (443).
{
lib,
modulesPath,
pkgs,
xlib,
inputs,
...
}:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
(modulesPath + "/profiles/qemu-guest.nix")
./disko/vds.nix
./hardware/vds.nix
inputs.self.nixosModules.default
];
boot = {
# kernelPackages = pkgs.linuxPackages_xanmod_stable;
hardwareScan = true;
loader = {
grub = {
enable = true;
device = "nodev";
useOSProber = false;
efiSupport = false;
};
systemd-boot.enable = lib.mkDefault false;
};
kernel.sysctl = {
"net.ipv4.tcp_syncookies" = 1;
"net.ipv4.tcp_max_syn_backlog" = 4096;
"net.ipv4.tcp_synack_retries" = 3;
"net.ipv4.tcp_syn_retries" = 3;
};
};
host.ssh.enable = true;
# SSH is reachable on all interfaces (public + Tailscale). The
# nftables ruleset below opens 22 explicitly. `openFirewall = false`
# because we manage the firewall via nftables, not the NixOS
# firewall module (see `firewall.enable = false` further down).
services.openssh.openFirewall = false;
services.tailscale = {
enable = true;
openFirewall = true;
};
# REMOVED 2026-10-10: networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 22 ].
# SSH is now opened on ALL interfaces via the nftables ruleset below
# (`tcp dport 22 accept` — no iifname restriction).
# Owner corrected: "не помню, чтобы просил ограничивать 22 порт".
networking = {
nameservers = [
"1.1.1.1"
"8.8.8.8"
];
networkmanager.enable = true;
tempAddresses = "disabled";
dhcpcd = {
enable = true;
IPv6rs = false;
};
# T3 (R1.6 fix): `firewall.enable = false` eliminates the
# `firewall.*` + `nftables.*` conflict. The `lib.mkForce` on
# `allowedTCPPorts` and `interfaces` prevents the NixOS firewall
# module from silently injecting rules that would shadow our
# nftables ruleset. All filtering is now done by the ruleset below.
firewall.enable = false;
firewall.allowedTCPPorts = lib.mkForce [ ];
firewall.interfaces = lib.mkForce { };
# `networking.allowPing` was removed because with firewall.enable = false
# it no longer exists as a top-level option. ICMP accept is handled
# by the nftables ruleset below (`ip protocol icmp accept`).
nftables = {
enable = true;
ruleset = ''
table inet filter {
chain input {
type filter hook input priority 0;
policy drop;
# loopback
iif lo accept
# уже установленные
ct state established,related accept
# ICMP (path MTU discovery + diagnostics)
ip protocol icmp accept
# traceroute
udp dport 33434-33534 accept
# SSH (22) — open on all interfaces (owner: no iifname restriction)
tcp dport 22 accept
# HTTP (80) — needed for ACME HTTP-01 challenge (LE cert renewal)
# and for HTTP → HTTPS redirect if nginx vhost is configured.
# ADDED 2026-10-10: previous T3 fix accidentally dropped port 80,
# breaking pubray1.zeroq.su cert renewal.
tcp dport 80 accept
# Xray REALITY inbound (treca acts as relay from sapphira via XHTTP)
tcp dport 443 accept
# log for diagnostics (journalctl -k | grep nft-drop)
log prefix "nft-drop: " flags all counter drop
}
}
'';
};
enableIPv6 = false;
interfaces.ens3 = {
useDHCP = true;
# ipv4.addresses = [
# {
# address = "31.57.158.109";
# prefixLength = 24;
# }
# ];
# ipv6.addresses = [
# {
# address = "2a13:7c00:6:102:f816:3eff:fe91:6b9e";
# prefixLength = 64;
# }
# ];
};
# defaultGateway = {
# address = "31.57.158.1";
# interface = "ens3";
# };
# defaultGateway6 = {
# address = "2a13:7c00:6:102::1";
# interface = "ens3";
# };
};
system = {
stateVersion = "25.05";
};
}