When connecting through OpenVPN, servers often push DNS configurations that need integration with the local resolver. Traditional methods using resolvconf scripts don't work well with systemd-resolved, which manages DNS through its own API rather than direct /etc/resolv.conf modifications.
systemd-resolved maintains DNS configuration in three key locations:
/run/systemd/resolve/resolv.conf
/etc/resolv.conf (symlink)
DBus interface for dynamic configuration
Create a custom script that interfaces with systemd-resolved's DBus API:
#!/bin/bash
# /etc/openvpn/update-systemd-resolved
case $script_type in
up)
for optionname in ${!foreign_option_*} ; do
option="${!optionname}"
if [[ "$option" =~ ^dhcp-option\ DNS\ (.*)$ ]] ; then
DNS="${BASH_REMATCH[1]}"
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 \
org.freedesktop.resolve1.Manager SetLinkDNS ia(iay) \
$dev 1 2 4 ${DNS//./ }
fi
done
;;
down)
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 \
org.freedesktop.resolve1.Manager RevertLink i $dev
;;
esac
1. Save the script to /etc/openvpn/update-systemd-resolved
2. Make it executable:
chmod +x /etc/openvpn/update-systemd-resolved
3. Add to OpenVPN client config:
script-security 2
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved
Check active DNS configuration after connection:
resolvectl status
Look for your VPN interface in the output with the pushed DNS servers listed.
For split-DNS scenarios where only certain domains should use VPN DNS:
# Add to the 'up' case in the script
if [[ "$option" =~ ^dhcp-option\ DOMAIN\ (.*)$ ]] ; then
DOMAIN="${BASH_REMATCH[1]}"
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 \
org.freedesktop.resolve1.Manager SetLinkDomains a(sb) \
$dev 1 "$DOMAIN" true
fi
If DNS isn't working:
- Verify script is executable and called properly in OpenVPN log
- Check DBus is running: systemctl status dbus
- Ensure systemd-resolved is active: systemctl status systemd-resolved
When establishing an OpenVPN connection, DNS servers are often pushed from the VPN server to enable proper name resolution for internal resources. Traditionally, this was handled by scripts like openvpn-update-resolv-conf
which modified /etc/resolv.conf
directly. However, with modern systems using systemd-resolved
, we need a different approach.
systemd-resolved
manages DNS configuration through its own database at /run/systemd/resolve/resolv.conf
. The key components involved are:
- DNS server list management
- Per-link DNS configuration
- DNSSEC validation
Here's how to properly configure OpenVPN to work with systemd-resolved
:
1. Create an OpenVPN Up/Down Script
#!/bin/bash
# /etc/openvpn/update-systemd-resolved
case $script_type in
up)
for optionname in ${!foreign_option_*}; do
option="${!optionname}"
if [[ "$option" =~ ^dhcp-option\ DNS ]]; then
DNS=${option##dhcp-option DNS }
resolvectl dns "$dev" "$DNS"
resolvectl domain "$dev" "~${DNS%% *}"
fi
done
;;
down)
resolvectl revert "$dev"
;;
esac
2. Configure OpenVPN Client
Add these lines to your OpenVPN client configuration:
script-security 2
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved
down-pre
After connecting to your VPN, check the active DNS configuration:
resolvectl status
You should see your VPN interface listed with the pushed DNS servers.
For more complex setups, consider these additional parameters:
# Set DNS priority (lower number = higher priority)
resolvectl dns "$dev" "$DNS" --set-dns-priority=10
# Configure search domains
resolvectl domain "$dev" "~internal.example.com" "~vpn.example.com"
# Enable DNSSEC for the VPN connection
resolvectl dnsssec "$dev" yes
- DNS leaks: Verify with
dig +short myip.opendns.com @resolver1.opendns.com
- Connection delays: Adjust DNS priority to prevent timeouts
- Domain resolution failures: Check search domain configuration
If using NetworkManager with OpenVPN, you can configure DNS handling directly:
[ipv4]
dns=192.168.1.1;
dns-search=internal.example.com;
ignore-auto-dns=true