[GH-ISSUE #3121] setup_host_firewall.sh blocks all incoming ICMP ping on self-hosted servers — no option to disable, breaks ping-based monitoring #1449

Open
opened 2026-10-13 20:42:39 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @snarknn on GitHub (Sep 3, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3121

Issue: setup_host_firewall.sh blocks all incoming ICMP ping on self-hosted servers — no option to disable, breaks ping-based monitoring

Summary

When deploying a self-hosted server via the Amnezia Windows client (v5.0.1.5), the script client/server_scripts/setup_host_firewall.sh unconditionally adds a host-level iptables rule that drops every incoming ICMP echo-request (ping):

sudo iptables -C INPUT -p icmp --icmp-type echo-request -j DROP || sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

Result: the server is completely unresponsive to ping, even though it is fully up (SSH/TCP and the VPN itself work). There is no option to disable this in the client, so external ICMP-based monitoring/health checks of such servers are impossible.

Affected

  • Amnezia Windows client 5.0.1.5, self-hosted setup flow (InstallController).
  • Deployed protocol: AmneziaWG (observed), but the rule is host-level, so it applies to any protocol (except XRay, see below).

Reproduction

  1. Deploy a self-hosted server through the client (e.g. AmneziaWG).
  2. From outside: ping <server-ip> → 100% packet loss, though SSH/TCP connect fine.
  3. On the server: sudo iptables -L INPUT shows -A INPUT -p icmp -m icmp --icmp-type 8 -j DROP.

Where the rule comes from

  • Added by client/server_scripts/setup_host_firewall.sh:2.
  • Run on every container setup: InstallController::setupContainer() → setupServerFirewall() (client/core/controllers/selfhosted/installController.cpp:158), which executes setup_host_firewall.sh over SSH (installController.cpp:982-988).
  • Appended with -A each time; no config flag skips it.

Thus the DROP is re-applied on the next deploy — manual removal is not persistent.

Why it matters

  • Host becomes invisible to ICMP uptime monitoring / external health checks.
  • Nothing in the UI warns that ping will be blocked; it's the install itself, not the provider/network.
  • Cannot be permanently disabled without forking or patching the script.

Proposal

Add an option to disable ICMP ping blocking (checkbox during server setup, or a config flag) so users running plain self-hosted VPN servers can keep ping monitoring. Precedent already exists: XRay does the opposite — iptables -A INPUT -p icmp -j ACCEPT (client/server_scripts/xray/start.sh:10).

Workaround (current)

Insert an ACCEPT before the DROP in INPUT chain:

sudo iptables -I INPUT 1 -p icmp --icmp-type echo-request -j ACCEPT

Note: this is transient — the next deploy re-appends the DROP.

Originally created by @snarknn on GitHub (Sep 3, 2026). Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3121 # Issue: `setup_host_firewall.sh` blocks all incoming ICMP ping on self-hosted servers — no option to disable, breaks ping-based monitoring ## Summary When deploying a self-hosted server via the Amnezia Windows client (v5.0.1.5), the script `client/server_scripts/setup_host_firewall.sh` unconditionally adds a host-level iptables rule that **drops every incoming ICMP echo-request (ping)**: ```sh sudo iptables -C INPUT -p icmp --icmp-type echo-request -j DROP || sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP ``` Result: the server is **completely unresponsive to ping**, even though it is fully up (SSH/TCP and the VPN itself work). There is **no option to disable this** in the client, so external ICMP-based monitoring/health checks of such servers are impossible. ## Affected - Amnezia Windows client **5.0.1.5**, self-hosted setup flow (`InstallController`). - Deployed protocol: **AmneziaWG** (observed), but the rule is host-level, so it applies to any protocol (except XRay, see below). ## Reproduction 1. Deploy a self-hosted server through the client (e.g. AmneziaWG). 2. From outside: `ping <server-ip>` → 100% packet loss, though SSH/TCP connect fine. 3. On the server: `sudo iptables -L INPUT` shows `-A INPUT -p icmp -m icmp --icmp-type 8 -j DROP`. ## Where the rule comes from - Added by `client/server_scripts/setup_host_firewall.sh:2`. - Run on **every** container setup: `InstallController::setupContainer()` → `setupServerFirewall()` (`client/core/controllers/selfhosted/installController.cpp:158`), which executes `setup_host_firewall.sh` over SSH (`installController.cpp:982-988`). - Appended with `-A` each time; no config flag skips it. Thus the DROP is re-applied on the next deploy — manual removal is not persistent. ## Why it matters - Host becomes invisible to ICMP uptime monitoring / external health checks. - Nothing in the UI warns that ping will be blocked; it's the install itself, not the provider/network. - Cannot be permanently disabled without forking or patching the script. ## Proposal Add an option to **disable ICMP ping blocking** (checkbox during server setup, or a config flag) so users running plain self-hosted VPN servers can keep ping monitoring. Precedent already exists: XRay does the opposite — `iptables -A INPUT -p icmp -j ACCEPT` (`client/server_scripts/xray/start.sh:10`). ## Workaround (current) Insert an ACCEPT before the DROP in INPUT chain: ```sh sudo iptables -I INPUT 1 -p icmp --icmp-type echo-request -j ACCEPT ``` Note: this is transient — the next deploy re-appends the DROP.
Author
Owner

@HeisLuka commented on GitHub (Sep 8, 2026):

I think this is also an ownership/lifecycle problem, not only a missing checkbox.

Current dev still unconditionally adds the host-level rule:

iptables -C INPUT -p icmp --icmp-type echo-request -j DROP ||
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

during setupContainer().

There are two additional details worth accounting for when fixing it.

First, the XRay iptables -A INPUT -p icmp -j ACCEPT mentioned in the issue is not really an exception to this host policy.

That rule is executed by /opt/amnezia/start.sh inside the XRay container, while setup_host_firewall.sh modifies the host namespace.

setupServerFirewall() is still called for XRay setup as well, so the container-local ACCEPT does not undo the VPS host INPUT DROP.

Second, I would avoid implementing the option as simply:

iptables -D INPUT -p icmp --icmp-type echo-request -j DROP

because the existing iptables -C test proves only that an equivalent rule exists; it does not prove that Amnezia owns it.

For example:

administrator creates identical DROP rule
↓
Amnezia install
↓
-C succeeds, so Amnezia creates nothing
↓
user disables "block ping" / removes Amnezia
↓
generic -D removes administrator's rule

So:

matching rule != owned rule

Current lifecycle has the opposite problem as well. If Amnezia itself creates the DROP, remove_container.sh only removes the Docker container/image and leaves the host firewall rule behind.

Therefore:

host A
-> install
-> A + ICMP DROP
-> remove protocol/container
-> A + ICMP DROP

rather than restoring A.

I think the cleanest product behaviour would be:

default:
preserve the administrator's existing host ICMP policy

explicit option enabled:
Amnezia manages an Amnezia-owned ICMP policy

If Amnezia needs to own such host rules, I would give them an explicit ownership boundary instead of writing anonymous rules directly into INPUT.

For example conceptually:

INPUT
-> AMNEZIA-HOST

AMNEZIA-HOST
-> owned ICMP policy

with an Amnezia-specific marker/manifest for the jump/chain, and only mutate/remove objects whose ownership can be established.

Then:

pre-existing foreign identical rule
-> leave untouched

Amnezia-owned rule
-> update/remove allowed

unknown/colliding AMNEZIA-HOST object
-> do not destructively adopt it

Regression matrix:

  1. Clean host + default settings
    expected: existing ICMP policy unchanged

  2. Administrator already has identical DROP
    install + uninstall
    expected: administrator rule survives

  3. Amnezia ICMP blocking explicitly enabled
    expected: exactly one owned rule

  4. Reinstall/update
    expected: no duplicate rules

  5. Disable option / uninstall
    expected: only Amnezia-owned state removed

  6. Administrator adds unrelated ACCEPT/DROP rules
    expected: order/content of foreign rules preserved

There is also another transaction boundary in current setupContainer():

setupServerFirewall(credentials, sshSession);
return startupContainerWorker(...);

The return value from setupServerFirewall() is currently ignored.

Since the same script modifies not only iptables but also multiple host-global sysctls, a partially failed script can mutate some host state and installation can continue anyway.

I would therefore also propagate that error and ideally treat host-policy changes as an explicit setup transaction rather than best-effort side effects.

The important invariant would be:

Amnezia may modify/remove host-global firewall state
only when:
policy was explicitly requested
AND ownership is known

This avoids solving the monitoring issue by introducing a different class of destructive firewall bugs.

<!-- gh-comment-id:5587665795 --> @HeisLuka commented on GitHub (Sep 8, 2026): I think this is also an ownership/lifecycle problem, not only a missing checkbox. Current dev still unconditionally adds the host-level rule: iptables -C INPUT -p icmp --icmp-type echo-request -j DROP || iptables -A INPUT -p icmp --icmp-type echo-request -j DROP during setupContainer(). There are two additional details worth accounting for when fixing it. First, the XRay iptables -A INPUT -p icmp -j ACCEPT mentioned in the issue is not really an exception to this host policy. That rule is executed by /opt/amnezia/start.sh inside the XRay container, while setup_host_firewall.sh modifies the host namespace. setupServerFirewall() is still called for XRay setup as well, so the container-local ACCEPT does not undo the VPS host INPUT DROP. Second, I would avoid implementing the option as simply: iptables -D INPUT -p icmp --icmp-type echo-request -j DROP because the existing iptables -C test proves only that an equivalent rule exists; it does not prove that Amnezia owns it. For example: administrator creates identical DROP rule ↓ Amnezia install ↓ -C succeeds, so Amnezia creates nothing ↓ user disables "block ping" / removes Amnezia ↓ generic -D removes administrator's rule So: matching rule != owned rule Current lifecycle has the opposite problem as well. If Amnezia itself creates the DROP, remove_container.sh only removes the Docker container/image and leaves the host firewall rule behind. Therefore: host A -> install -> A + ICMP DROP -> remove protocol/container -> A + ICMP DROP rather than restoring A. I think the cleanest product behaviour would be: default: preserve the administrator's existing host ICMP policy explicit option enabled: Amnezia manages an Amnezia-owned ICMP policy If Amnezia needs to own such host rules, I would give them an explicit ownership boundary instead of writing anonymous rules directly into INPUT. For example conceptually: INPUT -> AMNEZIA-HOST AMNEZIA-HOST -> owned ICMP policy with an Amnezia-specific marker/manifest for the jump/chain, and only mutate/remove objects whose ownership can be established. Then: pre-existing foreign identical rule -> leave untouched Amnezia-owned rule -> update/remove allowed unknown/colliding AMNEZIA-HOST object -> do not destructively adopt it Regression matrix: 1. Clean host + default settings expected: existing ICMP policy unchanged 2. Administrator already has identical DROP install + uninstall expected: administrator rule survives 3. Amnezia ICMP blocking explicitly enabled expected: exactly one owned rule 4. Reinstall/update expected: no duplicate rules 5. Disable option / uninstall expected: only Amnezia-owned state removed 6. Administrator adds unrelated ACCEPT/DROP rules expected: order/content of foreign rules preserved There is also another transaction boundary in current setupContainer(): setupServerFirewall(credentials, sshSession); return startupContainerWorker(...); The return value from setupServerFirewall() is currently ignored. Since the same script modifies not only iptables but also multiple host-global sysctls, a partially failed script can mutate some host state and installation can continue anyway. I would therefore also propagate that error and ideally treat host-policy changes as an explicit setup transaction rather than best-effort side effects. The important invariant would be: Amnezia may modify/remove host-global firewall state only when: policy was explicitly requested AND ownership is known This avoids solving the monitoring issue by introducing a different class of destructive firewall bugs.
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amnezia-vpn/amnezia-client#1449
No description provided.