Add Docker-based E2E testing (#1320)

### Summary
- Add automated end-to-end testing using Docker to verify the installation script works across 18 Linux distributions
- Add Oracle Linux 9 support to the installation script
- Drop support for EOL distributions (Debian 8/9/10, CentOS 7, Ubuntu 16.04) 
- Disable Digital Ocean droplets based end-to-end tests, let's use docker from now on

### Changes
**New test infrastructure:**
- `test/Dockerfile.server` - Multi-OS server image with `BASE_IMAGE` build arg
- `test/Dockerfile.client` - Ubuntu 24.04 client for connectivity testing
- `test/server-entrypoint.sh` - Runs install script, verifies files exist, asserts iptables NAT rules, starts OpenVPN
- `test/client-entrypoint.sh` - Connects to VPN, verifies tun0 interface, pings gateway
- `docker-compose.yml` - Orchestrates server + client with shared volume
- `.github/workflows/docker-test.yml` - CI matrix testing 18 OS variants
- `.github/workflows/test.yml` - Removed push/PR triggers, now manual only for DO tests
- `Makefile` - Local testing commands (`make test`, `make test-ubuntu-24.04`, etc.)

**Distributions tested (18 total):**
| Family | Versions |
|--------|----------|
| Ubuntu | 18.04, 20.04, 22.04, 24.04 |
| Debian | 11, 12 |
| Fedora | 40, 41 |
| Rocky Linux | 8, 9 |
| AlmaLinux | 8, 9 |
| Oracle Linux | 8, 9 |
| Amazon Linux | 2, 2023 |
| CentOS Stream | 9 |
| Arch Linux | latest |
This commit is contained in:
Stanislas
2025-12-07 12:27:41 +01:00
committed by GitHub
parent 94c1af2b5d
commit a3389c126c
10 changed files with 655 additions and 46 deletions

166
.github/workflows/docker-test.yml vendored Normal file
View File

@@ -0,0 +1,166 @@
---
on:
push:
workflow_dispatch:
name: Docker Test
permissions:
contents: read
jobs:
docker-test:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os:
- name: ubuntu-18.04
image: ubuntu:18.04
- name: ubuntu-20.04
image: ubuntu:20.04
- name: ubuntu-22.04
image: ubuntu:22.04
- name: ubuntu-24.04
image: ubuntu:24.04
- name: debian-11
image: debian:11
- name: debian-12
image: debian:12
- name: centos-stream-9
image: quay.io/centos/centos:stream9
- name: fedora-40
image: fedora:40
- name: fedora-41
image: fedora:41
- name: rocky-8
image: rockylinux:8
- name: rocky-9
image: rockylinux:9
- name: almalinux-8
image: almalinux:8
- name: almalinux-9
image: almalinux:9
- name: archlinux
image: archlinux:latest
- name: oraclelinux-8
image: oraclelinux:8
- name: oraclelinux-9
image: oraclelinux:9
- name: amazonlinux-2
image: amazonlinux:2
- name: amazonlinux-2023
image: amazonlinux:2023
name: ${{ matrix.os.name }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build server image
run: |
docker build \
--build-arg BASE_IMAGE=${{ matrix.os.image }} \
-t openvpn-server \
-f test/Dockerfile.server .
- name: Build client image
run: docker build -t openvpn-client -f test/Dockerfile.client .
- name: Create Docker network
run: docker network create --subnet=172.28.0.0/24 vpn-test
- name: Create shared volume
run: docker volume create shared-config
- name: Start OpenVPN server
run: |
docker run -d \
--name openvpn-server \
--hostname openvpn-server \
--cap-add=NET_ADMIN \
--device=/dev/net/tun:/dev/net/tun \
--sysctl net.ipv4.ip_forward=1 \
--network vpn-test \
--ip 172.28.0.10 \
-v shared-config:/shared \
openvpn-server
- name: Wait for server installation and startup
run: |
echo "Waiting for OpenVPN server to install and start..."
for i in {1..60}; do
if docker exec openvpn-server pgrep openvpn > /dev/null 2>&1; then
echo "OpenVPN server is running!"
break
fi
echo "Waiting... ($i/60)"
sleep 5
# Show logs for debugging
docker logs --tail 20 openvpn-server 2>&1 || true
done
# Final check
if ! docker exec openvpn-server pgrep openvpn > /dev/null 2>&1; then
echo "ERROR: OpenVPN server failed to start"
docker logs openvpn-server
exit 1
fi
- name: Verify client config was generated
run: |
docker run --rm -v shared-config:/shared alpine \
ls -la /shared/
docker run --rm -v shared-config:/shared alpine \
cat /shared/client.ovpn
- name: Start OpenVPN client and run tests
run: |
docker run \
--name openvpn-client \
--hostname openvpn-client \
--cap-add=NET_ADMIN \
--device=/dev/net/tun:/dev/net/tun \
--network vpn-test \
--ip 172.28.0.20 \
-v shared-config:/shared:ro \
openvpn-client &
# Wait for tests to complete (look for success message)
for i in {1..60}; do
if docker logs openvpn-client 2>&1 | grep -q "ALL TESTS PASSED"
then
echo "Tests passed!"
exit 0
fi
if docker logs openvpn-client 2>&1 | grep -q "FAIL:"; then
echo "Tests failed!"
docker logs openvpn-client
exit 1
fi
echo "Waiting for tests... ($i/60)"
sleep 2
done
echo "Timeout waiting for tests"
docker logs openvpn-client
exit 1
- name: Show server logs
if: always()
run: docker logs openvpn-server 2>&1 || true
- name: Show client logs
if: always()
run: docker logs openvpn-client 2>&1 || true
- name: Cleanup
if: always()
run: |
docker stop openvpn-server openvpn-client 2>/dev/null || true
docker rm openvpn-server openvpn-client 2>/dev/null || true
docker network rm vpn-test 2>/dev/null || true
docker volume rm shared-config 2>/dev/null || true

View File

@@ -1,8 +1,7 @@
# DigitalOcean E2E tests (manual trigger only)
# Primary CI testing is now done via Docker in docker-test.yml
# This workflow is kept for real-world VM testing when needed
on:
push:
branches:
- master
- ci
workflow_dispatch:
name: Test

136
Makefile Normal file
View File

@@ -0,0 +1,136 @@
.PHONY: test test-build test-up test-down test-logs test-clean
# Run the full test suite
test: test-build test-up
@echo "Waiting for tests to complete..."
@for i in $$(seq 1 60); do \
if docker logs openvpn-client 2>&1 | grep -q "ALL TESTS PASSED"; then \
echo "✓ Tests passed!"; \
$(MAKE) test-down; \
exit 0; \
fi; \
if docker logs openvpn-client 2>&1 | grep -q "FAIL:"; then \
echo "✗ Tests failed!"; \
docker logs openvpn-client; \
$(MAKE) test-down; \
exit 1; \
fi; \
echo "Waiting... ($$i/60)"; \
sleep 2; \
done; \
echo "Timeout waiting for tests"; \
$(MAKE) test-down; \
exit 1
# Build test containers
test-build:
BASE_IMAGE=$(BASE_IMAGE) docker compose build
# Start test containers
test-up:
docker compose up -d
# Stop and remove test containers
test-down:
docker compose down -v --remove-orphans
# View logs
test-logs:
docker compose logs -f
# View server logs only
test-logs-server:
docker logs -f openvpn-server
# View client logs only
test-logs-client:
docker logs -f openvpn-client
# Full cleanup
test-clean: test-down
docker rmi openvpn-install-openvpn-server openvpn-install-openvpn-client 2>/dev/null || true
docker volume prune -f
# Interactive shell into server container
test-shell-server:
docker exec -it openvpn-server /bin/bash
# Interactive shell into client container
test-shell-client:
docker exec -it openvpn-client /bin/bash
# Test specific distributions
test-ubuntu-18.04:
$(MAKE) test BASE_IMAGE=ubuntu:18.04
test-ubuntu-20.04:
$(MAKE) test BASE_IMAGE=ubuntu:20.04
test-ubuntu-22.04:
$(MAKE) test BASE_IMAGE=ubuntu:22.04
test-ubuntu-24.04:
$(MAKE) test BASE_IMAGE=ubuntu:24.04
test-debian-11:
$(MAKE) test BASE_IMAGE=debian:11
test-debian-12:
$(MAKE) test BASE_IMAGE=debian:12
test-fedora-40:
$(MAKE) test BASE_IMAGE=fedora:40
test-fedora-41:
$(MAKE) test BASE_IMAGE=fedora:41
test-rocky-8:
$(MAKE) test BASE_IMAGE=rockylinux:8
test-rocky-9:
$(MAKE) test BASE_IMAGE=rockylinux:9
test-almalinux-8:
$(MAKE) test BASE_IMAGE=almalinux:8
test-almalinux-9:
$(MAKE) test BASE_IMAGE=almalinux:9
test-oracle-8:
$(MAKE) test BASE_IMAGE=oraclelinux:8
test-oracle-9:
$(MAKE) test BASE_IMAGE=oraclelinux:9
test-amazon-2:
$(MAKE) test BASE_IMAGE=amazonlinux:2
test-amazon-2023:
$(MAKE) test BASE_IMAGE=amazonlinux:2023
test-arch:
$(MAKE) test BASE_IMAGE=archlinux:latest
test-centos-stream-9:
$(MAKE) test BASE_IMAGE=quay.io/centos/centos:stream9
# Test all distributions (runs sequentially)
test-all:
$(MAKE) test-ubuntu-18.04
$(MAKE) test-ubuntu-20.04
$(MAKE) test-ubuntu-22.04
$(MAKE) test-ubuntu-24.04
$(MAKE) test-debian-11
$(MAKE) test-debian-12
$(MAKE) test-fedora-40
$(MAKE) test-fedora-41
$(MAKE) test-rocky-8
$(MAKE) test-rocky-9
$(MAKE) test-almalinux-8
$(MAKE) test-almalinux-9
$(MAKE) test-oracle-8
$(MAKE) test-oracle-9
$(MAKE) test-amazon-2
$(MAKE) test-amazon-2023
$(MAKE) test-arch
$(MAKE) test-centos-stream-9

View File

@@ -132,26 +132,23 @@ export PASS="1"
The script supports these Linux distributions:
| | Support |
| ---------------------- | ------- |
| AlmaLinux 8 | ✅ |
| Amazon Linux 2 | ✅ |
| Amazon Linux >= 2023.6 | ✅ |
| Arch Linux | ✅ |
| CentOS 7 | ✅ |
| CentOS Stream >= 8 | ✅ 🤖 |
| Debian >= 10 | ✅ 🤖 |
| Fedora >= 35 | ✅ 🤖 |
| Oracle Linux 8 | ✅ |
| Rocky Linux 8 | ✅ |
| Ubuntu >= 18.04 | ✅ 🤖 |
| | Support |
| ------------------ | ------- |
| AlmaLinux >= 8 | ✅ 🤖 |
| Amazon Linux 2 | ✅ 🤖 |
| Amazon Linux 2023 | ✅ 🤖 |
| Arch Linux | ✅ 🤖 |
| CentOS Stream >= 8 | ✅ 🤖 |
| Debian >= 11 | ✅ 🤖 |
| Fedora >= 40 | ✅ 🤖 |
| Oracle Linux >= 8 | ✅ 🤖 |
| Rocky Linux >= 8 | ✅ 🤖 |
| Ubuntu >= 18.04 | ✅ 🤖 |
To be noted:
- The script is regularly tested against the distributions marked with a 🤖 only.
- It's only tested on `amd64` architecture.
- It should work on older versions such as Debian 8+, Ubuntu 16.04+ and previous Fedora releases. But versions not in the table above are not officially supported.
- It should also support versions between the LTS versions, but these are not tested.
- The script requires `systemd`.
## Fork

55
docker-compose.yml Normal file
View File

@@ -0,0 +1,55 @@
---
services:
openvpn-server:
build:
context: .
dockerfile: test/Dockerfile.server
args:
BASE_IMAGE: ${BASE_IMAGE:-}
container_name: openvpn-server
hostname: openvpn-server
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
sysctls:
- net.ipv4.ip_forward=1
volumes:
- shared-config:/shared
networks:
vpn-test:
ipv4_address: 172.28.0.10
healthcheck:
test: ["CMD", "pgrep", "openvpn"]
interval: 5s
timeout: 3s
retries: 30
openvpn-client:
build:
context: .
dockerfile: test/Dockerfile.client
container_name: openvpn-client
hostname: openvpn-client
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- shared-config:/shared:ro
networks:
vpn-test:
ipv4_address: 172.28.0.20
depends_on:
openvpn-server:
condition: service_healthy
volumes:
shared-config:
networks:
vpn-test:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/24

View File

@@ -3,7 +3,7 @@
# SC1091: Not following /etc/os-release (sourced dynamically)
# SC2034: Variables used indirectly or exported for subprocesses
# Secure OpenVPN server installer for Debian, Ubuntu, CentOS, Amazon Linux 2, Fedora, Oracle Linux 8, Arch Linux, Rocky Linux and AlmaLinux.
# Secure OpenVPN server installer for Debian, Ubuntu, CentOS, Amazon Linux 2, Fedora, Oracle Linux, Arch Linux, Rocky Linux and AlmaLinux.
# https://github.com/angristan/openvpn-install
# Configuration constants
@@ -30,10 +30,10 @@ function checkOS() {
source /etc/os-release
if [[ $ID == "debian" || $ID == "raspbian" ]]; then
if [[ $VERSION_ID -lt 9 ]]; then
if [[ $VERSION_ID -lt 11 ]]; then
echo "⚠️ Your version of Debian is not supported."
echo ""
echo "However, if you're using Debian >= 9 or unstable/testing, you can continue at your own risk."
echo "However, if you're using Debian >= 11 or unstable/testing, you can continue at your own risk."
echo ""
until [[ $CONTINUE =~ (y|n) ]]; do
read -rp "Continue? [y/n]: " -e CONTINUE
@@ -45,10 +45,10 @@ function checkOS() {
elif [[ $ID == "ubuntu" ]]; then
OS="ubuntu"
MAJOR_UBUNTU_VERSION=$(echo "$VERSION_ID" | cut -d '.' -f1)
if [[ $MAJOR_UBUNTU_VERSION -lt 16 ]]; then
if [[ $MAJOR_UBUNTU_VERSION -lt 18 ]]; then
echo "⚠️ Your version of Ubuntu is not supported."
echo ""
echo "However, if you're using Ubuntu >= 16.04 or beta, you can continue at your own risk."
echo "However, if you're using Ubuntu >= 18.04 or beta, you can continue at your own risk."
echo ""
until [[ $CONTINUE =~ (y|n) ]]; do
read -rp "Continue? [y/n]: " -e CONTINUE
@@ -65,20 +65,20 @@ function checkOS() {
fi
if [[ $ID == "centos" || $ID == "rocky" || $ID == "almalinux" ]]; then
OS="centos"
if [[ ${VERSION_ID%.*} -lt 7 ]]; then
if [[ ${VERSION_ID%.*} -lt 8 ]]; then
echo "⚠️ Your version of CentOS is not supported."
echo ""
echo "The script only supports CentOS 7 and CentOS 8."
echo "The script only supports CentOS Stream 8+ / Rocky Linux 8+ / AlmaLinux 8+."
echo ""
exit 1
fi
fi
if [[ $ID == "ol" ]]; then
OS="oracle"
if [[ ! $VERSION_ID =~ (8) ]]; then
if [[ ! $VERSION_ID =~ ^(8|9) ]]; then
echo "Your version of Oracle Linux is not supported."
echo ""
echo "The script only supports Oracle Linux 8."
echo "The script only supports Oracle Linux 8 and 9."
exit 1
fi
fi
@@ -98,7 +98,7 @@ function checkOS() {
elif [[ -e /etc/arch-release ]]; then
OS=arch
else
echo "It looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS, Amazon Linux 2, Oracle Linux 8 or Arch Linux system."
echo "It looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS, Amazon Linux 2, Oracle Linux or Arch Linux system."
exit 1
fi
}
@@ -718,20 +718,19 @@ function installOpenVPN() {
if [[ $OS =~ (debian|ubuntu) ]]; then
apt-get update
apt-get -y install ca-certificates gnupg
# We add the OpenVPN repo to get the latest version.
if [[ $VERSION_ID == "16.04" ]]; then
echo "deb http://build.openvpn.net/debian/openvpn/stable xenial main" >/etc/apt/sources.list.d/openvpn.list
wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add -
apt-get update
fi
# Ubuntu > 16.04 and Debian > 8 have OpenVPN >= 2.4 without the need of a third party repository.
# Ubuntu >= 18.04 and Debian >= 11 have OpenVPN >= 2.4 without the need of a third party repository.
apt-get install -y openvpn iptables openssl wget ca-certificates curl
elif [[ $OS == 'centos' ]]; then
yum install -y epel-release
yum install -y openvpn iptables openssl wget ca-certificates curl tar 'policycoreutils-python*'
elif [[ $OS == 'oracle' ]]; then
yum install -y oracle-epel-release-el8
yum-config-manager --enable ol8_developer_EPEL
if [[ $VERSION_ID =~ ^8 ]]; then
yum install -y oracle-epel-release-el8
yum-config-manager --enable ol8_developer_EPEL
elif [[ $VERSION_ID =~ ^9 ]]; then
yum install -y oracle-epel-release-el9
yum-config-manager --enable ol9_developer_EPEL
fi
yum install -y openvpn iptables openssl wget ca-certificates curl tar policycoreutils-python-utils
elif [[ $OS == 'amzn' ]]; then
amazon-linux-extras install -y epel
@@ -993,11 +992,6 @@ verb 3" >>/etc/openvpn/server.conf
systemctl daemon-reload
systemctl enable openvpn-server@server
systemctl restart openvpn-server@server
elif [[ $OS == "ubuntu" ]] && [[ $VERSION_ID == "16.04" ]]; then
# On Ubuntu 16.04, we use the package from the OpenVPN repo
# This package uses a sysvinit service
systemctl enable openvpn
systemctl start openvpn
else
# Don't modify package-provided service
cp /lib/systemd/system/openvpn\@.service /etc/systemd/system/openvpn\@.service
@@ -1297,9 +1291,6 @@ function removeOpenVPN() {
systemctl stop openvpn-server@server
# Remove customised service
rm /etc/systemd/system/openvpn-server@.service
elif [[ $OS == "ubuntu" ]] && [[ $VERSION_ID == "16.04" ]]; then
systemctl disable openvpn
systemctl stop openvpn
else
systemctl disable openvpn@server
systemctl stop openvpn@server

24
test/Dockerfile.client Normal file
View File

@@ -0,0 +1,24 @@
# checkov:skip=CKV_DOCKER_2:Test container doesn't need healthcheck
# checkov:skip=CKV_DOCKER_3:OpenVPN client requires root for NET_ADMIN
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
# Install OpenVPN client and testing tools
RUN apt-get update && apt-get install -y \
openvpn \
iproute2 \
iputils-ping \
procps \
&& rm -rf /var/lib/apt/lists/*
# Create TUN device directory (device will be mounted at runtime)
RUN mkdir -p /dev/net
# Copy test scripts
COPY test/client-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
WORKDIR /etc/openvpn
ENTRYPOINT ["/entrypoint.sh"]

42
test/Dockerfile.server Normal file
View File

@@ -0,0 +1,42 @@
# checkov:skip=CKV_DOCKER_2:Test container doesn't need healthcheck
# checkov:skip=CKV_DOCKER_3:OpenVPN server requires root for NET_ADMIN
# checkov:skip=CKV_DOCKER_7:Base image is parameterized, some use latest tag
ARG BASE_IMAGE=ubuntu:24.04
FROM ${BASE_IMAGE}
ARG BASE_IMAGE
ENV DEBIAN_FRONTEND=noninteractive
# Install basic dependencies based on the OS
RUN if command -v apt-get >/dev/null; then \
apt-get update && apt-get install -y \
iproute2 iptables curl procps systemd systemd-sysv \
&& rm -rf /var/lib/apt/lists/*; \
elif command -v dnf >/dev/null; then \
dnf install -y --allowerasing \
iproute iptables curl procps-ng systemd tar gzip \
&& dnf clean all; \
elif command -v yum >/dev/null; then \
yum install -y \
iproute iptables curl procps-ng systemd tar gzip \
&& yum clean all; \
elif command -v pacman >/dev/null; then \
pacman -Syu --noconfirm \
iproute2 iptables curl procps-ng \
&& pacman -Scc --noconfirm; \
fi
# Create TUN device (will be mounted at runtime)
RUN mkdir -p /dev/net
# Copy the install script
COPY openvpn-install.sh /opt/openvpn-install.sh
RUN chmod +x /opt/openvpn-install.sh
# Copy test scripts
COPY test/server-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
WORKDIR /opt
ENTRYPOINT ["/entrypoint.sh"]

90
test/client-entrypoint.sh Executable file
View File

@@ -0,0 +1,90 @@
#!/bin/bash
set -e
echo "=== OpenVPN Client Container ==="
# Create TUN device if it doesn't exist
if [ ! -c /dev/net/tun ]; then
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
fi
echo "TUN device ready"
# Wait for client config to be available
echo "Waiting for client config..."
MAX_WAIT=120
WAITED=0
while [ ! -f /shared/client.ovpn ] && [ $WAITED -lt $MAX_WAIT ]; do
sleep 2
WAITED=$((WAITED + 2))
echo "Waiting... ($WAITED/$MAX_WAIT seconds)"
done
if [ ! -f /shared/client.ovpn ]; then
echo "ERROR: Client config not found after ${MAX_WAIT}s"
exit 1
fi
echo "Client config found!"
cat /shared/client.ovpn
# Connect to VPN
echo "Connecting to OpenVPN server..."
openvpn --config /shared/client.ovpn --daemon --log /var/log/openvpn.log
# Wait for connection
echo "Waiting for VPN connection..."
MAX_WAIT=60
WAITED=0
while ! ip addr show tun0 2>/dev/null | grep -q "inet " && [ $WAITED -lt $MAX_WAIT ]; do
sleep 2
WAITED=$((WAITED + 2))
echo "Waiting for tun0... ($WAITED/$MAX_WAIT seconds)"
# Check for errors
if [ -f /var/log/openvpn.log ]; then
tail -5 /var/log/openvpn.log
fi
done
if ! ip addr show tun0 2>/dev/null | grep -q "inet "; then
echo "ERROR: VPN connection failed"
echo "=== OpenVPN log ==="
cat /var/log/openvpn.log || true
exit 1
fi
echo "=== VPN Connected! ==="
ip addr show tun0
# Run connectivity tests
echo ""
echo "=== Running connectivity tests ==="
# Test 1: Check tun0 interface
echo "Test 1: Checking tun0 interface..."
if ip addr show tun0 | grep -q "10.8.0"; then
echo "PASS: tun0 interface has correct IP range (10.8.0.x)"
else
echo "FAIL: tun0 interface doesn't have expected IP"
exit 1
fi
# Test 2: Ping VPN gateway
echo "Test 2: Pinging VPN gateway (10.8.0.1)..."
if ping -c 3 10.8.0.1; then
echo "PASS: Can ping VPN gateway"
else
echo "FAIL: Cannot ping VPN gateway"
exit 1
fi
echo ""
echo "=========================================="
echo " ALL TESTS PASSED!"
echo "=========================================="
# Keep container running for debugging if needed
exec tail -f /var/log/openvpn.log

109
test/server-entrypoint.sh Executable file
View File

@@ -0,0 +1,109 @@
#!/bin/bash
set -e
echo "=== OpenVPN Server Container ==="
# Create TUN device if it doesn't exist
if [ ! -c /dev/net/tun ]; then
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
fi
echo "TUN device ready"
# Set up environment for auto-install
export AUTO_INSTALL=y
export APPROVE_INSTALL=y
export APPROVE_IP=y
export IPV6_SUPPORT=n
export PORT_CHOICE=1
export PROTOCOL_CHOICE=1
export DNS=9 # Google DNS (works in containers)
export COMPRESSION_ENABLED=n
export CUSTOMIZE_ENC=n
export CLIENT=testclient
export PASS=1
export ENDPOINT=openvpn-server
# Prepare script for container environment:
# - Replace systemctl calls with no-ops (systemd doesn't work in containers)
# This ensures the script won't fail silently on systemctl commands
sed 's/\bsystemctl /echo "[SKIPPED] systemctl " # /g' /opt/openvpn-install.sh >/tmp/openvpn-install.sh
chmod +x /tmp/openvpn-install.sh
echo "Running OpenVPN install script..."
# Run in subshell because the script calls 'exit 0' after generating client config
# Use || true to prevent set -e from exiting on failure, then check exit code
(bash -x /tmp/openvpn-install.sh) && INSTALL_EXIT_CODE=0 || INSTALL_EXIT_CODE=$?
echo "=== Installation complete (exit code: $INSTALL_EXIT_CODE) ==="
if [ "$INSTALL_EXIT_CODE" -ne 0 ]; then
echo "ERROR: Install script failed with exit code $INSTALL_EXIT_CODE"
exit 1
fi
# Verify all expected files were created
echo "Verifying installation..."
MISSING_FILES=0
for f in \
/etc/openvpn/server.conf \
/etc/openvpn/ca.crt \
/etc/openvpn/ca.key \
/etc/openvpn/tls-crypt.key \
/etc/openvpn/crl.pem \
/etc/openvpn/easy-rsa/pki/ca.crt \
/etc/iptables/add-openvpn-rules.sh \
/root/testclient.ovpn; do
if [ ! -f "$f" ]; then
echo "ERROR: Missing file: $f"
MISSING_FILES=$((MISSING_FILES + 1))
fi
done
if [ $MISSING_FILES -gt 0 ]; then
echo "ERROR: $MISSING_FILES required files are missing"
exit 1
fi
echo "All required files present"
echo ""
echo "Server config:"
cat /etc/openvpn/server.conf
# Copy client config to shared volume
cp /root/testclient.ovpn /shared/client.ovpn
# Modify remote address to use container hostname
sed -i 's/^remote .*/remote openvpn-server 1194/' /shared/client.ovpn
echo "Client config copied to /shared/client.ovpn"
# Start OpenVPN server manually (systemd doesn't work in containers)
echo "Starting OpenVPN server..."
# Apply iptables rules manually (systemd not available in containers)
echo "Applying iptables rules..."
bash /etc/iptables/add-openvpn-rules.sh
# Verify iptables NAT rules exist
echo "Verifying iptables NAT rules..."
if iptables -t nat -L POSTROUTING -n | grep -q "10.8.0.0"; then
echo "PASS: NAT POSTROUTING rule for 10.8.0.0/24 exists"
else
echo "FAIL: NAT POSTROUTING rule for 10.8.0.0/24 not found"
echo "Current NAT rules:"
iptables -t nat -L POSTROUTING -n -v
exit 1
fi
# Enable IP forwarding (may already be set via docker-compose sysctls)
if [ "$(cat /proc/sys/net/ipv4/ip_forward)" != "1" ]; then
echo 1 >/proc/sys/net/ipv4/ip_forward || {
echo "ERROR: Failed to enable IP forwarding"
exit 1
}
fi
# Start OpenVPN in foreground (run from /etc/openvpn so relative paths work)
cd /etc/openvpn
exec openvpn --config /etc/openvpn/server.conf