Initial Startup

The first boot takes a few minutes longer than a stock AMI because the gateway provisions itself on first launch: the easy-rsa PKI is generated, a server certificate is issued, the OpenVPN service is configured against the VPC's network layout, and the runtime services are started. Subsequent reboots are fast — these one-time steps are skipped.

Server Connection

Using SSM

All of our products are designed to support AWS Systems Manager (SSM) right out of the box. We strongly believe in security, and the fewer ports exposed to the public, the better. The SSM service provided by AWS perfectly aligns with this approach.

When you need to connect to an instance, opt for connecting through the Session Manager. Once you've gained access, execute the command sudo su ec2-user to switch to the user account where all of our tools are located. This ensures you have the appropriate permissions and access to the necessary resources.

Using SSH

SSH is also available, but is not the recommended path. The AMI ships without any pre-installed SSH keys: you must attach a key pair at instance launch and open port 22 on the security group yourself. The default user is ec2-user. Prefer SSM Session Manager whenever possible — it requires no inbound ports and produces an audit trail.

User Management

Creating a User

To create a new VPN user, all parameters except --auto-renew are required:

sudo ov_user_add --first-name John \
                 --last-name Doe \
                 --email john.doe@example.com \
                 --traffic all \
                 --expiration-date 2026-12-31 \
                 --creation-reason "Remote access for Q4 project"

For routing only remote network traffic via the VPN:

sudo ov_user_add --first-name Jane \
                 --last-name Smith \
                 --email jane.smith@example.com \
                 --traffic partial \
                 --expiration-date 2026-06-30 \
                 --creation-reason "Access to private subnet" \
                 --auto-renew yes

Required Parameters

  • --first-name: User's first name
  • --last-name: User's last name
  • --email: User's email address
  • --traffic: Traffic routing mode (all or partial)
    • all: Routes all traffic through the VPN
    • partial: Routes only traffic to the remote network through the VPN
  • --expiration-date: Profile expiration date in YYYY-MM-DD format
  • --creation-reason: Justification for creating the profile (for audit purposes)

Optional Parameters

  • --auto-renew: yes or no (default no). When yes, the gateway automatically issues and emails a fresh profile before this one expires. See Automatic Renewal below.

The .ovpn profile is emailed to the address specified — see Email Delivery below for the required SES setup.

Deleting a User

To delete a user, specify their email and traffic type:

sudo ov_user_delete --email john.doe@example.com --traffic all

This revokes the user's certificate and updates the Certificate Revocation List (CRL).

ov_user_delete identifies the user by their (email, traffic) pair, not by a single certificate. It revokes every certificate that pair can still connect with, adds them to the CRL, and restarts OpenVPN so the revocation takes effect immediately. There is no way to target one individual certificate — the command removes the whole user. Once it completes, that user can no longer connect with any profile they were ever issued.

Listing All Users

To view all VPN users:

sudo ov_user_list

Each row shows the user's email, traffic mode, full name, expiration date, and creation timestamp.

Listing Expired Users

To view all users with expired profiles:

sudo ov_user_list_expired

This command is report-only: it identifies profiles whose expiration date has passed, but does not revoke or disable them. Expired profiles continue to work until you explicitly run ov_user_delete. Use this command as part of a regular review cadence to renew or remove stale accounts.

Resending a Profile

If a user loses the email or never received it, re-deliver the existing profile to its registered address — no reissue, no new certificate:

sudo ov_user_resend --email john.doe@example.com --traffic all

The .ovpn on disk is sent as-is; the user database is not modified.

Automatic Renewal

New in v1.1.0. Certificates are issued with a hard expiration date (--expiration-date). Auto-renewal lets the gateway issue and email a fresh profile before the current one expires, so users never experience a gap — and the operator does not have to track expiry dates by hand.

Renewal is opt-in per profile. A daily background check looks for profiles that have auto-renew enabled and that fall inside the renewal window (10 days by default). For each one, the gateway issues a fresh profile and emails it to the registered address before the current one lapses. The recipient simply imports the new profile they receive.

If a profile cannot be renewed, the existing one is left untouched and the profile is flagged so you can investigate it with ov_user_audit --stuck.

Enabling Auto-Renew

At creation time, pass --auto-renew yes to ov_user_add.

For an existing profile, toggle it without reissuing the certificate:

sudo ov_user_auto_renew --email john.doe@example.com --traffic all --enable

Disable it the same way:

sudo ov_user_auto_renew --email john.doe@example.com --traffic all --disable

Auditing Renewals

ov_user_audit provides read-only lenses over the user database (it never writes):

LensShows
--summaryOne-line counts (active, expiring, revoked, renewed).
--expiring [--days N]Active profiles expiring within N days (default 10).
--renewed [--since <date>] [--until <date>]Profiles renewed in the given window.
--revoked [--since <date>]Revoked profiles.
--history --email <addr> [--traffic <all|partial>]Full lifecycle of one profile.
--stuckProfiles whose auto-renewal failed, with the last log line for each.

Example:

sudo ov_user_audit --expiring --days 14

Backup and Restore

From v1.0.3 the gateway ships two CLI tools — ov_backup and ov_restore — that capture and re-apply every operator-unique piece of state in a single command. Use them to migrate to a new instance, to roll forward onto a new AMI version, or to keep a disaster-recovery archive off the box.

Creating a backup

SSH into the gateway and run:

sudo ov_backup

No flags, no arguments. The command writes a single timestamped archive to the ec2-user home directory, prints a summary so you can sanity-check the contents, and prints ready-to-paste scp commands for copying it off the box.

The archive holds every private key and credential on the gateway. Copy it off with one of the printed scp commands, store it encrypted at rest, and never email it, put it in chat, or commit it to git.

Restoring onto a new gateway

Launch a fresh v1.1.0+ instance from the AMI and wait for first boot to complete (the OpenVPN service is up). Then copy the archive up and run:

sudo ov_restore backup-<hostname>-<timestamp>.tar.gz

To validate an archive without touching disk first, run sudo ov_restore --dry-run <file> — it checks the archive and exits.

ov_restore is all-or-nothing. It validates the archive before touching the disk and refuses to proceed on a tampered, incomplete, or invalid archive — if validation fails, the gateway is left untouched. On success it restores your state, restarts the VPN, and prints a restore summary in the same shape as the backup summary, so you can diff the two and confirm nothing was lost.

After a restore

Move the Elastic IP from the old gateway to the new one before users reconnect. Existing .ovpn profiles bake in the public IP at issue time: same IP and every existing profile keeps working with no client-side change; different IP and every profile must be reissued with ov_user_add.

Verify:

sudo ov_user_list

The user list must match the old gateway. Then connect a test client to confirm the new gateway is serving the restored certificates. Once verified, stop and terminate the old instance.

Caveats

  • Run as root. Both commands refuse to run without sudo.
  • Restore forward, not backward. A v1.1.0 gateway can restore a backup taken on v1.1.0 or on any older v1.0.x gateway — older backups are upgraded automatically. You cannot restore a v1.1.0 backup onto an older gateway.
  • The archive is a master secret. Treat it like a root password — if it ever leaks, rotate the CA and reissue every user.
  • No automatic schedule. ov_backup runs on demand only. If you want periodic snapshots, schedule it via cron or Systems Manager and copy the resulting file to S3 (with KMS encryption).

Email Delivery

When you create a user, their .ovpn profile is emailed automatically via Amazon SES. Configure SES credentials in /opt/0x4447/configs/email.conf:

AWS_REGION=us-east-1
SMTP_USERNAME=REPLACE_WITH_YOUR_SES_SMTP_USERNAME
SMTP_PASSWORD=REPLACE_WITH_YOUR_SES_SMTP_PASSWORD
FROM_EMAIL=no_reply@example.com
ENVIRONMENT_NAME=VPN Server

Notes:

  • SMTP_USERNAME and SMTP_PASSWORD are SES SMTP credentials, not your AWS access key/secret. Generate them in the SES console: Account dashboard → SMTP settings → Create SMTP credentials.
  • FROM_EMAIL must be a verified identity in the SES region you configured (a verified address or a verified domain).
  • While your SES account is in sandbox mode, recipient addresses must also be verified. Request production access in the SES console to send to arbitrary recipients.
  • ENVIRONMENT_NAME appears in the email body to help recipients identify which gateway issued the profile.

VPN Clients

Linux split-tunnel (partial) profiles

A partial profile is designed to route only traffic destined for your AWS network through the VPN, leaving normal internet traffic on the user's local connection (split-tunnel). On Windows, macOS, iOS, Android, and the Linux OpenVPN command-line client, imported partial profiles behave exactly that way.

Linux desktops that import the profile into NetworkManager (Ubuntu, Fedora, Debian, Mint, Pop!_OS, and most GNOME/KDE distributions) have an important caveat. By default NetworkManager sends all traffic — including normal internet traffic — through the VPN, turning a partial profile into a full tunnel. This is long-standing NetworkManager behaviour, not a fault in the profile: NetworkManager silently ignores the split-tunnel routing directives inside the .ovpn file. The identical profile run with the OpenVPN command-line client (sudo openvpn --config profile.ovpn) split-tunnels correctly.

For full-tunnel (all) profiles this makes no difference. For partial profiles on NetworkManager, tell NetworkManager not to use the VPN as the default route:

Command line:

nmcli connection modify <connection-name> ipv4.never-default yes
nmcli connection up <connection-name>

Replace <connection-name> with the name shown by nmcli connection show (it matches the profile you imported).

GUI (GNOME / KDE network settings):

  1. Open the VPN connection's settings.
  2. Go to the IPv4 tab.
  3. Open Routes….
  4. Tick Use this connection only for resources on its network.
  5. Save, then reconnect the VPN.

This change affects only Linux NetworkManager clients using partial profiles. Full-tunnel (all) profiles, and every other platform, need no change.

Troubleshooting

The OpenVPN service runs as openvpn@0x4447-udp.service.

GoalCommand
Check service statussudo systemctl status openvpn@0x4447-udp
Tail live logssudo journalctl -u openvpn@0x4447-udp -f
Restart the servicesudo systemctl restart openvpn@0x4447-udp
Inspect generated server configsudo cat /etc/openvpn/udp-server.conf

The server config (/etc/openvpn/udp-server.conf) is regenerated on every boot. Do not edit it directly.

DNS Routing (advanced)

By default the gateway pushes its own resolver (the VPC DNS) to every connected client, so all DNS queries flow through the VPN. Most customers do not need to change this.

For hybrid networks — where some domains live in AWS Route 53 Private Hosted Zones, and others must resolve against on-prem DNS — you can configure per-domain DNS routing (split-DNS). Clients send queries for the listed suffixes through the VPN's DNS, and use their own local resolver for everything else.

Configuring Domain Routes

Edit /opt/0x4447/configs/dns.conf:

VPN_DNS_DOMAIN_ROUTES="internal.acme.com corp.acme.local"

Apply the change without rebooting:

sudo /opt/0x4447/lib/dns_routes_apply.sh

This applies the new routes immediately. Already-connected clients pick them up on their next reconnect.

Caveats

  • Only meaningful for --traffic partial profiles. Full-tunnel (all) profiles route every packet through the VPN, including DNS, so per-domain routing has no effect there.
  • Client compatibility: OpenVPN Connect 3.x (Windows, macOS, iOS, Android) and Tunnelblick honour DOMAIN-ROUTE. NetworkManager-openvpn honours it when paired with systemd-resolved. Older clients silently fall back to using the pushed DNS for every query.
  • Empty value = default behaviour. If VPN_DNS_DOMAIN_ROUTES="", no per-domain routes are pushed.

IAM Requirements

The instance profile attached to the gateway must allow:

  • ec2:DescribeRouteTables
  • AmazonSSMManagedInstanceCore (AWS-managed policy) — required if you want to connect via SSM Session Manager.

Features

  • Unlimited Users: Supports an unlimited number of users, ensuring scalability for your growing needs.
  • Flexible Traffic Routing: Route all or specific parts of your traffic through the VPN, giving you complete control over your data flow.
  • Multi-CIDR VPC Support: Secondary VPC CIDR blocks are auto-detected and pushed to clients — no manual configuration needed.
  • VPC Peering Support: CIDRs of peer VPCs reachable via active peering connections are auto-discovered and pushed to clients, so users transparently reach resources across peered VPCs.

Use Cases

Access to Private AWS Subnets:

AWS networks contain subnets, which can be public or private. Private subnets are secure areas not directly accessible from the public internet, housing critical servers and data. The most secure method to access these private subnets is through a VPN deployed in a public subnet. This setup encrypts your connection, allowing safe access to the private subnet and its servers as if they were local to your network, ensuring data security and integrity within AWS environments.

Secured Internet Connection for Remote Employees:

Beyond accessing private resources, this VPN also safeguards the internet connections of remote employees. By routing their traffic through the VPN, all online activities are encrypted, protecting company-sensitive data from potential interception by third parties. This ensures that employees can work securely from any location, preserving confidentiality and data integrity.

Inter-Office Connectivity:

For organizations with multiple office locations, maintaining a secure and reliable inter-office network is crucial. Our VPN solution facilitates the creation of a secure virtual network overlaying the public internet, linking different office locations. This secure network tunnel ensures that data exchanged between offices is encrypted and protected from external threats, enabling seamless collaboration and resource sharing across geographical locations.

Compliance and Data Protection:

Businesses subject to stringent regulatory requirements can benefit significantly from our VPN solution. By encrypting data in transit and providing secure access controls, the VPN helps organizations comply with data protection laws and industry standards. This is particularly important for sectors like healthcare, finance, and legal, where data privacy is paramount.

FAQ

Is there a limit on the number of users?

No. The gateway supports an unlimited number of VPN profiles. Each user you create with ov_user_add gets their own certificate and .ovpn profile.

Why does my partial (split-tunnel) profile route everything through the VPN on Linux?

This happens only on Linux desktops that import the profile into NetworkManager, which claims the default route by default. Run nmcli connection modify <connection-name> ipv4.never-default yes (or tick Use this connection only for resources on its network in the IPv4 settings) and reconnect. See VPN Clients → Linux split-tunnel profiles for full details. Windows, macOS, iOS, Android, and the OpenVPN command-line client are unaffected.

What is the difference between all and partial traffic mode?

all routes every packet from the client through the VPN (full tunnel) — useful for securing all of a remote employee's internet traffic. partial routes only traffic destined for your AWS network through the VPN (split tunnel), leaving normal internet traffic on the user's local connection.

Does a profile stop working once its expiration date passes?

Yes. --expiration-date is the certificate's hard cryptographic expiry — it is stamped into the certificate's notAfter field at issue time. Once that date passes, the OpenVPN server rejects the certificate during the TLS handshake and the profile can no longer connect. No operator action is required for the profile to stop working.

What does not happen automatically is revocation. The certificate is not added to the CRL and the database row still shows the profile as activeov_user_list_expired is a report-only convenience to surface these. To revoke a still-valid profile before its expiry date (so it stops working immediately), run ov_user_delete, which revokes the certificate and updates the CRL. To remove the stale database row after natural expiry, also use ov_user_delete.

How does auto-renewal work and is it on by default?

Auto-renewal is opt-in per profile and off by default. Enable it with --auto-renew yes at creation, or ov_user_auto_renew --enable later. A daily job issues and emails a fresh profile before the current one expires (within a 10-day window). See Automatic Renewal.

A user lost their email — do I have to recreate the profile?

No. Run ov_user_resend --email <addr> --traffic <all|partial> to re-deliver the existing profile. No new certificate is issued and the user database is not modified.

How do I move the gateway to a new instance or AMI version without losing users?

Run ov_backup on the old gateway, launch a fresh instance from the AMI, copy the archive up, and run ov_restore. Then move the Elastic IP to the new instance before users reconnect so existing profiles keep working. See Backup and Restore.

Why does the first boot take longer than a normal AMI?

On first launch the gateway generates its PKI, issues a server certificate, configures OpenVPN against your VPC layout, and starts the services. This is one-time work — subsequent reboots skip it and are fast.

How do I connect without opening SSH?

Use AWS Systems Manager Session Manager — no inbound ports required. Connect, then run sudo su ec2-user. The instance profile needs the AmazonSSMManagedInstanceCore policy. See Server Connection → Using SSM.

Why are my profile emails not being delivered?

Email is sent via Amazon SES. Confirm /opt/0x4447/configs/email.conf holds valid SES SMTP credentials (not your AWS access key), that FROM_EMAIL is a verified SES identity, and — if your SES account is still in sandbox mode — that the recipient address is verified too. See Email Delivery.