OneLinersCommand workbench
Guides
Networking & DNS / Security

Deploy an OpenVPN server on Ubuntu 24.04 LTS

Build a routed full-tunnel OpenVPN service with Easy-RSA, an owned nftables policy, a tested encrypted client profile, and rehearsed certificate revocation.

75 min10 stepsChanges system stateRevision 2
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 10 steps completed
Goal

Provide certificate-authenticated remote access and IPv4 internet egress through a dedicated gateway without weakening server identity checks or leaving revocation untested.

Supported environments
  • Ubuntu Server 24.04 LTS
  • OpenVPN 2.6.x
  • Easy-RSA 3.x
Prerequisites
  • Recovery access Keep console access while changing forwarding and firewall rules.
  • Network plan Reserve a non-overlapping VPN subnet, public UDP port, and allowed private routes.
  • Stable endpoint Point a DNS name at the server public address.
  • Current-state backup Export firewall and sysctl configuration before the change.sudo nft list ruleset
Operating boundary

OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.

Full guide

What you will build

System
  • A certificate-authenticated OpenVPN 2.6 server on a dedicated Ubuntu 24.04 LTS host. The server listens on one public UDP port, assigns addresses from a private tunnel subnet, and rejects peers that do not present a client certificate signed by your certificate authority.
  • A deliberately owned nftables policy that permits management access from a named source network, accepts the OpenVPN listener, forwards authenticated tunnel traffic, and performs IPv4 masquerading for full-tunnel internet access.
  • A repeatable client lifecycle: issue one encrypted private key per person or device, assemble a restricted inline profile, test it from an external network, and revoke it by publishing a new certificate revocation list.
Observable outcome
  • The OpenVPN systemd instance is active, UDP port 1194 or your selected replacement is listening, and the journal contains an Initialization Sequence Completed message without certificate, cipher, route, or permission errors.
  • A test client receives an address from the planned VPN subnet, installs two def1 routes through the tunnel, resolves DNS through the selected resolver, and reaches the server-side tunnel address.
  • After a disposable certificate is revoked and the new CRL is installed, that profile cannot establish a new session while certificates that remain valid continue to connect normally.

Architecture

How the parts fit together

This guide uses routed TUN mode rather than Ethernet bridging. A client first reaches the server's public UDP socket and authenticates the server certificate. The server then validates the client's certificate against the same CA and its current CRL. Only after the TLS control channel succeeds does OpenVPN create encrypted data-channel keys and assign a tunnel address. Linux forwards that authenticated traffic from tun0 to the public interface, while nftables limits the allowed path and rewrites the private source address for internet egress.

Offline-capable certificate authoritySigns server and client identities. Its private key is the trust root and is not copied into OpenVPN profiles or the server configuration directory.
Ubuntu OpenVPN gatewayTerminates the encrypted tunnel, validates certificate purpose and revocation, assigns tunnel addresses, and exposes the tun0 routed interface.
nftables policyProtects the host input path, permits only intended forwarding from the VPN subnet, and applies source NAT for full-tunnel IPv4 egress.
External clientHolds one unique encrypted private key and profile, verifies that it reached the designated server, and installs routes supplied by the server.
  1. The client resolves the stable VPN hostname and sends a tls-crypt-protected OpenVPN control packet to the selected UDP port.
  2. The client verifies that the server certificate has TLS Web Server Authentication usage; the server requires a certificate with TLS Web Client Authentication usage.
  3. OpenVPN negotiates a mutually supported AEAD data cipher and assigns the client an address from the 10.8.0.0/24 example pool.
  4. The server pushes full-tunnel routes and a DNS resolver. Linux forwards accepted packets from tun0 to the public interface.
  5. nftables allows established replies and masquerades the private tunnel source address before the packet leaves the gateway.

Assumptions

  • The target is a dedicated or carefully isolated VPN gateway. Do not apply the example ruleset unchanged to a Docker host, Kubernetes node, hypervisor, router, or machine whose existing firewall is managed by UFW, firewalld, configuration management, or another nftables owner.
  • You have provider console, hypervisor console, or physical access throughout the firewall change. A second SSH session is open from the exact management network that will be placed in {{managementCidr}}.
  • The public interface has stable connectivity and the provider or upstream firewall forwards {{vpnPort}}/UDP to this host. The hostname in {{vpnHost}} already resolves to the public address clients will use.
  • The VPN address pool does not overlap the client's home network, corporate networks, container networks, cloud VPCs, or another VPN. The examples use 10.8.0.0/24 only after that collision check.
  • This procedure provides an IPv4 full tunnel. IPv6 requires an explicit address plan, OpenVPN IPv6 directives, forwarding policy, leak testing, and either routed IPv6 or a deliberate decision to disable it on the client.

Key concepts

Certificate authority (CA)
The trust root that signs every server and client certificate. Possession of the CA private key allows an operator or attacker to mint identities trusted by the VPN, so the key should be passphrase-protected and preferably kept away from the internet-facing gateway.
Control channel
The TLS-protected conversation used for peer authentication, capability negotiation, and creation of short-lived data-channel keys. tls-crypt additionally encrypts and authenticates the outer control packets before the TLS stack processes them.
Data channel
The encrypted path carrying user packets after authentication. OpenVPN 2.6 negotiates a cipher from data-ciphers; the server's first cipher also supported by the client wins.
TUN routed mode
A layer-3 virtual interface that transports IP packets. It avoids stretching Ethernet broadcasts across the internet and makes access policy, routes, and address ownership explicit.
Certificate revocation list (CRL)
A signed list of certificates that the CA no longer trusts. Revocation has no effect until a newly generated CRL is copied to the server path referenced by crl-verify and the running service reads it.
Masquerading
A form of source NAT used when the egress address may change. nftables replaces a packet's 10.8.0.0/24 source with the gateway's public-interface address so internet replies return through the VPN server.

Before you copy

Values used in this guide

{{vpnHost}}

Public DNS name clients use. It must resolve externally and should remain stable across server maintenance.

Example: vpn.example.net
{{vpnPort}}

Public UDP listener. The guide uses OpenVPN's conventional port unless your network policy assigns another.

Example: 1194
{{publicInterface}}

Linux interface carrying the default route and public traffic. Confirm it rather than assuming a legacy eth0 name.

Example: ens3
{{managementCidr}}

Trusted IPv4 source network allowed to reach SSH after the nftables policy becomes active.

Example: 203.0.113.32/28
{{sshPort}}

Actual SSH listening port that must remain reachable from the management network.

Example: 22
{{vpnNetwork}}

Network address passed to OpenVPN's server helper directive.

Example: 10.8.0.0
{{vpnNetmask}}

IPv4 netmask paired with the VPN network address.

Example: 255.255.255.0
{{vpnNetworkCidr}}

The same tunnel pool in CIDR notation for nftables source matching.

Example: 10.8.0.0/24
{{dnsServer}}

Resolver reachable through the completed tunnel. Confirm its privacy policy and availability before pushing it to clients.

Example: 1.1.1.1
{{clientName}}

Unique certificate identity for one device or operator. Use only letters, digits, underscore, and hyphen so it is safe in file names.

Example: laptop-alice

Security and production boundaries

  • The CA private key is more powerful than the server key. Keep it encrypted and back it up independently; for a production deployment, perform signing on an administrative workstation or offline CA rather than leaving the CA on the public gateway.
  • The example client profile contains its private key. File mode 0600 reduces accidental disclosure but does not protect a copied file, so the Easy-RSA client key should remain passphrase-protected and the profile must never be sent through public chat, tickets, or source control.
  • Replacing the complete nftables ruleset can disconnect administrators or break unrelated forwarding. This guide deliberately limits that action to a dedicated gateway and requires console access, a saved ruleset, syntax validation, and a second SSH session.
  • A full tunnel changes the client's effective network path and DNS. Test for DNS, IPv6, and application leaks from a disposable client before claiming that the VPN supplies a privacy or compliance boundary.
  • Revocation prevents future authentication but does not remotely erase a profile. Treat suspected theft as an incident: revoke, publish the CRL, inspect active sessions and logs, and rotate broader secrets if the CA or tls-crypt key may also be exposed.

Stop before continuing if

  • Stop before changing nftables if you cannot identify the current firewall owner, cannot obtain console access, or cannot explain every existing input and forwarding exception that would be replaced.
  • Stop if {{vpnNetworkCidr}} overlaps any route shown on the server or the external test client. Renumbering after issuing profiles is disruptive, while an overlap can silently route production traffic to the wrong network.
  • Stop if the server certificate and key do not match, if certificate purposes are wrong, or if the server key is readable by untrusted users. Do not weaken verification to make a broken PKI start.
  • Stop after any failed checkpoint. Preserve the journal and current ruleset, restore the previous known-good state, and diagnose the failed layer before proceeding to client distribution.
01

command

Install the supported packages

caution

Install OpenVPN, Easy-RSA, and nftables from Ubuntu repositories.

Why this step matters

Using Ubuntu's signed packages keeps the OpenVPN binary, systemd templates, Easy-RSA tooling, and nftables integration within the distribution's security-update path. Confirming the actual version immediately prevents the rest of the tutorial from silently relying on OpenVPN 2.6 behavior when an older repository, container image, or manually installed binary is taking precedence.

What to understand

apt update refreshes repository metadata but does not upgrade unrelated packages. apt install resolves the supported OpenVPN, Easy-RSA, and nftables packages for Ubuntu 24.04. The final version commands are evidence: save them with the change record because service names, available directives, and cipher behavior are version-sensitive.

Inspect existing packages and listeners before installation on a reused host. A previous OpenVPN package, snap, container, or hand-built /usr/local/sbin/openvpn can make the shell and systemd run different binaries. Resolve that ambiguity now instead of debugging it after certificates and firewall policy have changed.

System changes

  • Installs the OpenVPN daemon, Easy-RSA PKI scripts, nftables userspace tools, systemd service templates, package documentation, and their dependencies.
  • Does not start a configured VPN instance because /etc/openvpn/server/server.conf does not exist yet.

Syntax explained

apt update
Downloads current package indexes from configured repositories without installing an upgrade.
apt install --yes
Installs the named packages and accepts the package transaction after apt has displayed it.
openvpn --version
Prints the binary version and linked crypto capabilities used to validate the OpenVPN 2.6 baseline.
Command
sudo apt update && sudo apt install --yes openvpn easy-rsa nftables && openvpn --version | head -n 1 && nft --version
Example output / evidence
OpenVPN 2.6.15 x86_64-pc-linux-gnu
nftables v1.0.9 (Old Doc Yak #3)

Checkpoint: Supported tools are present

openvpn --version | head -n 1 && test -x /usr/share/easy-rsa/easyrsa && nft --version

Continue whenOpenVPN reports 2.6.x, the Easy-RSA executable exists, and nftables prints a version without an error.

Stop whenOpenVPN is older than 2.6, comes from an unexpected path, or apt reports a broken or partially configured package transaction.

If this step fails

apt cannot locate openvpn or easy-rsa.

Likely causeRepository metadata is stale, the standard Ubuntu repositories are disabled, or the machine is not actually running the declared Ubuntu release.

Safe checks
  • cat /etc/os-release
  • apt-cache policy openvpn easy-rsa nftables
  • grep -R --line-number '^Types\|^URIs\|^Suites' /etc/apt/sources.list.d

ResolutionRestore the appropriate official Ubuntu repository configuration and rerun apt update. Do not add an unreviewed third-party repository merely to continue.

Security notes

  • Review the apt transaction before accepting it on a production host and record whether a reboot is already pending from earlier maintenance.

Alternatives

  • If organizational policy requires an internal mirror, verify that it mirrors Ubuntu Noble security updates and does not pin OpenVPN below the documented baseline.

Stop conditions

  • Do not continue when the installed binary or package origin does not match the reviewed Ubuntu 24.04 environment.
02

command

Create the CA and server identity

caution

Build an isolated PKI. Protect the CA private key and never embed it in a client profile.

Why this step matters

Mutual certificate authentication gives every server and client a distinct identity and makes individual revocation possible. The CA is created before the server identity because the server certificate must be signed by a trust root that clients can verify. Easy-RSA assigns the server certificate the extended key usage expected by remote-cert-tls verification.

What to understand

make-cadir creates a writable Easy-RSA workspace owned by the administrator rather than modifying package files under /usr/share. init-pki starts a new certificate database. build-ca should prompt for a strong passphrase and a recognizable CA name; that passphrase protects the trust root at rest.

build-server-full server nopass creates a server certificate and an unencrypted server private key. An unattended systemd service cannot type a passphrase during boot, so the server key relies on strict file permissions and host security. This convenience must not be copied to the CA key.

System changes

  • Creates ~/openvpn-ca with the CA database, CA certificate, encrypted CA private key, server request, signed server certificate, and unencrypted server private key.
  • Does not yet expose PKI material to /etc/openvpn/server or start a network listener.

Syntax explained

make-cadir ~/openvpn-ca
Copies the distribution's Easy-RSA scripts and variables into an administrator-owned working directory.
./easyrsa init-pki
Creates a fresh PKI database. Running it against an existing PKI can be destructive and requires a separate migration plan.
./easyrsa build-ca
Creates the self-signed CA certificate and prompts for protection of the CA private key.
build-server-full server nopass
Generates and signs a certificate with server purpose; nopass leaves only the server key unencrypted for unattended startup.
Command
make-cadir ~/openvpn-ca && cd ~/openvpn-ca && ./easyrsa init-pki && ./easyrsa build-ca && ./easyrsa build-server-full server nopass
Example output / evidence
Certificate created at: pki/issued/server.crt

Checkpoint: CA and server certificate form one valid chain

cd ~/openvpn-ca && openssl verify -CAfile pki/ca.crt pki/issued/server.crt && openssl x509 -in pki/issued/server.crt -noout -subject -issuer -dates

Continue whenopenssl verify prints pki/issued/server.crt: OK, and the issuer matches the new CA with a validity period acceptable to your policy.

Stop whenVerification fails, an unexpected CA signed the certificate, the certificate is already near expiry, or the CA private key was created without the intended protection.

If this step fails

Easy-RSA reports that a PKI already exists.

Likely causeThe selected directory contains an earlier CA or an interrupted attempt. Reinitializing it could destroy issuance and revocation history.

Safe checks
  • cd ~/openvpn-ca && ./easyrsa show-ca
  • find ~/openvpn-ca/pki -maxdepth 2 -type f -printf '%M %p\n'

ResolutionIdentify and back up the existing PKI. Reuse it only if it is the intended authority; otherwise create a new, clearly named working directory rather than running init-pki over unknown state.

Security notes

  • Back up pki/ca.crt, pki/private/ca.key, index.txt, serial, and the revocation database together. A CA key without its database makes lifecycle management unreliable.

Alternatives

  • For production, generate the server request on the gateway, import and sign it on an offline CA, then return only the signed certificate and CA certificate.

Stop conditions

  • Stop if the directory contains an unidentified existing CA or if the CA key is accidentally disclosed in terminal output, shell history, backup logs, or a shared location.
03

command

Generate and install server cryptographic material

caution

Create DH parameters, the initial revocation list, and a tls-crypt key, then install only the gateway runtime material under restrictive permissions.

Why this step matters

OpenVPN needs the server identity, a trusted CA, revocation evidence, and control-channel protection in the runtime directory. Generating and installing them as one reviewed stage avoids a service that starts with only part of the intended policy. The CRL exists before the first client is issued, so revocation is not an afterthought.

What to understand

Easy-RSA gen-dh creates Diffie-Hellman parameters used by this TLS server configuration. gen-crl signs the initial empty revocation list. openvpn --genkey secret creates the shared tls-crypt key that clients will also embed in their profiles.

Public certificates, DH parameters, and the CRL are installed read-only at mode 0644. The server private key and tls-crypt key are installed at mode 0600. Absolute paths in server.conf make the runtime location explicit and independent of the service's working directory.

System changes

  • Creates pki/dh.pem, pki/crl.pem, and pki/tls-crypt.key in the CA workspace.
  • Creates /etc/openvpn/server and installs only the files required by the public gateway; the CA private key remains outside that directory.

Syntax explained

./easyrsa gen-dh
Generates DH parameters for the server configuration and may take noticeable time on a small VM.
./easyrsa gen-crl
Publishes the CA's current revocation state as a signed PEM CRL.
openvpn --genkey secret
Creates a static key in OpenVPN format for tls-crypt control-channel protection.
install -m 0600
Copies secret material with owner-only permissions in one operation instead of relying on a later chmod.
Command
cd ~/openvpn-ca && ./easyrsa gen-dh && ./easyrsa gen-crl && openvpn --genkey secret pki/tls-crypt.key && sudo install -d -m 0750 /etc/openvpn/server && sudo install -m 0644 pki/ca.crt pki/issued/server.crt pki/dh.pem pki/crl.pem /etc/openvpn/server/ && sudo install -m 0600 pki/private/server.key pki/tls-crypt.key /etc/openvpn/server/
Example output / evidence
DH parameters of size 2048 created at pki/dh.pem
CRL file: pki/crl.pem
600 server.key
600 tls-crypt.key

Checkpoint: Runtime material is complete and internally consistent

sudo find /etc/openvpn/server -maxdepth 1 -type f -printf '%m %f\n' | sort && sudo openssl verify -CAfile /etc/openvpn/server/ca.crt /etc/openvpn/server/server.crt && sudo openssl crl -in /etc/openvpn/server/crl.pem -noout -lastupdate -nextupdate

Continue whenAll six required files are present, secret keys show mode 600, certificate verification is OK, and the CRL has a current update window.

Stop whenA file is missing, a secret is group/world-readable, certificate verification fails, or the CRL cannot be parsed.

If this step fails

gen-dh appears to hang or is terminated.

Likely causeThe operation is CPU-intensive on a small VM, or the process was interrupted before pki/dh.pem was completed.

Safe checks
  • pgrep -af 'easyrsa|openssl.*dh'
  • test -s ~/openvpn-ca/pki/dh.pem && openssl dhparam -in ~/openvpn-ca/pki/dh.pem -check -noout

ResolutionAllow the active process to finish. If it was interrupted, remove only the incomplete dh.pem after confirming no process uses it, then rerun gen-dh.

Security notes

  • The tls-crypt key is shared by every profile in this design. Exposure does not reveal the CA key, but it removes the outer control-channel protection and requires profile-wide rotation.

Alternatives

  • OpenVPN 2.6 supports tls-crypt-v2 for client-specific wrapped keys; adopt it when per-client control-key lifecycle is worth the additional provisioning complexity.

Stop conditions

  • Do not copy pki/private/ca.key into /etc/openvpn/server or any client profile.
04

config

Write the routed server configuration

caution

Use modern subnet topology, mutual certificate-purpose verification, explicit revocation, AEAD negotiation, and full-tunnel IPv4 routes.

Why this step matters

The server configuration turns the PKI and address plan into enforceable runtime behavior. It explicitly selects modern routed topology, requires client-purpose certificates, checks the CRL, limits TLS versions, negotiates modern AEAD ciphers, and drops privileges after initialization rather than relying on historical defaults.

What to understand

topology subnet makes the 10.8.0.0/24 example behave like an ordinary routed subnet for modern clients. The server helper assigns 10.8.0.1 to the server and allocates the remaining pool. redirect-gateway def1 installs two more-specific half-default routes, which preserve the client's direct route to the VPN endpoint while sending ordinary IPv4 traffic through the tunnel.

data-ciphers is an ordered negotiation list, not a command to use every cipher. remote-cert-tls client checks client certificate purpose. crl-verify rejects newly connecting certificates listed in the installed CRL. user and group reduce runtime privilege after OpenVPN has opened protected files and configured the tunnel.

System changes

  • Creates /etc/openvpn/server/server.conf, defining the public listener, tunnel pool, pushed routes and DNS, certificate paths, cipher policy, keepalive behavior, and runtime privilege.

Syntax explained

proto udp4
Listens with IPv4 UDP transport, matching this guide's explicit IPv4 firewall and forwarding design.
topology subnet
Uses modern subnet addressing instead of the legacy net30 allocation model.
server {{vpnNetwork}} {{vpnNetmask}}
Enables multi-client server mode and allocates tunnel addresses from the reviewed pool.
push "redirect-gateway def1 bypass-dhcp"
Sends full-tunnel IPv4 routing to clients while preserving their local DHCP path.
remote-cert-tls client
Requires a connecting certificate with TLS Web Client Authentication purpose.
data-ciphers
Orders acceptable AEAD data ciphers; the first mutually supported value is selected.
tls-crypt
Encrypts and authenticates control-channel packets before the TLS exchange is exposed.
user nobody / group nogroup
Drops the daemon's user and group privilege after privileged initialization.
File /etc/openvpn/server/server.conf
Configuration
Fill variables0/4 ready

Values stay on this page and are never sent or saved.

port {{vpnPort}}
proto udp4
dev tun
topology subnet
server {{vpnNetwork}} {{vpnNetmask}}
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS {{dnsServer}}"
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh.pem
crl-verify /etc/openvpn/server/crl.pem
verify-client-cert require
remote-cert-tls client
tls-version-min 1.2
tls-crypt /etc/openvpn/server/tls-crypt.key
data-ciphers AES-256-GCM:AES-128-GCM:?CHACHA20-POLY1305
auth SHA256
user nobody
group nogroup
persist-key
persist-tun
keepalive 10 120
explicit-exit-notify 1
verb 3
Example output / evidence
Configuration saved at /etc/openvpn/server/server.conf with unresolved placeholders replaced.

Checkpoint: Configuration references the intended material and network

sudo grep -Ev '^(#|$)' /etc/openvpn/server/server.conf && sudo test -r /etc/openvpn/server/server.key && sudo test -r /etc/openvpn/server/crl.pem

Continue whenThe rendered configuration contains the planned values and every referenced credential file is readable by the initializing service.

Stop whenAny placeholder remains unresolved, the VPN pool overlaps a real route, or the configuration points at credentials from another PKI.

If this step fails

OpenVPN later reports an unrecognized option.

Likely causeThe running binary is older than the documented baseline, a directive was misspelled, or a configuration line was copied with typographic quotes.

Safe checks
  • openvpn --version | head -n 1
  • sudo journalctl -u openvpn-server@server -b --no-pager -n 100
  • sudo sed -n '=' /etc/openvpn/server/server.conf

ResolutionCorrect the exact directive against the OpenVPN 2.6 manual or restore the supported package. Do not use ignore-unknown-option to hide a security-relevant mistake.

Security notes

  • Do not add compression for ordinary VPN traffic. Compression can expose secrets when attacker-controlled and sensitive data share a compressed encrypted stream.

Alternatives

  • For split tunneling, remove redirect-gateway and push only the specific network prefixes clients are authorized to reach.

Stop conditions

  • Do not proceed while unresolved {{placeholders}} or an unreviewed redirect, script, plugin, management socket, or compatibility cipher remains in the file.
05

config

Enable forwarding deliberately

caution

Persist forwarding only when clients must reach networks beyond the VPN server.

Why this step matters

A working tunnel interface does not automatically make the host a router. Linux must be allowed to forward IPv4 packets between tun0 and the public interface. Keeping this setting in a dedicated sysctl file makes the change visible, reviewable, and removable during rollback.

What to understand

net.ipv4.ip_forward controls forwarding globally for the network namespace. The value 1 permits the kernel to consider routing a packet; it does not bypass nftables. The forward chain still decides which traffic is allowed.

sysctl --system reloads all system configuration files, so review its complete output for an unrelated invalid setting. Query the final key explicitly because the last loaded assignment wins.

System changes

  • Creates /etc/sysctl.d/99-openvpn-forward.conf and changes the live net.ipv4.ip_forward value to 1.

Syntax explained

net.ipv4.ip_forward = 1
Enables IPv4 routing in the current network namespace after sysctl applies the file.
sysctl --system
Loads sysctl configuration from the standard system directories in precedence order.
File /etc/sysctl.d/99-openvpn-forward.conf
Configuration
net.ipv4.ip_forward = 1
Command
sudo sysctl --system && sysctl net.ipv4.ip_forward
Example output / evidence
* Applying /etc/sysctl.d/99-openvpn-forward.conf ...
net.ipv4.ip_forward = 1

Checkpoint: IPv4 forwarding is active and persistent

sysctl net.ipv4.ip_forward && cat /etc/sysctl.d/99-openvpn-forward.conf

Continue whenBoth the live value and the dedicated file show net.ipv4.ip_forward = 1.

Stop whensysctl reports an error, a later file forces the value back to 0, or forwarding is prohibited by the host's security design.

If this step fails

The setting returns to 0 after sysctl --system or reboot.

Likely causeAnother later-loading sysctl file overrides it, or configuration management restores a conflicting policy.

Safe checks
  • grep -R --line-number 'net.ipv4.ip_forward' /etc/sysctl.conf /etc/sysctl.d /usr/lib/sysctl.d
  • journalctl -b -u systemd-sysctl --no-pager

ResolutionRemove the conflict from the authoritative configuration source or choose a filename and policy ordering approved for the environment. Do not repeatedly overwrite a managed file by hand.

Security notes

  • Forwarding expands the host's role from endpoint to router. The following firewall policy must be applied before untrusted clients are allowed to connect.

Alternatives

  • Use a dedicated network namespace or separate VPN appliance when the base host must not become a general-purpose router.

Stop conditions

  • Stop if another platform owns sysctl networking policy or if enabling forwarding would violate the host's isolation assumptions.
06

warning

Validate and activate the dedicated gateway firewall

danger

Stage a complete default-drop policy, preserve the previous file, validate before installation, and keep console plus a second SSH session open.

Why this step matters

The firewall is the enforcement boundary between an authenticated VPN identity and the rest of the host or internet. This example deliberately owns the complete nftables ruleset on a dedicated gateway: it preserves loopback and established traffic, limits SSH to one management CIDR, opens only the VPN UDP port, allows forwarding only from the tunnel pool to the public interface, and performs IPv4 masquerading.

What to understand

Write the proposed policy to /etc/nftables.conf.oneliners first. The apply command saves the existing persistent file, validates the complete candidate without changing live rules, installs it only after that check succeeds, and then enables nftables. Keep the console and a second SSH session open throughout.

flush ruleset makes this file authoritative. That is appropriate only under the dedicated-host assumptions stated above. The input and forward chains default to drop, while output defaults to accept. Established replies are accepted before narrow new-connection rules. NAT occurs only for packets whose source belongs to {{vpnNetworkCidr}} and whose egress interface is {{publicInterface}}.

System changes

  • Replaces the persistent /etc/nftables.conf after creating /etc/nftables.conf.before-openvpn.
  • Flushes the live nftables ruleset when the service loads the new file, establishes default-drop input and forward chains, and creates an IPv4 postrouting masquerade rule.

Syntax explained

nft --check --file
Parses and validates the complete candidate ruleset without applying it.
policy drop
Drops packets that reach the end of the input or forward chain without an explicit accept rule.
ct state established,related accept
Allows reply traffic for connections that the policy already permitted and related protocol flows tracked by conntrack.
ip saddr $management_net
Restricts new SSH connections to the reviewed IPv4 management source range.
masquerade
Rewrites VPN client source addresses to the current address of the public egress interface.
File /etc/nftables.conf.oneliners
Configuration
Fill variables0/5 ready

Values stay on this page and are never sent or saved.

#!/usr/sbin/nft -f

flush ruleset

define public_if = "{{publicInterface}}"
define management_net = {{managementCidr}}
define vpn_net = {{vpnNetworkCidr}}
define ssh_port = {{sshPort}}
define vpn_port = {{vpnPort}}

table inet oneliners_openvpn_filter {
  chain input {
    type filter hook input priority filter; policy drop;
    iifname "lo" accept
    ct state invalid drop
    ct state established,related accept
    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept
    iifname $public_if ip saddr $management_net tcp dport $ssh_port accept
    iifname $public_if udp dport $vpn_port accept
  }

  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state invalid drop
    ct state established,related accept
    iifname "tun0" oifname $public_if ip saddr $vpn_net accept
  }

  chain output {
    type filter hook output priority filter; policy accept;
  }
}

table ip oneliners_openvpn_nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    oifname $public_if ip saddr $vpn_net masquerade
  }
}
Command
sudo cp --archive /etc/nftables.conf /etc/nftables.conf.before-openvpn && sudo nft --check --file /etc/nftables.conf.oneliners && echo 'nftables syntax: valid' && sudo install -o root -g root -m 0644 /etc/nftables.conf.oneliners /etc/nftables.conf && sudo systemctl enable --now nftables && systemctl is-active nftables
Example output / evidence
nftables syntax: valid
active

Checkpoint: Policy is active without losing recovery access

sudo nft list ruleset && systemctl is-active nftables && ss -lnt | grep ':{{sshPort}}'

Continue whenThe named OpenVPN tables and rules are present, nftables is active, the SSH listener remains present, and a second management session still works.

Stop whenThe candidate fails validation, the interface or CIDR is wrong, the second SSH connection fails, or unrelated production forwarding disappears.

If this step fails

nft --check reports a syntax error.

Likely causeA placeholder was not replaced, an interface name contains an unexpected value, or the file was damaged while copying.

Safe checks
  • grep -n '{{\|}}' /etc/nftables.conf.oneliners
  • ip -brief link
  • sudo nft --check --debug=parser --file /etc/nftables.conf.oneliners

ResolutionCorrect the candidate and rerun the check. Because validation happens before install, leave the current live and persistent policy untouched until the candidate is clean.

SSH disconnects or a new management session cannot connect after activation.

Likely cause{{managementCidr}}, {{sshPort}}, or {{publicInterface}} does not match the real management path, or an upstream firewall uses a different source after NAT.

Safe checks
  • ip -brief address
  • ss -lntp
  • sudo nft monitor trace

ResolutionUse console access to restore /etc/nftables.conf.before-openvpn and restart nftables. Determine the actual observed source and listener before preparing a corrected candidate.

Security notes

  • Do not broaden SSH to 0.0.0.0/0 as a quick repair. Restore the prior ruleset through the console and correct the management path deliberately.

Alternatives

  • If an existing firewall manager owns the host, translate these narrow input, forward, and NAT requirements into that manager instead of loading this complete ruleset.

Stop conditions

  • Do not activate the candidate without a successful syntax check, console recovery, and a verified second SSH session from the intended management source.
07

command

Start and inspect the VPN

caution

Enable the instance and inspect first startup before distributing profiles.

Why this step matters

Starting the service is the first point where configuration, protected files, kernel TUN support, socket binding, and privilege dropping are exercised together. Inspect the journal immediately rather than treating systemd's active state alone as proof that the VPN is usable.

What to understand

openvpn-server@server maps to /etc/openvpn/server/server.conf in Ubuntu's packaged systemd template. enable records the intended boot behavior; --now starts the instance in the current boot. The status and journal provide separate evidence of process state and OpenVPN initialization.

The phrase Initialization Sequence Completed indicates that the daemon passed configuration and tunnel initialization. It does not yet prove external reachability, client authentication, forwarding, DNS, or revocation; those are tested later.

System changes

  • Enables openvpn-server@server for future boots, binds {{vpnPort}}/UDP, creates tun0, assigns the server tunnel address, and starts journal logging.

Syntax explained

systemctl enable --now
Enables the instance for boot and starts it immediately as one explicit operation.
openvpn-server@server
Selects the packaged server template and the server.conf instance name.
journalctl -u
Restricts diagnostic output to the exact OpenVPN systemd instance.
Command
sudo systemctl enable --now openvpn-server@server && systemctl --no-pager --full status openvpn-server@server
Example output / evidence
Active: active (running)

Checkpoint: The server initialized and is listening

systemctl is-active openvpn-server@server && sudo ss -lunp | grep ':{{vpnPort}}' && sudo journalctl -u openvpn-server@server -b --no-pager | tail -n 30

Continue whenThe unit is active, OpenVPN owns the intended UDP socket, tun0 has 10.8.0.1/24, and the journal reports Initialization Sequence Completed.

Stop whenThe unit restarts repeatedly, another process owns the port, tun0 is absent, or the journal contains certificate, CRL, cipher, permission, or route errors.

If this step fails

The unit fails with Cannot open TUN/TAP dev /dev/net/tun.

Likely causeThe TUN kernel device is unavailable in the VM or container, the module is not loaded, or the hosting platform forbids it.

Safe checks
  • ls -l /dev/net/tun
  • sudo modprobe tun
  • systemd-detect-virt

ResolutionEnable TUN support in the hypervisor or hosting platform and verify /dev/net/tun. Do not run a privileged container as a shortcut without reviewing the expanded host access.

Security notes

  • Do not distribute client profiles until the service, firewall, and journal all pass their checkpoints.

Alternatives

  • Keep the instance disabled during a change window by starting without enable; enable it only after the external client test succeeds.

Stop conditions

  • Stop on any repeating systemd restart or OpenVPN initialization warning instead of increasing restart limits or log verbosity indefinitely.
08

command

Issue a unique client certificate and restricted profile

caution

Generate one passphrase-protected identity per person or device and assemble a self-contained profile with only client-side material.

Why this step matters

A unique certificate per person or device creates an identity that can be audited and revoked without affecting every user. The inline profile packages the public CA, client certificate, encrypted client private key, and tls-crypt key into one restricted file while preserving server-purpose verification and modern cipher negotiation.

What to understand

build-client-full prompts for the CA passphrase to sign and for a client-key passphrase unless local Easy-RSA policy says otherwise. The profile intentionally omits nopass so copying the file alone is not sufficient to use the private key. Use a client name that maps to an asset or operator record, not a shared department identity.

The shell block writes fixed client directives and then appends reviewed PEM sections. sed starts the certificate at BEGIN CERTIFICATE so Easy-RSA's human-readable preamble is not embedded. The resulting file is mode 0600 and should move to the client over an authenticated, confidential administrative channel.

System changes

  • Adds one client request, encrypted private key, signed certificate, and issuance record to the CA workspace.
  • Creates ~/client-configs/{{clientName}}.ovpn containing the client's complete credential bundle and connection policy.

Syntax explained

build-client-full {{clientName}}
Generates a client-purpose key and certificate and records the issuance in the CA database.
remote-cert-tls server
Prevents a different valid client certificate from impersonating the VPN server.
auth-nocache
Requests that OpenVPN not retain interactive authentication material in virtual memory after use.
<ca>, <cert>, <key>, <tls-crypt>
Embeds the four referenced PEM or OpenVPN key files in a portable profile without external file paths.
chmod 0600
Limits local profile access to its owner because the file contains a private key.
Command
Fill variables0/3 ready

Values stay on this page and are never sent or saved.

cd ~/openvpn-ca && ./easyrsa build-client-full {{clientName}} && install -d -m 0700 "$HOME/client-configs" && { printf '%s\n' 'client' 'dev tun' 'proto udp4' 'remote {{vpnHost}} {{vpnPort}}' 'resolv-retry infinite' 'nobind' 'persist-key' 'persist-tun' 'remote-cert-tls server' 'auth-nocache' 'data-ciphers AES-256-GCM:AES-128-GCM:?CHACHA20-POLY1305' 'verb 3' '<ca>'; cat pki/ca.crt; printf '%s\n' '</ca>' '<cert>'; sed -ne '/-----BEGIN CERTIFICATE-----/,$p' "pki/issued/{{clientName}}.crt"; printf '%s\n' '</cert>' '<key>'; cat "pki/private/{{clientName}}.key"; printf '%s\n' '</key>' '<tls-crypt>'; cat pki/tls-crypt.key; printf '%s\n' '</tls-crypt>'; } > "$HOME/client-configs/{{clientName}}.ovpn" && chmod 0600 "$HOME/client-configs/{{clientName}}.ovpn" && stat -c '%a %n' "$HOME/client-configs/{{clientName}}.ovpn"
Example output / evidence
Certificate created at: pki/issued/laptop-alice.crt
600 /home/admin/client-configs/laptop-alice.ovpn

Checkpoint: Profile contains one matching client identity

cd ~/openvpn-ca && openssl verify -CAfile pki/ca.crt pki/issued/{{clientName}}.crt && openssl x509 -in pki/issued/{{clientName}}.crt -noout -subject -issuer -dates && stat -c '%a %n' ~/client-configs/{{clientName}}.ovpn

Continue whenCertificate verification is OK, the subject matches {{clientName}}, validity is acceptable, and the profile mode is 600.

Stop whenThe certificate name is shared, the key was created without the intended passphrase, verification fails, or the profile is readable by another user.

If this step fails

Easy-RSA says a certificate with this name already exists.

Likely causeThe identity was previously issued. Reusing the name would make audit and revocation ambiguous.

Safe checks
  • cd ~/openvpn-ca && ./easyrsa show-cert {{clientName}}
  • grep -F '/CN={{clientName}}' ~/openvpn-ca/pki/index.txt

ResolutionDetermine whether the existing certificate belongs to the same asset. Renew or revoke through the documented lifecycle, or choose a new unique identity; do not delete CA database rows by hand.

Security notes

  • Treat the generated .ovpn file as a secret even when its private key has a passphrase. Do not paste it into the OneLiners site, tickets, chat, or source control.

Alternatives

  • Use separate certificate and key files when the client platform can protect them in an OS keychain, TPM, smart card, or managed configuration profile.

Stop conditions

  • Do not distribute a profile until its certificate purpose, chain, name, validity, file permissions, and destination owner are verified.
09

verification

Test from an external network

read-only

Confirm tunnel address, intended routes, and connectivity from outside the server network.

Why this step matters

Testing from outside the server network proves the layers that local checks cannot: public DNS, upstream firewall, UDP reachability, mutual certificate authentication, pushed routes, DNS, forwarding, and NAT. A successful process on the server alone is not evidence that a remote operator can recover access.

What to understand

Install the test profile on a disposable Ubuntu client connected through a different network, such as a mobile hotspot. The packaged openvpn-client@ template reads /etc/openvpn/client/{{clientName}}.conf. Keep the client journal open during the first connection.

The route lookup should select tun0 for an internet address after redirect-gateway def1. The tunnel address should be inside {{vpnNetworkCidr}}, and 10.8.0.1 should respond as the server endpoint. DNS resolution must succeed after the pushed resolver is active.

System changes

  • Installs the restricted profile on the external test client, enables one OpenVPN client instance, creates tun0, and changes that client's IPv4 routing and DNS behavior while connected.

Syntax explained

openvpn-client@{{clientName}}
Maps the instance name to /etc/openvpn/client/{{clientName}}.conf on Ubuntu.
ip route get 1.1.1.1
Shows which interface and next hop the kernel would use without sending application data to that address.
getent ahosts example.com
Exercises the client's configured resolver path through the standard name-service switch.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo install -m 0600 "$HOME/client-configs/{{clientName}}.ovpn" "/etc/openvpn/client/{{clientName}}.conf" && sudo systemctl enable --now "openvpn-client@{{clientName}}" && systemctl is-active "openvpn-client@{{clientName}}" && ip -brief address show dev tun0 && ip route get 1.1.1.1 && ping -c 3 10.8.0.1 && getent ahosts example.com | head
Example output / evidence
active
tun0  UP  10.8.0.2/24
1.1.1.1 via 10.8.0.1 dev tun0 src 10.8.0.2
3 packets transmitted, 3 received
93.184.216.34 STREAM example.com

Checkpoint: Remote client uses the intended tunnel

systemctl is-active openvpn-client@{{clientName}} && ip -brief address show dev tun0 && ip route get 1.1.1.1 && ping -c 3 10.8.0.1 && getent ahosts example.com | head

Continue whenThe unit is active, tun0 has an address in {{vpnNetworkCidr}}, route lookup selects tun0, all three server-tunnel pings return, and DNS produces addresses.

Stop whenThe route still uses the local gateway, DNS stops working, IPv6 bypasses the intended policy, or access succeeds only from the server's own network.

If this step fails

The client times out without any corresponding server journal entry.

Likely causeThe hostname resolves incorrectly, the upstream or provider firewall blocks UDP, the port is not forwarded, or the client network blocks the selected transport.

Safe checks
  • getent ahosts {{vpnHost}}
  • sudo tcpdump -ni {{publicInterface}} udp port {{vpnPort}}
  • sudo ss -lunp | grep ':{{vpnPort}}'

ResolutionCorrect DNS or the upstream firewall and confirm packets arrive at the public interface. Do not weaken certificate verification when the TLS handshake never reached the server.

Security notes

  • A connected client now sends ordinary IPv4 traffic through the gateway. Do not perform the first test from a workstation whose critical access depends on an untested local route.

Alternatives

  • For cross-platform acceptance, repeat the same evidence collection on every supported client family after the Ubuntu command-line canary passes.

Stop conditions

  • Stop deployment if any traffic family or DNS path bypasses the intended tunnel and the security requirement is full-tunnel enforcement.
10

instruction

Exercise certificate revocation

caution

Revoke a disposable client, regenerate and deploy the CRL, then confirm the profile cannot reconnect.

Why this step matters

Issuance without a tested revocation path leaves the operator unable to remove a stolen or retired device safely. Revoking a disposable canary proves that the CA database, CRL generation, server installation path, service restart, and client rejection behavior work together before a real incident.

What to understand

revoke changes the certificate status in the CA database; gen-crl creates a newly signed list. Installing that CRL at /etc/openvpn/server/crl.pem publishes the decision to the gateway. The service restart ensures the running instance reads the new file.

The client certificate and key files may remain on disk for evidence, but they must not be reissued as valid. Compare the revoked certificate serial with the CRL and then attempt a new connection. An already established session should be disconnected during an actual compromise.

System changes

  • Marks {{clientName}} revoked in the CA database, replaces the generated and installed CRL, and restarts the OpenVPN server instance.
  • Prevents new TLS authentication by the revoked certificate while leaving other certificates under the same CA valid.

Syntax explained

./easyrsa revoke {{clientName}}
Records the certificate as revoked in the authoritative CA database.
./easyrsa gen-crl
Generates a signed CRL containing every currently revoked certificate serial.
install -m 0644 pki/crl.pem
Publishes the reviewed CRL atomically at the server path without exposing private key material.
systemctl restart
Forces the server instance to reopen configuration and revocation material.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

cd ~/openvpn-ca && ./easyrsa revoke {{clientName}} && ./easyrsa gen-crl && sudo install -o root -g root -m 0644 pki/crl.pem /etc/openvpn/server/crl.pem && sudo systemctl restart openvpn-server@server && systemctl is-active openvpn-server@server
Example output / evidence
Revoking Certificate ...
CRL file: pki/crl.pem
active

Checkpoint: Revoked serial is rejected while service remains healthy

openssl x509 -in ~/openvpn-ca/pki/issued/{{clientName}}.crt -noout -serial && openssl crl -in /etc/openvpn/server/crl.pem -noout -text | grep -A2 'Revoked Certificates' && systemctl is-active openvpn-server@server

Continue whenThe client serial appears in the CRL, the server remains active, and a fresh connection using that profile fails with a revocation-related verification message.

Stop whenThe serial is absent, the wrong CA produced the CRL, the server fails to restart, or other valid canary clients can no longer connect.

If this step fails

The CRL shows no revoked certificates after revoke.

Likely causegen-crl ran in a different Easy-RSA workspace or the revoke operation did not update the intended CA database.

Safe checks
  • grep -F '/CN={{clientName}}' ~/openvpn-ca/pki/index.txt
  • openssl x509 -in ~/openvpn-ca/pki/issued/{{clientName}}.crt -noout -issuer -serial
  • openssl crl -in ~/openvpn-ca/pki/crl.pem -noout -issuer -lastupdate

ResolutionReturn to the authoritative CA workspace, confirm the certificate row is marked revoked, regenerate the CRL, and verify issuer and serial before installation.

Security notes

  • If the CA private key is suspected compromised, individual revocation is insufficient. Build a new PKI and rotate every server and client identity.

Alternatives

  • For routine retirement, revoke after a replacement identity is proven. For active compromise, revoke immediately and terminate the current session before issuing replacement credentials.

Stop conditions

  • Do not declare revocation complete until a real new handshake with the revoked profile is rejected and a separate valid canary still succeeds.

Finish line

Verification checklist

Service healthsystemctl is-active openvpn-server@serverReturns active.
Listening socketss -lunp | grep ':1194'Shows OpenVPN on the intended UDP address.
Client tunnelip address show dev tun0Client receives an address from the planned subnet.

Recovery guidance

Common problems and safe checks

The systemd instance exits immediately and the journal reports that a certificate, key, DH file, CRL, or tls-crypt file cannot be opened.

Likely causeA path in server.conf does not match the installed PKI layout, a file was copied under the wrong name, or permissions prevent the process from opening material during initialization.

Safe checks
  • sudo journalctl -u openvpn-server@server -b --no-pager -n 100
  • sudo namei -l /etc/openvpn/server/server.key /etc/openvpn/server/crl.pem
  • sudo openssl x509 -in /etc/openvpn/server/server.crt -noout -subject -issuer -dates

ResolutionCorrect the path or reinstall the intended file from the reviewed PKI. Keep the private key at mode 0600 and public certificates or the CRL readable as required. Do not replace a missing file with material from an unrelated CA.

The client repeatedly reaches the server but fails with VERIFY ERROR, unsupported certificate purpose, or no shared cipher.

Likely causeThe client trusts a different CA, the profile contains the wrong peer certificate, the certificate was issued with the wrong Easy-RSA type, the certificate is expired or revoked, or old client cipher settings cannot negotiate with OpenVPN 2.6.

Safe checks
  • openssl x509 -in pki/issued/server.crt -noout -text | grep -A4 'Extended Key Usage'
  • openssl verify -CAfile pki/ca.crt pki/issued/server.crt
  • openvpn --show-ciphers | grep -E 'AES-256-GCM|AES-128-GCM|CHACHA20-POLY1305'

ResolutionIssue a correctly typed certificate from the intended CA and keep remote-cert-tls verification enabled. Align data-ciphers on supported modern values; add a legacy fallback only after documenting the old peer and accepting the reduced security.

The tunnel connects and receives 10.8.0.x, but internet traffic or DNS does not work.

Likely causeIPv4 forwarding is disabled, the forward chain does not match tun0 and the real egress interface, masquerading is absent, the provider blocks forwarding, or the pushed resolver is not reachable through the selected route.

Safe checks
  • sysctl net.ipv4.ip_forward
  • sudo nft list ruleset
  • ip route get 1.1.1.1
  • sudo tcpdump -ni tun0 -c 20

ResolutionFix the first failing layer rather than adding broad accept rules. Confirm packets enter tun0, match the intended forward rule, leave the actual public interface, and receive replies. Select a resolver that is reachable after the full-tunnel routes are installed.

A revoked client still reconnects successfully.

Likely causeThe certificate was revoked in a different PKI, gen-crl was not run, the new crl.pem was not installed at the server's crl-verify path, or an already active session was never terminated.

Safe checks
  • openssl crl -in /etc/openvpn/server/crl.pem -noout -lastupdate -nextupdate
  • openssl x509 -in pki/issued/{{clientName}}.crt -noout -serial
  • sudo journalctl -u openvpn-server@server --since '-10 min' --no-pager

ResolutionGenerate the CRL from the CA that issued the certificate, install it atomically at the configured path, and restart the instance. Disconnect an existing session during the incident and confirm a new handshake is rejected for the revoked serial.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Use split tunneling by removing redirect-gateway and pushing only reviewed private routes when clients should keep ordinary internet traffic on their local connection.
  • Use WireGuard when a smaller static-key configuration and explicit peer routing better match the environment. OpenVPN remains useful when certificate lifecycle, mature cross-platform clients, or TLS-based policy is required.
  • Use a managed or distribution-integrated firewall policy instead of replacing /etc/nftables.conf when the host already belongs to UFW, firewalld, cloud-init, or configuration management. Translate the same allowlist and forwarding intent into that single authoritative system.

Operate it safely

  • Move CA signing away from the public gateway, maintain encrypted offline backups of the CA database and keys, and document a tested recovery procedure before issuing production identities.
  • Monitor service state, certificate and CRL expiry, repeated authentication failures, connected-client count, and unexpected changes to the listening socket or nftables ruleset.
  • Schedule certificate renewal and tls-crypt key rotation. Test the overlap period with a canary client so rotation does not create a simultaneous outage for every remote administrator.
  • Build a second recovery path before making the VPN the only route to critical infrastructure. A VPN cannot repair itself when the gateway, DNS, upstream firewall, or certificate authority is unavailable.

Reference

Frequently asked questions

Why use UDP instead of TCP?

OpenVPN carries application traffic that may already use TCP. UDP avoids nesting one congestion-controlled TCP connection inside another, which can amplify retransmission and head-of-line blocking. TCP transport remains useful where a network permits only TCP, but it should be an intentional compatibility choice.

Why does the client profile verify remote-cert-tls server?

Trusting the CA alone proves only that a certificate was signed by that CA. Certificate-purpose verification prevents another valid client certificate from impersonating the server and is an important part of mutual TLS identity separation.

Should the CA be created with nopass?

Not for a production trust root. The server key usually needs unattended startup and is commonly generated without an interactive passphrase, but the CA key is used only during issuance and revocation and should be encrypted. Protect the CA passphrase separately from its key backup.

Can this ruleset be added to a Docker or Kubernetes host?

Not unchanged. Those platforms create and depend on forwarding, NAT, and bridge rules of their own. Use a dedicated VPN gateway or merge the intended OpenVPN rules into the platform's authoritative firewall design after testing every workload and recovery path.

Recovery

Rollback

Disable the VPN and restore the previous network policy.

  1. Stop and disable openvpn-server@server.
  2. Restore, validate, and reload the saved firewall configuration.
  3. Remove the forwarding sysctl file and run sudo sysctl --system.
  4. Retain the PKI securely until every issued profile is retired.

Evidence

Sources and review

Verified 2026-07-24Review due 2026-10-22
Ubuntu: install OpenVPNofficialOpenVPN 2.6 manualofficialEasy-RSA documentationofficialnftables NAT documentationofficial