Michael Dvornichenko

Blog

vpn

Setting up a VPN server with traffic obfuscation

A brief guide on how to set up an OpenConnect VPN server on AlmaLinux with SNI proxy integration on NGINX for traffic obfuscation.

An SNI proxy (Server Name Indication) provides an additional layer of obfuscation, making the traffic appear like regular HTTPS traffic. This is especially useful in countries or networks where VPN traffic is actively blocked or inspected.

However, it’s important to note that this solution is not a panacea. Obfuscation works for most services I personally use, but there are some that can detect it. For example, OpenAI is quite good at recognizing VPN traffic, but banking services do not see it, allowing for smooth operation.

For the VPN setup, I purchased the cheapest VPS: 1 core, 2GB of RAM, 10GB of disk space, and a 500Mbps internet connection.

Step 1: Installing the necessary packages

First, you need to install the packages that will allow us to configure the VPN and SNI proxy. We need to install OpenConnect Server (ocserv), NGINX, and OpenSSL.

sudo dnf install epel-release -y
sudo dnf install ocserv nginx openssl -y

This installs the latest available versions of OpenConnect, NGINX, and OpenSSL on AlmaLinux.

Step 2: Creating SSL Certificates

Both OpenConnect and NGINX require SSL certificates for secure communication. You can create a self-signed certificate or use a real TLS certificate from a certificate authority if you have a domain.

Run the following command to create a certificate and a private key:

sudo mkdir -p /etc/ocserv/ssl
sudo openssl req -newkey rsa:4096 -nodes -keyout /etc/ocserv/ssl/server.key -x509 -days 365 -out /etc/ocserv/ssl/server.crt -subj "/C=UA/ST=Kyiv/L=Kyiv/O=MyVPN/OU=IT/CN=$(hostname -I)"
Code language: JavaScript (javascript)

This creates an SSL certificate at /etc/ocserv/ssl/server.crt and a private key at /etc/ocserv/ssl/server.key, valid for one year.

Step 3: Configuring the OpenConnect server

The next step is to configure the OpenConnect server by creating a configuration file. By default, the file is located at /etc/ocserv/ocserv.conf.

sudo tee /etc/ocserv/ocserv.conf > /dev/null <<EOF
auth = "plain[passwd=/etc/ocserv/ocpasswd]"
tcp-port = 443
udp-port = 443
server-cert = /etc/ocserv/ssl/server.crt
server-key = /etc/ocserv/ssl/server.key
device = vpns
ipv4-network = 192.168.100.0
ipv4-netmask = 255.255.255.0
run-as-user = nobody
run-as-group = nobody
max-clients = 128
max-same-clients = 4
keepalive = 32400
dpd = 90
cisco-client-compat = true
tls-priorities = "normal"
socket-file = /var/run/ocserv-socket
dns = 8.8.8.8
dns = 8.8.4.4
EOF
Code language: JavaScript (javascript)

This configuration sets up the OpenConnect server to handle traffic on port 443, supports up to 128 clients, and uses Google DNS servers.

Step 4: Configuring NGINX as an SNI Proxy

The NGINX SNI proxy will forward traffic depending on the server name (SNI) used in the request. It will forward VPN requests to OpenConnect and HTTP/HTTPS traffic to another server if necessary.

sudo tee /etc/nginx/nginx.conf > /dev/null <<EOF
worker_processes  1;

events {
    worker_connections  1024;
}

stream {
    map \$ssl_preread_server_name \$backend {
        vpn.example.com ocserv_backend;
        default web_backend;
    }

    upstream ocserv_backend {
        server 127.0.0.1:443;
    }

    upstream web_backend {
        server 127.0.0.1:8443;
    }

    server {
        listen 443;
        proxy_pass \$backend;
        ssl_preread on;
    }
}
EOF
Code language: PHP (php)

Replace vpn.example.com with your server’s domain or public IP address.

Step 5: Starting and Enabling the Services

After configuring OpenConnect and NGINX, you need to start and enable both services.

sudo systemctl enable nginx
sudo systemctl enable ocserv
sudo systemctl restart nginx
sudo systemctl restart ocserv

Step 6: Verifying Service Status

Ensure that both the OpenConnect and NGINX services are active and running:

systemctl status ocserv
systemctl status nginx

Step 7: Adding VPN Users

With OpenConnect, you can create VPN users. OpenConnect uses a simple password file (/etc/ocserv/ocpasswd) to store usernames and passwords. You’ll also need to create user certificates.

Here’s how to add a user and generate a client certificate:

read -p "Enter VPN username: " vpn_user
sudo ocpasswd -c /etc/ocserv/ocpasswd $vpn_user
Code language: PHP (php)

Creating Client Certificates and PKCS#12 Files

For each user, you need to generate a client certificate and a PKCS#12 file, which includes the certificate and key for easy client setup:

sudo openssl req -newkey rsa:2048 -nodes -keyout /etc/ocserv/ssl/$vpn_user.key -x509 -days 365 -out /etc/ocserv/ssl/$vpn_user.crt -subj "/C=UA/ST=Kyiv/L=Kyiv/O=MyVPN/OU=IT/CN=$vpn_user"
sudo openssl pkcs12 -export -out /etc/ocserv/ssl/$vpn_user.p12 -inkey /etc/ocserv/ssl/$vpn_user.key -in /etc/ocserv/ssl/$vpn_user.crt -certfile /etc/ocserv/ssl/server.crt -password pass:$vpn_pass
Code language: PHP (php)

The .p12 file needs to be sent to the client for VPN setup.

Step 8: Verifying VPN and SNI Proxy

After setting up the VPN server, you can check if it’s listening on the correct ports:

sudo lsof -i :443 | grep LISTEN

To ensure the VPN is accessible, use curl to check its availability:

curl -I https://$(hostname -I | awk '{print $1}') --insecure --max-time 10
Code language: JavaScript (javascript)

If everything is set up correctly, the VPN will respond to HTTPS requests on port 443.

Step 9: Verifying VPN Encryption

To confirm that the VPN encrypts traffic, you can use the tcpdump tool to capture traffic:

sudo tcpdump -i any port 443 

You should see encrypted traffic between the client and server. Any VPN client connecting via the .p12 certificate will have encrypted traffic. Instead of plain text, the packets will only contain headers and packet length, without revealing the content of the data.

Automatic Setup Script

If you don’t want to set it up manually, you can use the automatic script provided below.

I tested this script on a new Azure virtual machine before publishing this article, and everything seemed to work fine. If you find any errors, please let me know.

#!/bin/bash

# Automated OpenConnect Server and NGINX SNI Proxy Setup Script on AlmaLinux with Client Certificates (.crt, .p12)

echo "Starting the OpenConnect VPN Server and NGINX SNI Proxy installation on AlmaLinux..."

# Step 1: Install necessary packages
echo "Installing necessary packages: ocserv, nginx, and openssl..."
sudo dnf install epel-release -y
sudo dnf install ocserv nginx openssl -y

# Step 2: Check if required packages are installed
echo "Verifying package installation..."
if ! command -v ocserv &> /dev/null; then
    echo "Error: OpenConnect Server (ocserv) is not installed."
    exit 1
fi
if ! command -v nginx &> /dev/null; then
    echo "Error: NGINX is not installed."
    exit 1
fi
if ! command -v openssl &> /dev/null; then
    echo "Error: OpenSSL is not installed."
    exit 1
fi

echo "All required packages are installed."

# Step 3: Generate SSL certificate for OpenConnect Server and NGINX
echo "Generating SSL certificates..."
sudo mkdir -p /etc/ocserv/ssl
sudo openssl req -newkey rsa:4096 -nodes -keyout /etc/ocserv/ssl/server.key -x509 -days 365 -out /etc/ocserv/ssl/server.crt -subj "/C=US/ST=California/L=SanFrancisco/O=MyVPN/OU=IT/CN=$(hostname -I)"

# Step 4: Configure OpenConnect Server
echo "Configuring OpenConnect Server (ocserv)..."
sudo tee /etc/ocserv/ocserv.conf > /dev/null <<EOF
auth = "plain[passwd=/etc/ocserv/ocpasswd]"
tcp-port = 443
udp-port = 443
server-cert = /etc/ocserv/ssl/server.crt
server-key = /etc/ocserv/ssl/server.key
device = vpns
ipv4-network = 192.168.100.0
ipv4-netmask = 255.255.255.0
run-as-user = nobody
run-as-group = nobody
max-clients = 128
max-same-clients = 4
keepalive = 32400
dpd = 90
cisco-client-compat = true
tls-priorities = "normal"
socket-file = /var/run/ocserv-socket
dns = 8.8.8.8
dns = 8.8.4.4
EOF

# Step 5: Configure NGINX as SNI Proxy
echo "Configuring NGINX as SNI Proxy..."
sudo tee /etc/nginx/nginx.conf > /dev/null <<EOF
worker_processes  1;

events {
    worker_connections  1024;
}

stream {
    map \$ssl_preread_server_name \$backend {
        vpn.example.com ocserv_backend;
        default web_backend;
    }

    upstream ocserv_backend {
        server 127.0.0.1:443;
    }

    upstream web_backend {
        server 127.0.0.1:8443;
    }

    server {
        listen 443;
        proxy_pass \$backend;
        ssl_preread on;
    }
}
EOF

# Step 6: Enable and restart services
echo "Enabling and restarting services (NGINX and OCserv)..."
sudo systemctl enable nginx
sudo systemctl enable ocserv
sudo systemctl restart nginx
sudo systemctl restart ocserv

# Step 7: Verify services
echo "Verifying the status of OCserv and NGINX..."
if systemctl is-active --quiet ocserv; then
    echo "OCserv is running."
else
    echo "Error: OCserv is not running."
    exit 1
fi

if systemctl is-active --quiet nginx; then
    echo "NGINX is running."
else
    echo "Error: NGINX is not running."
    exit 1
fi

# Step 8: Check if port 443 is being listened on
echo "Checking if port 443 is being listened on..."
if sudo lsof -i :443 | grep LISTEN; then
    echo "Port 443 is listening."
else
    echo "Error: Port 443 is not listening."
    exit 1
fi

# Step 9: Adding VPN users and creating certificates
echo "Adding VPN users..."
while true; do
    read -p "Enter a username for VPN (or type 'exit' to quit): " vpn_user
    if [[ "$vpn_user" == "exit" ]]; then
        echo "Exiting user creation."
        break
    fi
    read -sp "Enter password for $vpn_user: " vpn_pass
    echo
    sudo ocpasswd -c /etc/ocserv/ocpasswd $vpn_user <<EOF
$vpn_pass
$vpn_pass
EOF
    echo "User $vpn_user has been added."

    # Step 10: Create client certificate
    echo "Generating client certificate for $vpn_user..."
    sudo openssl req -newkey rsa:2048 -nodes -keyout /etc/ocserv/ssl/$vpn_user.key -x509 -days 365 -out /etc/ocserv/ssl/$vpn_user.crt -subj "/C=US/ST=California/L=SanFrancisco/O=MyVPN/OU=IT/CN=$vpn_user"

    # Step 11: Create PKCS#12 (.p12) file for client
    echo "Creating .p12 certificate bundle for $vpn_user..."
    sudo openssl pkcs12 -export -out /etc/ocserv/ssl/$vpn_user.p12 -inkey /etc/ocserv/ssl/$vpn_user.key -in /etc/ocserv/ssl/$vpn_user.crt -certfile /etc/ocserv/ssl/server.crt -password pass:$vpn_pass

    echo "Client certificate (.crt), private key (.key), and PKCS#12 (.p12) bundle have been created for user $vpn_user."
    echo "Files for $vpn_user are located at /etc/ocserv/ssl/"

done

# Step 12: Verify VPN connection availability via curl
echo "Verifying VPN connection availability via curl..."
curl -I https://$(hostname -I | awk '{print $1}') --insecure --max-time 10 >/dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "VPN is accessible via HTTPS."
else
    echo "Error: Unable to access VPN via HTTPS."
    exit 1
fi

echo "Setup complete. Client certificates and .p12 bundles are located in /etc/ocserv/ssl/"
Code language: PHP (php)

Don’t forget to change permissions:

chmod +x vpn-setup.sh Code language: CSS (css)

Now, install the Cisco AnyConnect client

For Android: https://play.google.com/store/apps/details?id=com.cisco.anyconnect.vpn.android.avf

For iOS: https://apps.apple.com/us/app/cisco-secure-client/id1135064690

For Windows: https://apps.microsoft.com/detail/9wzdncrdj8lh

Don’t forget to install the generated client certificate on the client, obtained during Step 7.

I hope you found this information useful.

Leave a Reply

Your email address will not be published. Required fields are marked *