+++ date = '2024-10-20T14:22:33-03:00' draft = true title = 'Mastering iptables: Basic Firewall Configurations for a Newly Deployed GNU/Linux Server' description = "The basic usage of iptables for a new GNU/Linux webserver" tags = [ "webserver", "GNU/Linux", "Basics Series", ] +++ When setting up a new Linux server, one of the first things you’ll want to do is secure it by configuring a firewall. iptables, a powerful firewall tool available on most Linux distributions, is an excellent choice for managing traffic rules. In this post, I’ll walk you through setting up some basic iptables configurations for a freshly deployed server. By the end, you’ll have a solid firewall to protect your services while keeping things simple. ## What is iptables? iptables is a command-line firewall utility that uses policy chains to manage network traffic. Each chain is a list of rules that apply to incoming and outgoing packets. You can filter traffic based on things like IP addresses, ports, and protocols. Securing a server is a top priority for any sysadmin, and firewalls are one of the most important layers of defense. With iptables, you can: - [ ] Block unwanted traffic - [ ] Allow trusted connections (e.g., SSH, HTTP/HTTPS) - [ ] Protect against DoS attacks and port scanning - [ ] Log suspicious activity for future analysis ## How a packet flows in iptables I highly suggest that you read more about the packet flow in iptables before applying firewall rules. You can check those well made diagrams by [nerdalert on Github](https://gist.github.com/nerdalert/a1687ae4da1cc44a437d) ## Basic iptables Commands Let’s start with a quick overview of essential iptables commands: ### Show current rules: ```bash iptables -L ``` ### Flush (delete) all existing rules: ```bash iptables -F ``` ### Save iptables rules If you are running Debian, you need to install the `iptables-persistent` package, and then you can use the following commands: ```bash iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 ``` Restore iptables rules: ```bash iptables-restore < /etc/iptables/rules.v4 ip6tables-restore < /etc/iptables/rules.v6 ``` ## Setting Up iptables for a New Server Now, let’s walk through some basic rules you can apply to secure your server right from the start. We’ll allow essential services like SSH and HTTP/HTTPS while blocking everything else. ### Step 1: Clear Existing Rules Before setting up new rules, let’s clear any pre-existing configurations: ```bash iptables -F ``` This ensures you’re starting with a clean slate. Be careful with the following commands, since you can get locked you of your own server! That happens to every sysadmin sooner or later. The easiest way to be sure that it doesn't happen is to do it physically, or remotely via a KVM access. ### Step 2: Set Default Policies Next, we’ll define the default behavior for incoming, outgoing, and forwarded traffic. By default, it’s a good idea to block all incoming traffic and allow outgoing traffic: ```bash iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT ``` This means any incoming connection will be dropped unless you explicitly allow it. Outgoing traffic, on the other hand, is allowed by default. ### Step 3: Allow SSH Traffic (Port 22) You’ll need SSH access to manage your server, so we’ll allow traffic on port 22. It’s important to only allow connections from trusted IP addresses, but for simplicity, we’ll start by allowing all connections on SSH: ```bash iptables -A INPUT -p tcp --dport 22 -j ACCEPT ``` The `-A` is for "Append", this inserts the rule at the bottom, you can insert at the top with `-I` flag. It is a good idea to always add comments to your rules, so in the future you can troubleshoot it faster. In iptables, the syntax to add comments is as follows: ```bash iptables -m comment --comment "Your comments here" ``` If you want to restrict SSH access to a specific IP (for example, your home IP), use this instead: ```bash iptables -A INPUT -p tcp -s -m comment --comment "Allow SSH from my home IP" --dport 22 -j ACCEPT ``` ### Step 4: Allow HTTP and HTTPS Traffic (Ports 80 and 443) If you’re running a web server, you’ll want to allow HTTP and HTTPS traffic: ```bash iptables -A INPUT -m comment --comment "Allow HTTP" -p tcp --dport 80 -j ACCEPT iptables -A INPUT -m comment --comment "Allow HTTPS" -p tcp --dport 443 -j ACCEPT iptables -A INPUT -m comment --comment "Allow QUIC" -p udp --dport 443 -j ACCEPT ``` This allows visitors to access your website over both HTTP (port 80) and HTTPS (port 443). The 443/udp port is for QUIC protocol, QUIC is a transport layer protocol developed by Google, designed for faster, more secure internet connections by combining features of TCP, TLS, and HTTP/2 with lower latency and improved performance. I highly suggest that you search more about this, maybe I write an article about it in the future. ### Step 5: Allow Loopback Traffic Your server needs to communicate with itself via the loopback interface. Let’s make sure traffic on lo is allowed: ```bash iptables -A INPUT -m comment --comment "Allow loopback traffic" -i lo -j ACCEPT ``` ### Step 6: Drop Invalid Packets Invalid packets can often indicate an attack or misconfiguration, so it’s good practice to drop them: ```bash iptables -A INPUT -m conntrack --ctstate INVALID -j DROP ``` ### Step 7: Allow Established and Related Connections To allow responses to outgoing connections (like when your server requests updates), you’ll need to allow established and related connections: ```bash iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT ``` This ensures your server can accept responses to any requests it makes. ### Step 8: Don't forget IPv6 rules! For IPv6, the syntax is the same, you mostly need to change the command from `iptables` to `ip6tables` The main difference is the ICMP protocol, you really need to allow ICMPv6 to your server function properly. Here is a good starting point, where we explicity accept ICMPv6 control packets, while droppping all others. ```bash ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT ip6tables -A INPUT -p icmpv6 -j DROP ``` ### Step 9: Save Your iptables Rules Once you’ve added all your rules, don’t forget to save them. This ensures they persist after a reboot: ```bash iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 ``` ### Step 10: Testing Your Configuration After setting up iptables, it’s a good idea to test it by attempting to connect to your server. You should be able to access SSH, HTTP, and HTTPS services while all other traffic is blocked. ## Summary In summary, this is a good starting point for your rules, remember to save and test everything afterwards! ### IPv4 ```bash iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT iptables -A INPUT -p tcp -s -m comment --comment "Allow SSH from my home IP" --dport 22 -j ACCEPT iptables -A INPUT -m comment --comment "Allow HTTP" -p tcp --dport 80 -j ACCEPT iptables -A INPUT -m comment --comment "Allow HTTPS" -p tcp --dport 443 -j ACCEPT iptables -A INPUT -m comment --comment "Allow QUIC" -p udp --dport 443 -j ACCEPT iptables -A INPUT -m comment --comment "Allow loopback traffic" -i lo -j ACCEPT iptables -A INPUT -m conntrack --ctstate INVALID -j DROP iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables-save > /etc/iptables/rules.v4 ``` ### IPv6 ```bash ip6tables -P INPUT DROP ip6tables -P FORWARD DROP ip6tables -P OUTPUT ACCEPT ip6tables -A INPUT -p tcp -s -m comment --comment "Allow SSH from my home IP" --dport 22 -j ACCEPT ip6tables -A INPUT -m comment --comment "Allow HTTP" -p tcp --dport 80 -j ACCEPT ip6tables -A INPUT -m comment --comment "Allow HTTPS" -p tcp --dport 443 -j ACCEPT ip6tables -A INPUT -m comment --comment "Allow QUIC" -p udp --dport 443 -j ACCEPT ip6tables -A INPUT -m comment --comment "Allow loopback traffic" -i lo -j ACCEPT ip6tables -A INPUT -m conntrack --ctstate INVALID -j DROP ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT ip6tables-save > /etc/iptables/rules.v6 ``` ## Conclusion Congratulations! You’ve successfully configured basic iptables rules for your newly deployed Linux server. By blocking all incoming traffic except for trusted services and connections, you’ve added a crucial layer of security to your server.