Previous T3 fix missed port 8443. In modules/containers/3x-ui.nix,
the 3x-ui container's Xray REALITY inbound is mapped directly
to host port 8443:
basePorts = [
'127.0.0.1:2049:2049/tcp' # panel
'127.0.0.1:2096:2096/tcp' # subscription
'0.0.0.0:8443:8443/tcp' # Xray REALITY inbound
];
This is a DIRECT public mapping (0.0.0.0, not localhost), not
proxied through nginx. The 'reality443Forwarding' option
(погашен в T10) was a separate mechanism that forwarded host:443
→ 127.0.0.1:15380 → container:443 via nginx stream.
After T10, the nginx stream is removed. Xray is now ONLY on
host port 8443 (direct mapping). Port 443 in the nftables
ruleset is still open but not used by Xray — it was only used
through the stream mechanism (now removed).
Owner confirmation 2026-10-10: 'нужен 8443 порт для 3x-ui inbound'.
Fix: add 'tcp dport 8443 accept' to the nftables ruleset.
Xray REALITY is now reachable on:
- 8443 (direct, always was the primary)
- 443 (only if nginx vhost proxies to container, not the case here)
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).
Owner correction 2026-10-10: "не помню, чтобы просил ограничивать
22 порт". The previous T3 fix (5796786) restricted SSH to
iifname "tailscale0" based on a comment in the original vds.nix
that said "SSH is reachable only over Tailscale". The owner
did not actually request this restriction.
This commit:
- Changes to
(all interfaces, no iifname filter)
- Removes the reference
- Updates comments to reflect the actual owner intent
(SSH open everywhere, managed via nftables)
- Keeps the core R1.6 fix: explicit on chain
input, no firewall.* + nftables.* conflict (firewall.enable = false
with lib.mkForce on shadow rules)
- Keeps Xray REALITY (443), ICMP, traceroute, log+drop
- Keeps port 80 closed (no nginx on otreca)
SSH on otreca is now reachable on:
- Tailscale IP (100.64.1.0 or whatever current)
- Public IP (109.248.161.5) on ens3
- Any loopback
Deployment: otreca rebuild + nft verify.
networking.allowPing was a top-level networking option when
firewall.enable = true. With firewall.enable = false (T3 Option A),
the option no longer exists at the networking level. ICMP is now
handled by the nftables ruleset directly
().
Rebuild error: 'The option networking.allowPing does not exist.
Definition values: networking.domain, networking.vlans, networking.wicd.'
Fix: remove the line. No behavior change — ICMP is still accepted
via nftables.
T3/A3. otreca nftables had no final policy (implicit accept, R1.6
violation) and conflicted with networking.firewall.enable = true
(R1.6 conflict). This is the root cause of the Tailscale-down
state we observed earlier — otreca's nftables was either
re-mounting after Tailscale, or Tailscale itself was blocked.
Option A applied:
- networking.firewall.enable = false (eliminates the
firewall.* + nftables.* conflict, R1.6)
- lib.mkForce [] on allowedTCPPorts, lib.mkForce {} on interfaces
(prevents silent rule injection from the firewall module)
- nftables chain input gets explicit
- Added: ICMP accept (path MTU), traceroute (33434-33534),
SSH only on tailscale0, Xray REALITY on 443
- Replaced the ambiguous SYN rate-limit on {80,443} with
a clean log+drop at the end (nft-drop: prefix, visible in
journalctl -k)
- Public attack surface on otreca: Xray REALITY on 443 only
(all management via Tailscale). HTTP/80 closed.
Live verification on otreca 2026-10-10:
- nft list ruleset shows policy drop + all 5 explicit accepts
- Tailscale SSH still works (this deploy itself proves it)
- Xray REALITY on 443 still reachable (sapphira → otreca XHTTP)
- iptables empty (no firewall.* shadow rules)