route-up, route-pre-down, and ifconfig-remote directives within your local client configuration file. These hooks allow you to execute specific shell scripts at precise moments during the connection lifecycle, enabling dynamic route manipulation on the client side. This approach is essential when you lack administrative access to the VPN server but need to control traffic flow, such as routing specific subnets through the tunnel while keeping general internet traffic via your default gateway. By leveraging these built-in features, you maintain a clean separation between server-side policies and client-side networking requirements, ensuring that your local machine correctly interprets the remote network topology.
Understanding Client-Side Hooks
OpenVPN provides several environment variables and script execution points that trigger when the virtual network interface is established or torn down. The most critical for this task areroute-up and route-pre-down. The route-up script runs after the kernel has successfully added the routes provided by the server. This is the ideal place to add additional static routes that were not pushed by the server administrator. Conversely, route-pre-down executes before the connection is terminated, allowing you to clean up any custom routes you added to prevent orphaned entries in your routing table.
The ifconfig-remote directive is slightly different; it allows you to modify the IP address and netmask of the tunnel interface before the standard configuration is applied. While less commonly used for adding routes, it can be useful if you need to adjust the primary tunnel parameters based on local conditions. For most custom routing scenarios, focusing on route-up is sufficient. If you are experiencing issues with basic connectivity or authentication, you might find relevant troubleshooting steps in our guide on OpenVPN Can't Open (Kali), which covers common initialization failures that could interfere with script execution.
Creating the Route-Up Script
To implement custom routing, you must create an executable shell script that will handle the addition of routes. On Linux systems, this is typically a Bash script located in a directory accessible to the OpenVPN process, such as/etc/openvpn/scripts/. The script receives several environment variables passed by OpenVPN, including $1 (the interface name), $2 (the local tunnel IP), $3 (the remote tunnel IP), and $4 (the netmask).
Here is a basic example of what the route-up.sh script should contain:
#!/bin/bash
# Add a custom route to a specific subnet
/sbin/ip route add 192.168.100.0/24 dev $1
# Ensure the route is permanent or managed by your network manager
exit 0
Make sure to grant execute permissions to this script using chmod +x /etc/openvpn/scripts/route-up.sh. The script must exit with a status code of 0; otherwise, OpenVPN will consider the route setup failed and may disconnect. You can expand this script to include multiple routes or conditional logic based on the server-assigned IP addresses. For users setting up complex networks, understanding the full configuration workflow is helpful, so refer to How to Create a Configuration File for OpenVPN? for details on structuring your main configuration file.
Configuring the OpenVPN Client File
Once your script is ready, you need to point your OpenVPN client configuration to it. In your.ovpn file or .conf file, add the following line:
route-up /etc/openvpn/scripts/route-up.sh
This directive tells OpenVPN to execute the specified script whenever the routes are successfully installed. If you also want to ensure cleanup happens upon disconnection, add a corresponding route-pre-down directive pointing to a cleanup script that removes the custom routes you added. This prevents routing loops or unreachable destinations after the VPN drops. When connecting behind difficult network environments like CGNAT, proper routing is even more critical to avoid asymmetric routing issues, as discussed in Setting up OpenVPN Connection between Two PCs behind a CGNAT Cloud Server.
Verifying and Troubleshooting
After starting the connection, verify that your custom routes are active by runningip route show or netstat -rn on Linux, or route print on Windows. Look for the specific subnet you defined in your script. If the route does not appear, check the OpenVPN log output for errors related to script execution. Common issues include incorrect file paths, insufficient permissions, or syntax errors in the shell script. Remember that OpenVPN runs scripts with limited privileges, so ensure your script does not require sudo unless explicitly handled via secure mechanisms. For a broader overview of installing and configuring OpenVPN on various platforms, consult our comprehensive How to Set Up a VPN on Linux Using OpenVPN: A Comprehensive Guide.
Frequently Asked Questions
Why do my custom routes disappear after reconnecting?
If you use route-up correctly, routes should persist for the duration of the session. However, if they vanish immediately, check if your network manager is resetting routes upon link changes. Ensure your script exits cleanly with status 0.
Can I use batch files for OpenVPN on Windows?
Yes, Windows supports .bat or .cmd files for these hooks. You must specify the full path to the script in the route-up directive. Be aware that Windows firewall rules might block traffic on new interfaces until manually adjusted.
What if the server pushes conflicting routes?
OpenVPN processes server-pushed routes first. If your custom route conflicts with a server-pushed route, the last one processed usually wins. Use route-up to override or add to these, but be cautious of routing loops.
How do I debug script failures in OpenVPN?
Add logging commands inside your script, such as appending output to a file like echo "Script ran" >> /tmp/openvpn-debug.log. Check the OpenVPN verbose logs (-v level) to see if the script was invoked and if it returned an error code.
Is it safe to hardcode IPs in the route script?
It is generally safer to use the environment variables provided by OpenVPN ($1, $2, etc.) rather than hardcoding interface names or IPs, as these can vary between connections. Hardcoding makes the configuration less portable across different network setups.