Setting up OpenVPN clients traditionally involves multiple manual steps that create friction for end users. The standard workflow requires:
- Downloading a zip archive containing configuration and certificate files
- Extracting files to the correct filesystem location
- Manually editing .ovpn files to adjust paths and settings
We can streamline this process by programmatically generating and hosting ready-to-use OpenVPN profiles. Here's a Python implementation using Flask:
from flask import Flask, send_file
import os
import zipfile
import io
app = Flask(__name__)
@app.route('/generate-profile/<username>')
def generate_profile(username):
# Create in-memory zip file
memory_file = io.BytesIO()
with zipfile.ZipFile(memory_file, 'w') as zf:
# Add client certificate
zf.writestr(f'{username}.crt', get_client_cert(username))
# Add client key
zf.writestr(f'{username}.key', get_client_key(username))
# Generate and add .ovpn config
config = generate_ovpn_config(username)
zf.writestr(f'{username}.ovpn', config)
memory_file.seek(0)
return send_file(
memory_file,
mimetype='application/zip',
as_attachment=True,
download_name=f'{username}_openvpn_profile.zip'
)
def generate_ovpn_config(username):
return f'''client
dev tun
proto udp
remote vpn.example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
key-direction 1
<ca>
{get_ca_cert()}
</ca>
<cert>
{get_client_cert(username)}
</cert>
<key>
{get_client_key(username)}
</key>
'''
For even simpler deployment, we can embed all certificates directly in the .ovpn file:
def generate_all_in_one_ovpn(username):
config = f'''client
dev tun
proto udp
remote vpn.example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
<ca>
{get_ca_cert()}
</ca>
<cert>
{get_client_cert(username)}
</cert>
<key>
{get_client_key(username)}
</key>
tls-auth ta.key 1
<tls-auth>
{get_tls_auth_key()}
</tls-auth>
'''
return config
When implementing this solution, consider these security aspects:
- Implement proper authentication before generating profiles
- Use HTTPS for all connections
- Set appropriate cache-control headers
- Rotate certificates periodically
For enterprise deployments, you might want to integrate with existing authentication systems like LDAP or OAuth.
Here's how users can programmatically fetch and apply the configuration on Linux:
#!/bin/bash
# Download and install OpenVPN profile
curl -u username:password https://vpn.example.com/generate-profile/$USERNAME -o profile.zip
unzip profile.zip -d /etc/openvpn/client/
systemctl restart openvpn-client@$USERNAME
Distributing OpenVPN configurations shouldn't require users to manually handle certificate files and configuration tweaks. The ideal solution should generate complete, ready-to-use .ovpn profiles that include all necessary certificates and keys inline.
Here's a Python script that generates client configurations dynamically:
#!/usr/bin/env python3
import os
from configparser import ConfigParser
def generate_ovpn_profile(client_name, server_config):
"""Generate a complete OpenVPN client profile with inline certificates"""
template = f"""client
dev tun
proto {server_config['proto']}
remote {server_config['host']} {server_config['port']}
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
<ca>
{open(server_config['ca_path']).read()}
</ca>
<cert>
{open(f"pki/issued/{client_name}.crt").read()}
</cert>
<key>
{open(f"pki/private/{client_name}.key").read()}
</key>
"""
return template
Create a simple Flask endpoint to serve generated profiles:
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/download/vpn-profile/<username>')
def download_profile(username):
profile = generate_ovpn_profile(username, server_config)
response = make_response(profile)
response.headers['Content-Type'] = 'application/x-openvpn-profile'
response.headers['Content-Disposition'] = f'attachment; filename={username}.ovpn'
return response
When implementing automated profile generation:
- Store CA and server certificates outside web root
- Implement proper authentication before profile download
- Set appropriate file permissions (600 for private keys)
- Consider certificate expiration and revocation
For different operating systems, provide these instructions:
# Linux example
curl -u USERNAME https://vpn.example.com/download/vpn-profile/$USER > ~/client.ovpn
sudo mv ~/client.ovpn /etc/openvpn/client/
sudo systemctl start openvpn-client@client
For Windows users, create a PowerShell script that:
$client = New-Object System.Net.WebClient
$client.Credentials = New-Object System.Net.NetworkCredential($env:USERNAME, (Read-Host -AsSecureString))
$client.DownloadFile("https://vpn.example.com/download/vpn-profile/$env:USERNAME", "$env:USERPROFILE\OpenVPN\config\client.ovpn")