Ap
Networking AWS

accel-ppp VPN Server 1.14.0 on AWS User Guide

| Product: accel-ppp VPN Server 1.14.0 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and verifying accel-ppp VPN Server 1.14.0 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other VPN, proxy and remote access servers in the listing are described on the listing's guide hub.

accel-ppp is a fast, multithreaded PPP access server for Linux. It terminates remote access VPN sessions (SSTP, L2TP and PPPoE), authenticates users against a local secrets file or RADIUS, and hands each client an address from a pool. This image configures it as a remote access VPN endpoint using SSTP: PPP carried inside TLS on TCP 443, which the built-in Windows VPN client and sstp-client on Linux speak, and which passes through most firewalls because it looks like HTTPS.

The image builds accel-ppp 1.14.0, the current upstream release, from its published source tarball (checksum pinned) with no out-of-tree kernel modules. Everything it needs from the kernel (PPP, PPPoE, L2TP) ships in Ubuntu's own kernel modules package, so unattended security upgrades can move the kernel safely.

What is on the image:

  • accel-ppp 1.14.0 (accel-ppp.service) with SSTP on TCP 443 and a self-signed TLS certificate generated on your instance's first boot
  • One VPN user with a random 24-character password, created on first boot in /etc/accel-ppp/chap-secrets
  • MS-CHAPv2 and CHAP authentication only (PAP and MS-CHAPv1 are not loaded); only listed users can connect
  • The accel-ppp management CLI on 127.0.0.1:2001 only, protected by a per-instance password, and the accel-cli wrapper
  • A self-test, accel-ppp-selftest, that logs in over SSTP from the instance itself
  • No metadata access: accel-ppp.service cannot reach the instance metadata service, and VPN clients cannot route to it
  • L2TP and PPPoE built in as documented opt-ins (Steps 11 and 12)

Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3

Security posture

  • No default credential. The image ships with no VPN user, no rendered configuration, no management password and no TLS key. First boot generates the VPN username and password, the management CLI password, an L2TP tunnel secret and the SSTP certificate for this instance only, and writes them to /root/accel-ppp-credentials.txt (root only).
  • Strong authentication only. Clients authenticate with MS-CHAPv2 (Windows) or CHAP. Cleartext PAP and MS-CHAPv1 are not loaded, and any-login=0 means only users in chap-secrets get a session. Wrong passwords and unknown users are refused by the server.
  • TLS 1.2 and 1.3 only on port 443. A request that is not SSTP gets no HTTP answer.
  • The listing security group opens SSH only. Port 443 stays closed until you open it to your own client address ranges (Step 7).
  • Management stays local. The accel-ppp CLI listens on 127.0.0.1:2001 only and needs this instance's CLI password; the telnet CLI is off. sudo accel-cli reads the password from the root-only configuration and passes it on standard input, so it never appears in a process listing or in /var/log/auth.log.
  • Private endpoint by default. IP forwarding is off and no NAT rule exists, so a connected client reaches this instance only, not your VPC or the internet, until you choose to make it a gateway (Step 10). That also means a VPN client cannot reach the instance metadata service through the tunnel.
  • No SSRF to instance credentials. accel-ppp.service carries an IPAddressDeny rule for the metadata addresses (169.254.169.254, fd00:ec2::254, 168.63.129.16), and the AMI is registered IMDSv2 only.
  • Fails closed. accel-ppp starts only after first boot has written this instance's configuration and a ready marker, and a start-up check refuses to run it without the per-instance password, user and certificate. If first boot cannot finish, accel-ppp stays stopped and first boot tries again on the next boot.
  • Durable across kernel upgrades. accel-ppp's optional out-of-tree drivers (IPoE, VLAN monitor, PPTP accelerator) are not built, so nothing breaks when Ubuntu moves the kernel.
  • Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.

Prerequisites

  1. An AWS account and permission to launch EC2 instances
  2. An EC2 key pair in the Region you launch in
  3. The public IP ranges your VPN clients connect from

Recommended instance type: m5.large. A VPN endpoint for a small team runs comfortably on t3.small or larger.

Connecting to your instance

Version Operating system SSH user
accel-ppp VPN Server 1.14.0 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. Open the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  2. Once the subscription is active, choose Launch your software.
  3. Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose accel-ppp VPN Server 1.14.0 on Ubuntu 24.04, then choose your Region.
  4. Pick an instance type (m5.large recommended; the software charge is $0.04 per vCPU per hour) and your key pair.
  5. Security group: the listing's default group allows SSH (22) only. Restrict it to your own IP address. You open TCP 443 to your VPN clients in Step 7.
  6. Choose your VPC and a public subnet (or attach an Elastic IP later), leave the metadata defaults (the image already requires IMDSv2), then choose Launch.

Option B: AWS CLI

Run this on your own workstation. It creates a security group that allows SSH from your management address and SSTP from your client ranges only, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR ranges with your own:

SG=$(aws ec2 create-security-group --group-name accel-ppp-vpn \
  --description "accel-ppp SSTP VPN" --vpc-id vpc-0123456789abcdef0 \
  --query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22  --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr <your-client-cidr>
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --instance-type m5.large \
  --key-name my-key-pair \
  --security-group-ids "$SG" \
  --subnet-id subnet-0123456789abcdef0 \
  --associate-public-ip-address \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=accel-ppp-vpn}]'

You do not need --metadata-options: the AMI already makes IMDSv2 required.

Step 2: Connect and read the connection details

Connect as ubuntu with the key pair you chose:

ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>

First boot finishes within a minute of launch. It creates this instance's VPN user and passwords, issues the SSTP certificate for the instance's public address and public DNS name, and starts accel-ppp. The details are in /root/accel-ppp-credentials.txt, readable only by root. This command prints everything except the three secret lines:

sudo grep -vE '^(VPN_PASSWORD|CLI_PASSWORD|L2TP_SECRET)=' /root/accel-ppp-credentials.txt
# accel-ppp 1.14.0 VPN server - generated on first boot by accel-ppp-firstboot.service
# These values are unique to this instance. Nothing here was baked into the image.

SERVER_ADDRESS=18.206.117.157
SSTP_PORT=443
VPN_USERNAME=vpnhbirhrec
SSTP_CERT_SHA256=84:BF:BF:19:06:58:FD:14:2B:98:2F:8A:70:FB:E4:3D:A1:A1:E8:C3:6C:EF:37:D6:00:53:38:F3:F2:A0:E4:F1
VPN_GATEWAY=10.60.0.1
VPN_POOL=10.60.0.2-10.60.0.254

# Connect with SSTP (Windows built-in VPN client, sstp-client on Linux) to SERVER_ADDRESS on TCP 443 after you open
# TCP 443 in the security group to your client address ranges only. The certificate is self-signed and unique to
# this instance: trust /etc/accel-ppp/ssl/sstp-cert.pem on the client or check SSTP_CERT_SHA256.
# Add users:        /etc/accel-ppp/chap-secrets, then sudo systemctl restart accel-ppp
# Management CLI:   sudo accel-cli show sessions   (loopback only; the CLI password is read from the config)
# Self-test:        sudo accel-ppp-selftest
# Guide:            https://www.cloudimg.co.uk/guides/accel-ppp-vpn-server-1-14-0-on-ubuntu-24-04-aws/

Print the VPN password itself only when you need it, with sudo sed -n 's/^VPN_PASSWORD=//p' /root/accel-ppp-credentials.txt.

Step 3: Confirm accel-ppp is running

accel-ppp.service is active, first boot has completed, and accel-ppp listens on TCP 443 on every interface (SSTP) and on 127.0.0.1:2001 (management CLI). Nothing listens on UDP 1701 (L2TP is off by default):

systemctl is-active accel-ppp.service accel-ppp-firstboot.service
/usr/local/sbin/accel-pppd --version
sudo ss -Htlnp '( sport = :443 or sport = :2001 )'
echo "UDP 1701 listeners: $(sudo ss -Hulnp 'sport = :1701' | wc -l)"
active
active
accel-ppp 1.14.0
LISTEN 0      10       0.0.0.0:443  0.0.0.0:* users:(("accel-pppd",pid=1031,fd=21))
LISTEN 0      1      127.0.0.1:2001 0.0.0.0:* users:(("accel-pppd",pid=1031,fd=20))
UDP 1701 listeners: 0

Step 4: Run the self-test

The shipped self-test connects to 127.0.0.1:443 exactly as a VPN client would: it checks that the certificate served is this instance's own, runs the SSTP handshake, PPP negotiation and CHAP authentication with the first-boot user, gets an address from the pool, pings the VPN gateway and opens a TCP connection across the tunnel, and confirms that the instance metadata service is not reachable through the tunnel. It then proves that a wrong password and an unknown user are refused, and that the management CLI answers only to the right password. No password is printed:

sudo accel-ppp-selftest
TLS TLSv1.3 on 127.0.0.1:443 serves this instance's certificate (SHA-256 84bfbf190658fd14)
SSTP + CHAP-MD5 login accepted for user vpnhbirhrec
tunnel up: client address 10.60.0.2 from the pool, gateway 10.60.0.1
data plane: the gateway 10.60.0.1 answered a ping across the tunnel
control: TCP to 10.60.0.1:443 through the tunnel is answered (SYN-ACK)
metadata: 169.254.169.254:80 is unreachable from the VPN client (no answer in 6 s; IP forwarding is off)
management CLI: 'show sessions' lists the session of vpnhbirhrec
refused as expected: the right user with a wrong password (CHAP code 4 from the server)
refused as expected: an unknown user (CHAP code 4 from the server)
management CLI: answers with this instance's password, silent for a wrong one
SELFTEST_OK SSTP login, tunnel, refusals and CLI proven

Step 5: Use the management CLI

accel-cli runs one accel-ppp CLI command with this instance's CLI password. show stat gives the daemon's counters and show sessions lists connected users (empty until a client connects):

sudo accel-cli show stat | head -4
sudo accel-cli show sessions
uptime: 0.00:00:39
cpu: 0%
mem(rss/virt): 7928/243736 kB
core:
 ifname | username | calling-sid | ip | type | comp | state | uptime 
--------+----------+-------------+----+------+------+-------+--------

Other useful commands are sudo accel-cli help, sudo accel-cli terminate if ppp0 (disconnect one session) and sudo accel-cli show sessions ifname,username,ip,uptime.

Step 6: Check the certificate your clients will see

The SSTP certificate is self-signed and unique to this instance. It names the instance's public IPv4 address, its private address and its public DNS name:

sudo openssl x509 -in /etc/accel-ppp/ssl/sstp-cert.pem -noout -subject -ext subjectAltName -enddate
sudo openssl x509 -in /etc/accel-ppp/ssl/sstp-cert.pem -noout -fingerprint -sha256
subject=CN = 18.206.117.157
X509v3 Subject Alternative Name: 
    IP Address:18.206.117.157, IP Address:172.31.86.50, DNS:ec2-18-206-117-157.compute-1.amazonaws.com
notAfter=Oct 23 16:13:31 2036 GMT
sha256 Fingerprint=84:BF:BF:19:06:58:FD:14:2B:98:2F:8A:70:FB:E4:3D:A1:A1:E8:C3:6C:EF:37:D6:00:53:38:F3:F2:A0:E4:F1

A client must connect with one of those names. Copy the certificate (never the key) to each client, for example from your workstation with ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip> sudo cat /etc/accel-ppp/ssl/sstp-cert.pem > sstp-cert.pem (the directory is root only; the certificate itself is public, the key never leaves the instance). If the public address changes (the instance was stopped without an Elastic IP), or you want clients to use your own DNS name, re-issue the certificate as shown in Step 13.

Step 7: Open SSTP to your clients and connect

Add an inbound rule for TCP 443 to the instance's security group, only from the public ranges your clients connect from:

aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 443 --cidr <your-client-cidr>

Windows 10 and 11 (built-in VPN client). Import sstp-cert.pem into Local Computer > Trusted Root Certification Authorities (Manage computer certificates > Import). Then go to Settings > Network & internet > VPN > Add VPN: VPN provider Windows (built-in), server name or address = SERVER_ADDRESS from Step 2 (or the public DNS name), VPN type Secure Socket Tunneling Protocol (SSTP), sign-in info User name and password, with VPN_USERNAME and the VPN password. A self-signed certificate has no revocation list, so Windows may refuse it with a revocation error; Microsoft's documented setting for that case is the NoCertRevocationCheck DWORD set to 1 under HKLM\SYSTEM\CurrentControlSet\Services\Sstpsvc\Parameters, or use a certificate from a public CA instead (Step 13).

Linux (sstp-client). Put the credential in the client's /etc/ppp/chap-secrets (<VPN_USERNAME> * <password> *, mode 0600) so it never appears on a command line, then connect with the copied certificate:

sudo sstpc --ca-cert sstp-cert.pem --save-server-route --user <VPN_USERNAME> <SERVER_ADDRESS> \
  require-mschap-v2 noauth noipdefault nodefaultroute nobsdcomp nodeflate

Each client gets an address from 10.60.0.2-10.60.0.254 and reaches the server at 10.60.0.1. With the default settings a client reaches the VPN server only; to route clients onward to your VPC or the internet, see Step 10.

Step 8: Add VPN users

Users live in /etc/accel-ppp/chap-secrets (root only), one per line: <username> * <password> *. This block creates a user vpnuser2 with a random password inside a root shell (so the password never appears on a sudo command line or in /var/log/auth.log), tells accel-ppp to re-read its files, and logs the new user in with the self-test, which takes the password on standard input:

sudo bash -c 'F=/etc/accel-ppp/chap-secrets; KEEP="$(grep -v "^vpnuser2[[:space:]]" "$F")"
PW="$(openssl rand -base64 33 | tr -dc A-Za-z0-9 | cut -c1-24)"
printf "%s\nvpnuser2\t*\t%s\t*\n" "$KEEP" "$PW" > "$F"
systemctl reload accel-ppp
sleep 2
printf "%s\n" "$PW" | accel-ppp-selftest --user vpnuser2 | tail -1'
sudo awk '!/^#/ && NF {print $1}' /etc/accel-ppp/chap-secrets
SELFTEST_OK user vpnuser2
vpnhbirhrec
vpnuser2

Give the user their password through a secure channel. To remove a user, delete their line and run sudo systemctl reload accel-ppp. For more than a handful of users, point accel-ppp at your RADIUS server instead (the radius module is built in; see man accel-ppp.conf).

Step 9: Metadata access is blocked

accel-ppp.service carries an IPAddressDeny rule for the metadata addresses, and IP forwarding is off, so neither the daemon nor a VPN client can reach the instance metadata service (the self-test in Step 4 proved the client side):

systemctl show -p IPAddressDeny accel-ppp.service
sysctl net.ipv4.ip_forward
IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
net.ipv4.ip_forward = 0

Step 10: Route clients onward (optional)

By default a client reaches the VPN server only. To make the instance a gateway into your VPC or to the internet, turn on forwarding, NAT the client pool out of the instance's interface, and keep VPN clients away from the metadata service: drop forwarded traffic to 169.254.169.254, and set the instance's metadata hop limit to 1 so a forwarded request can never get an IMDSv2 token. Replace ens5 with your interface name (ip route show default):

echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/90-vpn-gateway.conf
sudo sysctl -p /etc/sysctl.d/90-vpn-gateway.conf
sudo iptables -I FORWARD -d 169.254.169.254 -j DROP
sudo iptables -t nat -A POSTROUTING -s 10.60.0.0/24 -o ens5 -j MASQUERADE
sudo apt-get install -y iptables-persistent && sudo netfilter-persistent save
aws ec2 modify-instance-metadata-options --instance-id <instance-id> --http-tokens required --http-put-response-hop-limit 1

Add a dns1= and dns2= line under [dns] in /etc/accel-ppp/accel-ppp.conf (for example the VPC resolver, the VPC base address plus two) if clients should resolve names through the VPN, then sudo systemctl restart accel-ppp.

Step 11: L2TP (optional, not encrypted on its own)

L2TP is built in but off. L2TP without IPsec carries PPP in clear text, so use it only on private networks or inside your own IPsec or site-to-site tunnel; the Windows, macOS and iOS built-in L2TP clients require IPsec and will not connect to it. To enable it, add l2tp under [modules], open UDP 1701 to the peers that need it, and restart. The per-instance tunnel secret is already in the [l2tp] section (L2TP_SECRET in the credentials file):

sudo sed -i '/^\[modules\]$/a l2tp' /etc/accel-ppp/accel-ppp.conf
sudo systemctl restart accel-ppp
sudo ss -Hulnp 'sport = :1701'

Step 12: PPPoE (optional, needs your own layer-2 network)

PPPoE is a layer-2 protocol, and an AWS VPC does not carry PPPoE frames between instances, so it is only useful over a layer-2 path you provide (for example a GRE or VXLAN tunnel to your site). The pppoe module is loaded with no interface. Bind it at run time with sudo accel-cli pppoe interface add <ifname>, or permanently with an interface=<ifname> line under [pppoe] followed by sudo systemctl restart accel-ppp.

Step 13: Re-issue the certificate (Elastic IP or your own DNS name)

accel-ppp-sstp-cert replaces the self-signed certificate. With no argument it reads the current public address and DNS name from the instance metadata; with arguments it uses the names you give (for example your own DNS name). It restarts accel-ppp, updates SSTP_CERT_SHA256 in the credentials file and prints the new fingerprint, so re-import the new certificate on your clients afterwards:

sudo accel-ppp-sstp-cert | head -1
sudo accel-ppp-selftest | tail -1
SSTP certificate re-issued for IP:18.206.117.157,DNS:ec2-18-206-117-157.compute-1.amazonaws.com,IP:172.31.86.50
SELFTEST_OK SSTP login, tunnel, refusals and CLI proven

To use a certificate from a public or internal CA instead, copy its full chain to /etc/accel-ppp/ssl/sstp-cert.pem and its key to /etc/accel-ppp/ssl/sstp-key.pem (mode 0600, owner root), then sudo systemctl restart accel-ppp. Clients that trust that CA need no certificate import.

Step 14: How the fail-closed start works

accel-ppp starts only once first boot has written /var/lib/cloudimg/accel-ppp-ready, and every start runs a check that refuses to start it without this instance's CLI password, VPN user file and SSTP key and certificate, or with a file left readable by other users:

systemctl cat accel-ppp.service | grep -E '^(ConditionPathExists|ExecStartPre)='
sudo stat -c '%a %U:%G %n' /etc/accel-ppp/accel-ppp.conf /etc/accel-ppp/chap-secrets /etc/accel-ppp/ssl/sstp-key.pem /root/accel-ppp-credentials.txt
ConditionPathExists=/var/lib/cloudimg/accel-ppp-ready
ExecStartPre=/usr/local/sbin/accel-ppp-preflight
600 root:root /etc/accel-ppp/accel-ppp.conf
600 root:root /etc/accel-ppp/chap-secrets
600 root:root /etc/accel-ppp/ssl/sstp-key.pem
600 root:root /root/accel-ppp-credentials.txt

Step 15: Security recommendations

  • Keep TCP 443 open only to the ranges your clients connect from, and TCP 22 only to your management addresses.
  • Give every person their own VPN user (Step 8) and remove users who leave; or use RADIUS for central control.
  • Prefer a certificate your clients already trust (Step 13) over importing the self-signed one.
  • If you route clients onward (Step 10), keep the metadata drop rule and the hop limit of 1.
  • Leave unattended security upgrades on, and reboot after kernel updates. accel-ppp needs no rebuild after a kernel update.
  • Session and authentication logs are in /var/log/accel-ppp/ (no passwords are logged).

Support and licensing

accel-ppp is free software maintained by the accel-ppp project and its contributors, distributed under the GNU General Public License, version 2 (GPL-2.0); the licence is in /usr/local/share/doc/accel-ppp/COPYING. This image builds the unmodified 1.14.0 release. cloudimg provides the packaging, the secure defaults, the per-instance credentials and certificate, the metadata block, the fail-closed start, the self-test and 24/7 support.

cloudimg is not affiliated with or endorsed by the accel-ppp project. accel-ppp is used here only to identify the software. Windows is a trademark of Microsoft Corporation.

For help with deployment or configuration, email support@cloudimg.co.uk or visit cloudimg support.