1Panel-dev / 1Panel-dev/1Panel

[Bug] Enabling container port guard (nftables) locks out SSH: nftables initialization ignores existing "Host Firewall" rules and stale FirewallPortWhiteList takes precedence

Open
#13,813 3 comments 0 reactions 1 assignee View on GitHub

@wanghe-fit2cloud is already working on this.

Since Sep 14, 2026.

type: question
Dominant language
Go
Stars
37k
Forks
3.4k
Avg merge
9h 16m
Merged PRs (30d)
105

Description

Contact Information

No response

1Panel Version

v2.3.0

Steps to Reproduce
  1. On a Linux server (e.g., Ubuntu 24.04 / 26.04), configure SSH to use a custom port (e.g., 54321).
  2. In 1Panel web console, navigate to System -> Firewall -> Host Firewall.
  3. Verify or add an ALLOW rule for port 54321 under the host firewall (e.g., UFW backend). The rule clearly shows status "Allowed" for port 54321 in the 1Panel UI.
  4. Now, navigate to System -> Firewall -> Settings.
  5. Under Container Port Guard , select nftables as the backend and click apply/initialize.
  6. Result: The active SSH session on port 54321 is immediately dropped, and all subsequent SSH connections are rejected/timed out, completely locking the administrator out.
Problem Description

Tracing 1Panel v2.3.0 reveals a severe design flaw where Host Firewall rules and Container Port Guard (nftables) operate as completely isolated silos:

A. Host Firewall Rules Are Completely Ignored by nftables
  • In the 1Panel UI, users manage firewall rules under Host Firewall (firewall_rules / system UFW). Here, port 54321 is clearly listed as Allowed.
  • However, when enabling Container Port Guard with nftables, 1Panel's initialization logic (nftables_helper/manager.go) never reads or migrates existing Host Firewall rules.
  • Because nftables hooks directly into the Linux netfilter pipeline, it bypasses UFW entirely.
B. The Stale Database Cache (FirewallPortWhiteList) Overrides Everything
  • Instead of checking active host firewall rules or active listening sockets, initPreRules() strictly pulls from the static database setting FirewallPortWhiteList (in agent.db):
    SELECT value FROM settings WHERE key = 'FirewallPortWhiteList';
    -- Permanently stuck at installation default: "22/tcp\n80/tcp\n443/tcp\n443/udp"
    
  • Even though 54321 was explicitly allowed in the UI's Host Firewall tab, it was never automatically synced into the separate FirewallPortWhiteList configuration key.
C. The Fatal Lockout Sequence (initPreRules)

In agent/utils/firewall/nftables_helper/manager.go:

func (m *Manager) initPreRules() error {
    // Only ports from the stale database whitelist (22, 80, 443) are accepted here
    for _, port := range ports {
        commands = append(commands, requiredPortCommand(tableFamily, port))
    }
    // Followed immediately by a catch-all drop
    commands = append(commands,
        []string{"flush", "chain", tableFamily, TableName, BasicAfterChain},
        []string{"add", "rule", tableFamily, TableName, BasicAfterChain, "meta", "l4proto", "tcp", "drop"},
        []string{"add", "rule", tableFamily, TableName, BasicAfterChain, "meta", "l4proto", "udp", "drop"},
    )
    return runBatch(commands...)
}
  • Port 22 (where nothing is listening) is allowed, while the real SSH port 54321 (despite being allowed under Host Firewall) is missing from the nftables chain.
  • The chain immediately executes meta l4proto tcp drop, severing admin access instantly.
The expected correct result
  1. Rule Inheritance / Migration: When initializing the nftables backend, 1Panel MUST inherit or migrate the active rules already explicitly allowed in Host Firewall , especially the SSH port.
  2. Dynamic Sync: 1Panel must ensure the actual active SSH listening port is included in the nftables whitelist before applying any packet drop policy.
  3. The administrator should never be locked out when enabling container protection on a server where the port was already marked as "Allowed" in the same panel.
Related log output

Additional Information

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.