This role installs OpenVPN from default repositories, configures it as a server, sets up networking and firewalls (primarily firewalld, ufw and iptables - best effort), and generates client configuration files. It also optionally supports LDAP authentication.
Supported Operating Systems:
- Ubuntu 24.04 and higher
- CentOS 9 and higher
- Debian 11 and higher
OpenVPN must be available as a package in yum/dnf/apt! For CentOS users, this role will run yum install epel-release
to ensure OpenVPN is available.
Ubuntu Precise has a weird bug that might cause the iptables-persistent
installation to fail. There is a workaround.
With Ansible 2.10, modules have been moved into collections. Aside from Ansible's built-in modules, additional collections are required for certain module like seboolean (now ansible.posix.seboolean). The required collections are:
- ansible.posix
- community.general (if using ufw)
Installation:
ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.general
If you're using a standard Ansible distribution, you won't need to install any additional collections.
This role is supported by a group of enthusiasts on a best-effort basis. Feel free to open an issue and contribute a related pull request with a fix.
These options change how the role works. This is a catch-all group, specific groups are broken out below.
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
clients | list | [] | List of clients (kinda users) to add to OpenVPN | |
openvpn_base_dir | string | /etc/openvpn | Path where your OpenVPN config will be stored | |
openvpn_client_config_no_log | boolean | true, false | true | Prevent client configuration files to be logged to stdout by Ansible |
openvpn_key_dir | string | /etc/openvpn/keys | Path where your server private keys and CA will be stored | |
openvpn_ovpn_dir | string | /etc/openvpn | Path where your client configurations will be stored | |
openvpn_revoke_these_certs | list | [] | List of client certificates to revoke. | |
openvpn_selinux_module | string | my-openvpn-server | Set the SELinux module name | |
openvpn_service_name | string | openvpn | Name of the service. Used by systemctl to start the service | |
openvpn_sync_certs | boolean | true, false | false | Revoke certificates not explicitly defined in 'clients' |
openvpn_uninstall | boolean | true, false | false | Set to true to uninstall the OpenVPN service |
openvpn_use_ldap | boolean | true, false | false | Active LDAP backend for authentication. Client certificate not needed anymore |
Change these options if you need to adjust how the configs are download to your local system
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_fetch_client_configs | boolean | true, false | true | Download generated client configurations to the local system |
openvpn_fetch_client_configs_dir | string | /tmp/ansible | If openvpn_fetch_client_configs is true, the local directory to download the client config files into | |
openvpn_fetch_client_configs_suffix | string | "" | If openvpn_fetch_client_configs is true, the suffix to append to the downloaded client config files before the trailing .ovpn extension |
Change these options if you need to force a particular firewall or change how the playbook interacts with the firewall.
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
firewalld_default_interface_zone | string | public | Firewalld zone where the "ansible_default_ipv4.interface" will be pushed into | |
iptables_service | string | iptables | Override the iptables service name | |
manage_firewall_rules | boolean | true, false | true | Allow playbook to manage iptables |
openvpn_firewall | string | auto, firewalld, ufw, iptables | auto | The firewall software to configure network rules. "auto" will attempt to detect it by inspecting the system |
These options change how OpenVPN itself works.
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_client_register_dns | boolean | true, false | true | Add register-dns option to client config (Windows only). |
openvpn_client_to_client | boolean | true, false | false | Set to true if you want clients to access each other. |
openvpn_custom_dns | list[string] | [] | List of DNS servers, only applied if openvpn_set_dns is set to true |
|
openvpn_dualstack | boolean | true | Whether or not to use a dualstack (IPv4 + v6) socket | |
openvpn_keepalive_ping | int | 5 | Set keepalive ping interval seconds. |
|
openvpn_keepalive_timeout | int | 30 | Set keepalive timeout seconds |
|
openvpn_local | string | unset |
Local host name or IP address for bind. If specified, OpenVPN will bind to this address only. If unspecified, OpenVPN will bind to all interfaces. | |
openvpn_port | int | 1194 | The port you want OpenVPN to run on. If you have different ports on different servers, I suggest you set the port in your inventory file. | |
openvpn_proto | string | udp, tcp | udp | The protocol you want OpenVPN to use |
openvpn_redirect_gateway | boolean | true, false | true | OpenVPN gateway push |
openvpn_resolv_retry | int/string | any int, infinite | 5 | Hostname resolv failure retry seconds. Set "infinite" to retry indefinitely in case of poor connection or laptop sleep mode recovery etc. |
openvpn_server_hostname | string | {{ inventory_hostname }} |
The server name to place in the client configuration file | |
openvpn_server_ipv6_network | string | unset |
If set, the network address and prefix of an IPv6 network to assign to clients. If True, IPv4 still used too. | |
openvpn_server_netmask | string | 255.255.255.0 | Netmask of the private network | |
openvpn_server_network | string | 10.9.0.0 | Private network used by OpenVPN service | |
openvpn_set_dns | boolean | true, false | true | Will push DNS to the client (Cloudflare and Google) |
openvpn_tun_mtu | int | unset |
Set tun-mtu value. Empty for default. |
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_auth_alg | string | SHA256 | Set auth authentication algoritm. |
|
openvpn_ca_key | dict | unset |
Contain "crt" and "key". If not set, CA cert and key will be automatically generated on the target system. | |
openvpn_cipher | string | AES-256-CBC | Set cipher option for server and client. |
|
openvpn_crl_path | string | unset |
Define a path to the CRL file for server revocation check. | |
openvpn_duplicate_cn | boolean | true, false | false | Add duplicate-cn option to server config - this allows clients to connect multiple times with the one key. NOTE: client ip addresses won't be static anymore! |
openvpn_rsa_bits | int | 2048 | Number of bits used to protect generated certificates | |
openvpn_script_security | int | 1 | Set openvpn script security option | |
openvpn_tls_auth_key | string | unset |
Single item with a pre-generated TLS authentication key. | |
openvpn_use_crl | boolean | true, false | false | Configure OpenVPN server to honor certificate revocation list. |
openvpn_use_1_3_tls | boolean | true, false | false | Require a minimum version of TLS 1.3 (TLS 1.2 used by default) |
openvpn_use_pregenerated_dh_params | boolean | true, false | false | DH params are generted with the install by default |
openvpn_verify_cn | boolean | true, false | false | Check that the CN of the certificate match the FQDN |
tls_auth_required | boolean | true, false | true | Ask the client to push the generated ta.key of the server during the connection |
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_addl_client_options | list | empty | List of user-defined client options that are not already present in the client template. (e.g. - mssfix 1400 ) |
|
openvpn_addl_server_options | list | empty | List of user-defined server options that are not already present in the server template. (e.g. - ping-timer-rem ) |
|
openvpn_compression | string | lzo | Set compress compression option. Empty for no compression. |
|
openvpn_config_file | string | openvpn_{{ openvpn_proto }}_{{ openvpn_port }} | The config file name you want to use (set in vars/main.yml) | |
openvpn_enable_management | boolean | true, false | false | |
openvpn_ifconfig_pool_persist_file | string | ipp.txt | ||
openvpn_management_bind | string | /var/run/openvpn/management unix | The interface to bind on for the management interface. Can be unix or TCP socket. | |
openvpn_management_client_user | string | root | Use this user when using a Unix socket for management interface. | |
openvpn_push | list | empty | Set here a list of string that will be inserted into the config file as push "" . E.g - route 10.20.30.0 255.255.255.0 will generate push "route 10.20.30.0 255.255.255.0" |
|
openvpn_script_client_connect | string | unset |
Path to your openvpn client-connect script | |
openvpn_script_client_disconnect | string | unset |
Path to your openvpn client-disconnect script | |
openvpn_script_down | string | unset |
Path to your openvpn down script | |
openvpn_script_up | string | unset |
Path to your openvpn up script | |
openvpn_service_group | string | nogroup | Set the openvpn service group. | |
openvpn_service_user | string | nobody | Set the openvpn service user. | |
openvpn_status_version | int | 1, 2, 3 | 1 | Define the formatting of the openvpn-status.log file where are listed current client connection |
openvpn_topology | string | unset |
the "topology" keyword will be set in the server config with the specified value. |
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_client_config | Boolean | false | Set to true if enable client configuration directory | |
openvpn_client_config_dir | string | ccd | Path of client-config-dir |
|
openvpn_client_configs | dict | {} | Dict of settings custom client configs |
Set your own custom logrotate options.
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_log_dir | string | /var/log | Set location of openvpn log files. This parameter is a part of log-append configuration value. |
|
openvpn_log_file | string | openvpn.log | Set log filename. This parameter is a part of log-append configuration value. |
|
openvpn_logrotate_config | string | rotate 4 weekly missingok notifempty sharedscripts copytruncate delaycompress |
Configure logrotate script. |
This role pulls in a bunch of different packages. Override the names as necessary.
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
epel_package_name | string | epel-release | Name of the epel-release package to install from the package manager | |
iptables_persistent_package_name | string | iptables-persistent | Name of the iptables-persistent package to install from the package manager | |
iptables_services_package_name | string | iptables-services | Name of the iptables-services package to install from the package manager | |
openssl_package_name | string | openssl | Name of the openssl package to install from the package manager | |
openvpn_ldap_plugin_package_name | string | openvpn-auth-ldap | Name of the openvpn-auth-ldap package to install from the package manager | |
openvpn_package_name | string | openvpn | Name of the openvpn package to install from the package manager | |
python_firewall_package_name | string | python-firewall | Name of the python-firewall package to install from the package manager |
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
ldap | dict | Dictionary that contain LDAP configuration | ||
url | string | ldap://host.example.com | Address of you LDAP backend with syntax ldap[s]://host[:port] | |
anonymous_bind | string | False , True | False | This is not an Ansible boolean but a string that will be pushed into the configuration file. |
bind_dn | string | uid=Manager,ou=People,dc=example,dc=com | Bind DN used if "anonymous_bind" set to "False" | |
bind_password | string | mysecretpassword | Password of the bind_dn user | |
tls_enable | string | yes , no | no | Force TLS encryption. Not necessary with ldaps addresses |
tls_ca_cert_file | string | /etc/openvpn/auth/ca.pem | Path to the CA ldap backend. This must have been pushed before | |
tls_cert_file | string | Path to client authentication certificate | ||
tls_key_file | string | Path to client authentication key | ||
base_dn | string | ou=People,dc=example,dc=com | Base DN where the backend will look for valid user | |
search_filter | string | (&(uid=%u)(accountStatus=active)) | Filter the ldap search | |
require_group | string | False , True | This is not an Ansible boolean but a string that will be pushed into the configuration file. | |
group_base_dn | string | ou=Groups,dc=example,dc=com | Precise the group to look for. Required if require_group is set to "True" | |
group_search_filter | string | ((cn=developers)(cn=artists)) | Precise valid groups | |
verify_client_cert | string | none , optional , require | client-cert-not-required | In OpenVPN 2.4+ client-cert-not-required is deprecated. Use verify-client-cert instead. |
Does not depend on any other roles
Assume you've cloned this repository into the ansible-role-openvpn
directory. Navigate to the directory one level above this using ..
. In this parent directory, create a new playbook named ovpn.yaml
.
---
- hosts: all
gather_facts: true
become: true
roles:
- role: ansible-role-openvpn
openvpn_port: 4300
openvpn_sync_certs: true
clients:
- myclient1
- myclient2
Note: As the role will need to know the remote used platform (32 or 64 bits), you must set
gather_facts
totrue
in your play.
Each client listed in the playbook will have a separate configuration generated with unique certificates. Ensure you add as many clients as you have users.
SSH key-based authentication is assumed. If using password authentication, add -kK
to the command.
ansible-playbook -u USERNAME -i ip.add.re.ss, ./ovpn.yaml
Where:
- USERNAME — replace USERNAME with your SSH username.
- ip.add.re.ss — replace ip.add.re.ss with the IP address (or DNS name) of your OpenVPN server, followed by a comma.
Client configuration files are copied to the machine where you ran the ansible-playbook command. By default, you'll find them in the /tmp/ansible
directory.
More examples will be provided in future documentation, which will be linked here. Stay tuned!
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
Check out our contributing guide to get started.
Don't forget to give the project a star! Thanks again!
MIT
Initially written by Kyle Lexmond