Documentation

Server 3.x

Firewall (iptables)#

A very simple static firewall based on iptables is installed when running the deploy scripts. It allows connections to the VPN, SSH, HTTP and HTTPS ports. In addition it uses NAT for both IPv4 and IPv6 client traffic.

This document explains how to modify the firewall for common scenarios that deviate from the default and on how to tailor the VPN configuration for your particular set-up. Much more is possible with iptables that is out of scope of this document. We only collected some common situations below.

The annotated default firewall configuration files as installed on new deployments can be found here:

You can of course also use the firewall software of your choice, or fully disable the firewall! As our goal was to keep things as simple and easy as possible by default.

CentOS, Red Hat Enterprise Linux and Fedora#

You can find the firewall rules in /etc/sysconfig/iptables (IPv4) and /etc/sysconfig/ip6tables (IPv6).

After making changes, you can restart the firewall using:

$ sudo systemctl restart iptables && sudo systemctl restart ip6tables

You can fully disable the firewall as well:

$ sudo systemctl disable --now iptables && sudo systemctl disable --now ip6tables

Debian#

You can find the firewall rules in /etc/iptables/rules.v4 (IPv4) and /etc/iptables/rules.v6 (IPv6).

After making changes, you can restart the firewall using:

$ sudo systemctl restart netfilter-persistent

You can fully disable the firewall as well:

$ sudo systemctl disable --now netfilter-persistent

IPv4 vs IPv6#

The configuration of IPv4 and IPv6 firewalls is almost identical. When modifying the configuration files you, obviously, have to use the IPv4 style addresses in the IPv4 firewall, and the IPv6 style addresses in the IPv6 firewall. In addition, the ICMP type is different, i.e. icmp for IPv4 and ipv6-icmp for IPv6, see the iptables and ip6tables for examples.

Improving the Defaults#

The default firewall works well, but can be improved upon by updating it to match your deployment.

Restricting SSH Access#

By default, SSH is allowed from everywhere, including the VPN clients. It makes sense to restrict this a set of hosts or a “bastion” host.

The default INPUT rule for SSH is:

-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT

You can modify these rules like this:

-A INPUT -s 192.0.2.0/24    -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -s 198.51.100.0/24 -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT

This allows only SSH connections coming from 192.0.2.0/24 and 198.51.100.0/24. This will also prevent VPN clients from accessing the SSH server.

Opening Additional VPN Ports#

By default, one port, both for TCP and UDP are open for OpenVPN connections:

-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 1194 -j ACCEPT

You can easily add more by using “ranges”, e.g.

-A INPUT -p udp -m state --state NEW -m udp --dport 1194:1197 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 1194:1197 -j ACCEPT

NAT to Multiple Public IP Addresses#

When using NAT with many clients, it makes sense to “share” the traffic over multiple public IP addresses.

The default POSTROUTING rule in the “NAT” table is:

-A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/12 -o eth0 -j MASQUERADE
-A POSTROUTING -s 192.168.0.0/16 -o eth0 -j MASQUERADE

Assuming all IP addresses assigned to VPN clients are in the 10.0.0.0/8 prefix, you can replace this by for example this line:

-A POSTROUTING -s 10.0.0.0/8 -j SNAT --to-source 192.0.2.1-192.0.2.8

Make sure you replace 10.0.0.0/8 with your VPN client IP range and 192.0.2.1-192.0.2.8 with your public IP addresses. All IP addresses in the specified --to-source range will be used, specified IPs included.

NOTE: for IPv6 the situation is similar, except you’d use the IPv6 range(s) and address(es).

NAT to Different Public IP Addresses per Profile#

When using Multiple Profiles, you may want to NAT to different public IP addresses. You could for example use:

-A POSTROUTING -s 10.0.1.0/24 -j SNAT --to-source 192.0.2.1
-A POSTROUTING -s 10.0.2.0/24 -j SNAT --to-source 192.0.2.2
-A POSTROUTING -s 10.0.3.0/24 -j SNAT --to-source 192.0.2.3

Make sure you replace the IP ranges specified in -s with your VPN client IP ranges assigned to the profiles, and the --to-source address with your public IP addresses.

NOTE: for IPv6 the situation is similar, except you’d use the IPv6 range(s) and address(es).

Allow Client to Client Traffic#

By default, client-to-client traffic is not allowed:

-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT

You can either allow all forwarding, be specific with IP ranges (using the -s and -d flags) or even interfaces.

-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o wg0 -j ACCEPT
-A FORWARD -i wg0 -o tun+ -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i tun+ -o tun+ -j ACCEPT
-A FORWARD -i tun+ -o wg0 -j ACCEPT

As an example, you have two WireGuard-only profiles on your server with 10.0.0.0/24 and 10.100.100.0/24 prefixes where the first allows access to the Internet, and the second only allows connectivity between the clients.

-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wg0 -s 10.0.0.0/24 -o eth0 -j ACCEPT
-A FORWARD -i wg0 -s 10.100.100.0/24 -d 10.100.100.0/24 -i wg0 -o wg0 -j ACCEPT

Reject Forwarding Traffic#

Sometimes you want to prevent VPN clients from reaching certain network, or allow them to reach only certain networks. For example in the “split tunnel” scenario. By default, the firewall will allow all traffic and just route traffic as long as the routing for it is configured.

If you use split tunnel, it could make sense to only allow traffic for the ranges you also push to the client. As the client can always (manually) override the configuration and try to send all traffic over the VPN, this may need to be restricted.

If you want to only only traffic to 10.1.1.0/24 and 192.168.1.0/24 from your VPN clients, you can use the following:

-A FORWARD -i tun+ -d 10.1.1.0/24 -j ACCEPT
-A FORWARD -i tun+ -d 192.168.1.0/24 -j ACCEPT

NOTE: for IPv6 the situation is similar.

Drop Certain VPN Client Traffic#

One might want to reject traffic to various ports on the Internet. Traditionally the port to block would be tcp/25 to prevent spam, but these days that seems unnecessary due to mitigations like SPF and DMARC/DKIM, but for completeness sake, we’ll show how to do that here.

The first line is for the IPv4 firewall, the second for IPv6.

-A FORWARD -p tcp --dport 25 -j REJECT --reject-with icmp-admin-prohibited
-A FORWARD -p tcp --dport 25 -j REJECT --reject-with icmp6-adm-prohibited

Reject IPv6 Client Traffic#

As the VPN server is “dual stack” throughout, it is not possible to “disable” IPv6. However, one can easily modify the firewall to prevent all IPv6 traffic over the VPN to be rejected. By rejecting instead of dropping, clients will quickly fall back to IPv4, there will not be any delays in establishing connections. You can simply remove all FORWARD rules and replace it with:

-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited

This will cause all IPv6 to be rejected. The VPN becomes thus effectively IPv4 only. You can of course also use it to reject IPv4 traffic to create an IPv6-only VPN.

Public IP Addresses for VPN Clients#

If you want to use Public Addresses for the VPN clients, this has some implications for the firewall:

  1. NAT needs to be disabled;
  2. Incoming traffic for VPN clients may need to be blocked.

NOTE: it is possible to use NAT for IPv4 and public IP addresses for IPv6, actually this is recommended over using IPv6 NAT!

Disabling NAT#

By removing all POSTROUTING rules from the “NAT” table takes care of disabling NAT.

Allowing Incoming Traffic#

The default FORWARD rules used are:

-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT

This restrict any traffic initiating on the outside reaching your VPN clients.

If you want to allow traffic from a designated host to the clients, e.g. for remote management, you can use the following:

-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o tun+ -s 192.168.11.22/32 -j ACCEPT
-A FORWARD -i eth0 -o wg0 -s 192.168.11.22/32 -j ACCEPT

NOTE: for IPv6 the situation is similar.