When running openvpn --config client.ovpn
on an EC2 instance, the immediate SSH connection drop occurs because:
- The VPN client routes all traffic through the tunnel by default
- EC2's SSH access relies on the original network interface
- Security Group rules become ineffective for the new VPN tunnel
For EC2 instances in a VPC, we need a two-pronged approach:
# 1. Modify OpenVPN client configuration
client
dev tun
proto udp
remote vpn.server.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
# Critical routing modifications:
route-nopull
route 169.254.169.254 255.255.255.255 net_gateway
script-security 2
up "/etc/openvpn/update-resolv-conf"
down "/etc/openvpn/update-resolv-conf"
Create a custom routing script (/etc/openvpn/ec2-routes.sh
):
#!/bin/bash
# Preserve EC2 metadata service access
ip route add 169.254.169.254 via $(ip route show | grep default | awk '{print $3}')
# Add your SSH source IPs (replace with your actual IPs)
ip route add YOUR_SSH_IP/32 via $(ip route show | grep default | awk '{print $3}')
# Route all other traffic through VPN
ip route add 0.0.0.0/1 via $route_vpn_gateway
ip route add 128.0.0.0/1 via $route_vpn_gateway
Modify your systemd service unit (/etc/systemd/system/openvpn-client@.service
):
[Unit]
Description=OpenVPN Client
After=network.target
[Service]
Type=simple
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/%i.conf --route-up /etc/openvpn/ec2-routes.sh
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
After implementation:
- Start the service:
sudo systemctl start openvpn-client@client
- Verify routes:
ip route show
- Check tunnel IP:
curl ifconfig.me
- Test metadata access:
curl http://169.254.169.254/latest/meta-data/
For persistent connections, consider using autossh
with a monitoring port:
autossh -M 20000 -N -f -L 2222:localhost:22 ec2-user@your-ec2-instance
When configuring an OpenVPN client on EC2 instances, the immediate SSH connection drop occurs because all traffic (including SSH) gets routed through the VPN tunnel by default. This creates a catch-22 situation where you need SSH access to fix the routing but lose it precisely when the VPN connects.
Before launching OpenVPN, verify your VPC security groups allow both:
- Inbound SSH (TCP 22) from your management IP
- Outbound UDP 1194 (or your VPN port) to the VPN server
# Sample AWS CLI command to update security groups
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789 \
--protocol tcp \
--port 22 \
--cidr 203.0.113.1/32
Modify the OpenVPN client configuration to maintain SSH access through these approaches:
# Method 1: Exclude SSH traffic in client.ovpn
route-nopull
route 203.0.113.1 255.255.255.255 net_gateway
route 10.0.0.0 255.0.0.0 vpn_gateway
# Method 2: Use routing policy scripts
script-security 2
route-up "/etc/openvpn/route-up.sh"
Create /etc/openvpn/route-up.sh
:
#!/bin/bash
# Preserve SSH access to management IP
ip route add 203.0.113.1/32 via $(ip route show default | awk '{print $3}')
# Add other exceptions if needed
ip route add 169.254.169.254/32 via $(ip route show default | awk '{print $3}')
# Verify metadata service remains accessible
curl http://169.254.169.254/latest/meta-data/instance-id
For systemd-based instances, create a custom service:
[Unit]
Description=OpenVPN Client with SSH Preservation
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/openvpn --daemon --config /etc/openvpn/client/client.ovpn --route-up /etc/openvpn/route-up.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
When connection drops occur:
- Check instance console logs via AWS web console
- Review OpenVPN logs in
/var/log/syslog
- Test routing tables with
ip route show table all
After successful connection:
# Confirm traffic routing
curl ifconfig.me # Should show VPN IP
dig +short myip.opendns.com @resolver1.opendns.com
# Verify SSH pathway remains
traceroute 203.0.113.1