SlickStack uses hardcoded Iptables rules as the server's local network firewall. The policy is intentionally small and predictable for a standard single-server WordPress stack rather than exposing every firewall option through ss-config.
The main rule templates are:
modules/iptables/rules-v4.txt
modules/iptables/rules-v6.txt
They are installed as:
/etc/iptables/rules.v4
/etc/iptables/rules.v6
Both installed files use mode 0600.
- Firewall layers
- Default policy
- Allowed inbound traffic
- Installation and persistence
- Persistence across reboots
- Inspecting the active firewall
- ICMP and ICMPv6
- SSH rate limiting
- Denied-packet logging
- Custom rules and managed-file boundaries
- Safe firewall changes
- Recovery
- IPv4 and IPv6 parity
- Scope
Iptables is only one security layer:
Internet
|
+--> provider firewall or security group
|
+--> Cloudflare, when proxied
|
+--> SlickStack Iptables rules
|
+--> Nginx request and connection limits
|
`--> WordPress and application authorization
These controls are related but not interchangeable:
- provider firewalls filter traffic before it reaches the server
- Cloudflare filters proxied HTTP and HTTPS traffic at the edge
- Iptables filters traffic on the server by protocol, address, port, and connection state
- Nginx limits web requests and connections after traffic reaches the web server
- Fail2ban currently adds temporary bans based on selected logs, but it is planned for removal
A public port allowed by a provider firewall can still be blocked by Iptables. A port allowed by Iptables can still be blocked by the provider.
The IPv4 and IPv6 templates use:
INPUT DROP
FORWARD DROP
OUTPUT ACCEPT
This means:
- inbound traffic is blocked unless a later rule allows it
- forwarded traffic is blocked because SlickStack is not intended to route traffic for other machines
- outbound traffic is allowed for updates, packages, certificates, DNS, backups, APIs, and other remote services
The rules use connection tracking to allow established and related inbound traffic after the original connection has already been permitted.
The default rules allow only the traffic expected for a normal SlickStack server:
loopback traffic
established and related connections
HTTP and HTTPS on TCP ports 80 and 443
essential ICMP or ICMPv6
DHCPv6 client traffic on UDP port 546, when applicable
SSH and SFTP on TCP port 22, with rate limiting
The firewall does not publicly expose normal internal services such as:
MySQL on 3306
Memcached on 11211
PHP-FPM on 9000
Those services also normally bind to local interfaces, but the firewall remains an additional boundary.
Install or reconcile the Iptables packages with:
sudo bash /var/www/ss-install-iptables-packagesThis installs:
iptables
iptables-persistent
The current installer explicitly selects the legacy command backend:
iptables-legacy
ip6tables-legacy
Install and immediately apply the SlickStack rule files with:
sudo bash /var/www/ss-install-iptables-configThe alias is:
ss install iptables configBefore promotion, the installer:
- downloads both rule templates
- verifies their SlickStack end markers
- tests them with
iptables-restore -tandip6tables-restore -t - replaces both installed files only when both tests succeed
- applies the IPv4 and IPv6 rules immediately
- enables and restarts
netfilter-persistent - restores file permissions
Invalid or incomplete downloaded rules are not intentionally promoted.
The complete SlickStack installer also reconciles the firewall:
sudo bash /var/www/ss-installUse the narrow Iptables installer when only the firewall layer needs repair.
iptables-persistent and netfilter-persistent load the saved files during startup.
Check the service with:
systemctl status netfilter-persistent --no-pager
systemctl is-enabled netfilter-persistentThe active in-memory rules and the saved files are separate states. A temporary command can alter the running firewall without changing the files that load after reboot. Conversely, editing a saved file does not apply it until it is restored or the persistence service reloads it.
SlickStack's installer updates both states together.
Show active IPv4 rules:
sudo iptables -L -n -v --line-numbersShow active IPv6 rules:
sudo ip6tables -L -n -v --line-numbersDisplay the complete restorable syntax:
sudo iptables-save
sudo ip6tables-saveCheck the selected command backend:
sudo update-alternatives --display iptables
sudo update-alternatives --display ip6tablesTest saved files without applying them:
sudo iptables-restore -t < /etc/iptables/rules.v4
sudo ip6tables-restore -t < /etc/iptables/rules.v6Check expected listeners separately:
sudo ss -lntupA listening service is not necessarily reachable through every firewall layer.
IPv4 and IPv6 use different ICMP policies because IPv6 depends on ICMPv6 for more fundamental network behavior.
The IPv4 rules allow:
echo-request
echo-reply
destination-unreachable
time-exceeded
This supports normal ping, basic diagnostics, traceroute-style behavior, and IPv4 Path MTU feedback through destination-unreachable messages.
The IPv6 rules allow:
echo-request
echo-reply
destination-unreachable
packet-too-big
time-exceeded
parameter-problem
router-advertisement
neighbor-solicitation
neighbor-advertisement
IPv6 requires additional ICMPv6 handling for Path MTU Discovery, router advertisements, and neighbor discovery.
Do not blindly copy the IPv4 ICMP allowlist into IPv6. Blocking required ICMPv6 can cause connectivity failures that appear unrelated to the firewall.
SSH remains public because administrators, SFTP clients, backup tools, and deployment tools may need it.
Both IPv4 and IPv6 use layered limiting:
INPUT -> SSH_GLOBAL_LIMIT -> SSH_SOURCE_LIMIT -> ACCEPT or REJECT
The default limits are:
global SSH cap: 30/min with burst 60
per-source SSH cap: 6/min with burst 12
hashlimit source entry expiry: 60000 ms
The per-source hashlimit names are:
IPv4: ssh4_per_ip
IPv6: ssh6_per_ip
The global limit protects a small server from excessive aggregate connection attempts. The per-source limit prevents one address from consuming the entire normal allowance.
Rejected SSH traffic inside these limiter chains is intentionally not sent to the generic firewall log rule. Constant public bot traffic would otherwise create noisy kernel logs.
The default firewall assumes SSH and SFTP use TCP port 22. Changing SSH to another port requires coordinated changes to SSH configuration, provider controls, Iptables templates, automation, and recovery access.
Remaining denied inbound packets are logged with rate limiting.
The prefixes are:
IPv4: [IPTABLES BLOCK]
IPv6: [IP6TABLES BLOCK]
Search the kernel journal:
journalctl -k | grep 'IPTABLES BLOCK'
journalctl -k | grep 'IP6TABLES BLOCK'Depending on the Ubuntu logging configuration, entries may also appear in:
/var/log/kern.log
/var/log/syslog
The generic log rule is limited to reduce disk and journal noise. Absence of a log entry does not prove that no firewall rejected the traffic; provider controls, Cloudflare, SSH limiter chains, or logging limits may account for the missing entry.
The standard SlickStack rules are hardcoded and are not generated from a general firewall schema in ss-config.
Direct edits to these files can be overwritten:
/etc/iptables/rules.v4
/etc/iptables/rules.v6
They can be replaced by:
ss-install-iptables-config- the complete
ss-install - future SlickStack firewall template updates
For persistent policy changes, prefer the layer that naturally owns the requirement:
- provider firewall for broad source-address or port restrictions before traffic reaches the machine
- Cloudflare for public web edge controls
- Nginx for HTTP path, request, connection, and application-facing limits
- a reviewed SlickStack source-template change when the local host firewall itself must differ
Do not casually append runtime rules and assume they will survive reboot or reconciliation.
SlickStack should not hardcode vendor-specific allowlists for individual backup, deployment, or SFTP services. Normal SSH automation should work within the default limits. Stricter source restrictions are deployment-specific and require an independently maintained policy.
A firewall mistake can immediately terminate SSH and block recovery.
Before changing local rules:
- keep an existing SSH session open
- confirm provider-console or out-of-band access works
- preserve the active and saved rules
- verify both IPv4 and IPv6 behavior
- test syntax before applying
- ensure SSH remains allowed before changing the default policy
- coordinate provider firewall rules with local rules
Create temporary backups:
sudo iptables-save > /root/iptables-v4.before
sudo ip6tables-save > /root/iptables-v6.before
sudo cp /etc/iptables/rules.v4 /root/rules.v4.before
sudo cp /etc/iptables/rules.v6 /root/rules.v6.beforeDo not publish these files without reviewing them for custom addresses or infrastructure details.
When SSH is blocked, use the cloud provider console or recovery environment rather than repeatedly attempting remote changes.
From a working console, inspect the active rules first:
sudo iptables -L -n -v --line-numbers
sudo ip6tables -L -n -v --line-numbersRestore known-good saved rules:
sudo iptables-restore < /etc/iptables/rules.v4
sudo ip6tables-restore < /etc/iptables/rules.v6Reinstall the SlickStack defaults when the saved rules are damaged:
sudo bash /var/www/ss-install-iptables-configThen verify:
systemctl status netfilter-persistent --no-pager
sudo iptables -L -n -v
sudo ip6tables -L -n -v
sudo ss -lntupA provider firewall can still block access after the local rules are repaired.
IPv4 and IPv6 should follow the same security intent for:
- default inbound and forwarding policies
- HTTP and HTTPS access
- SSH rate limiting
- established connections
- denied-packet logging
Their exact rule lists should not be identical because ICMP and address-family behavior differ.
Whenever the firewall policy changes, review and test both templates. Fixing only IPv4 can leave a service unexpectedly available or broken over IPv6.
The standard SlickStack firewall is designed for:
- one WordPress-oriented server
- public web traffic on ports 80 and 443
- administrative SSH and SFTP on port 22
- local application services
- simple inbound filtering
- persistent IPv4 and IPv6 rules
- predictable regeneration from repository templates
It is not intended to provide:
- a general firewall rule builder
- per-user or per-application firewall policy
- multi-server routing or NAT management
- container-network policy
- VPN configuration
- dynamic vendor allowlists
- geo-blocking
- a replacement for Cloudflare or provider firewalls
- a full intrusion-detection or security-monitoring platform
See Security, Cloudflare, Nginx, Fail2ban, Ubuntu, and Troubleshooting.