Skip to content
Joey Wang
Menu

Search

DevOps and Reliability

OpenVPN: Restrict Client Access to Specific IPs Only

How to restrict OpenVPN clients to a limited set of destination IPs, using client-config-dir routes, a client-connect script, and iptables rules.

· 3 min read

security #openvpn#networking#firewall#security

Audio summary

OpenVPN’s default behavior is full network access: once a client connects, it can reach anything routable through the tunnel. That’s not what you want for a contractor VPN, a support tunnel, or any profile that only needs a handful of internal services. Restricting a client to specific IPs takes three pieces working together: a client-config-dir route, a script that runs on connect, and iptables rules that actually enforce it.

Prerequisites

  • A working OpenVPN server
  • Root or sudo access to the server
  • Basic knowledge of networking and firewall concepts

Server configuration

Edit /etc/openvpn/server.conf:

# DNS setup
push "dhcp-option DNS 10.8.0.1"
push "redirect-gateway def1 bypass-dhcp"

# This helps prevent DNS leaks on Windows
push "block-outside-dns"

# Client configuration directory
client-config-dir /etc/openvpn/ccd
route 10.8.0.0 255.255.255.0

# Logging
log-append /var/log/openvpn.log
status /var/log/openvpn-status.log

# Enable running external scripts
script-security 2
client-connect /etc/openvpn/client-connect.sh

Create the client config directory:

sudo mkdir -p /etc/openvpn/ccd
sudo chown nobody:nogroup /etc/openvpn/ccd
sudo chmod 755 /etc/openvpn/ccd

Push the specific routes clients are allowed to use:

push "route 192.168.1.0 255.255.255.0"
push "route 10.0.0.5 255.255.255.255"

Enforcing the restriction with a client-connect script

Pushed routes tell the client which networks to send through the tunnel; they don’t stop the server from forwarding traffic anywhere else. The actual enforcement happens in iptables, applied by a script that runs every time a client connects.

List of allowed destination IPs:

echo "192.168.1.100
10.0.0.50
203.0.113.10" > /etc/openvpn/allowed_ips.txt

/etc/openvpn/client-connect.sh:

#!/bin/bash

# Read the allowed IPs
ALLOWED_IPS=$(cat /etc/openvpn/allowed_ips.txt)

# Create iptables rules for each allowed IP
for IP in $ALLOWED_IPS; do
    iptables -A FORWARD -i tun+ -d $IP -j ACCEPT
done

# Drop all other forward traffic from tun interfaces
iptables -A FORWARD -i tun+ -j DROP
chmod +x /etc/openvpn/client-connect.sh

Managing rules directly with iptables

If you’d rather manage rules by hand instead of through the connect script:

# Allow all traffic for other VPN clients
sudo iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT

# Rules for a specific client (10.8.0.5)
sudo iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.5 -d 93.184.216.34 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.5 -p udp --dport 53 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.5 -j DROP
# View current rules
sudo iptables -L -v -n

# Delete a specific rule
sudo iptables -L --line-numbers
sudo iptables -D CHAIN_NAME RULE_NUMBER

Back up and restore:

sudo iptables-save > /tmp/iptables.rules
sudo iptables-restore < /tmp/iptables.rules

A backup script, if you want this on a cron job:

#!/bin/bash
BACKUP_DIR="/path/to/backup/directory"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="$BACKUP_DIR/iptables_backup_$TIMESTAMP.rules"
iptables-save > "$BACKUP_FILE"
echo "Backup saved to $BACKUP_FILE"

Per-client configuration

To give one client its own IP and routes, create a file in ccd named after the client:

sudo nano /etc/openvpn/ccd/client1
# Assign a specific IP to the client
ifconfig-push 10.8.0.200 255.255.255.255

# Push specific routes to this client
push "route 192.168.1.0 255.255.255.0"
sudo chown nobody:nogroup /etc/openvpn/ccd/client1
sudo chmod 644 /etc/openvpn/ccd/client1

Verifying it worked

sudo systemctl status openvpn
# or
sudo service openvpn status
# Check routing table
netstat -r
ip route

# Check tun interface
ifconfig tun0
ip addr show tun0

# Check OpenVPN connections
ss -anp | grep openvpn
netstat -anp | grep openvpn
tail -f /var/log/openvpn.log

What this buys you, and what it doesn’t

Pushed routes and iptables rules restrict where traffic can go, but they’re enforced on the server, not the client: a compromised or misconfigured client is still authenticated, just unable to reach much. That’s the right trade-off for a contractor or support tunnel. It isn’t a substitute for per-client certificates and proper key management, which this setup assumes you’ve already solved.