Skip to content

Server Setup

This guide covers setting up an R-VPN server.

Prerequisites

  • Linux server with public IP
  • Domain name pointing to server (e.g., vpn.example.com)
  • Root or sudo access
  • Open port 443 (HTTPS)

Installation

1. Install Binary

Download the server binary for your platform:

# Download server binary (adjust URL/version as needed)
curl -L -o rvpn-server https://github.com/r-vpn/rvpn/releases/latest/download/rvpn-server-linux-x86_64

# Make executable
chmod +x rvpn-server

# Install to system path
sudo mv rvpn-server /usr/local/bin/

# Verify installation
rvpn-server --help

2. Create Directories

Create the required directories for configuration, data, and logs:

# Configuration directory
sudo mkdir -p /etc/rvpn

# Data directory (for persistent state)
sudo mkdir -p /var/lib/rvpn

# Log directory
sudo mkdir -p /var/log/rvpn

# Set permissions
sudo chmod 755 /etc/rvpn /var/lib/rvpn /var/log/rvpn

3. Generate Server Keys

Generate the server's identity key:

# Generate identity key (creates server_identity.key in current directory)
cd /etc/rvpn
sudo rvpn-server keygen

# Set secure permissions
sudo chmod 600 /etc/rvpn/server_identity.key

This creates an Ed25519 identity key pair used for authentication and X3DH key exchange.

4. Generate Prekey Bundle

Generate the X3DH prekey bundle for clients:

# Generate prekey bundle from identity key
sudo rvpn-server prekey-bundle \
    --identity /etc/rvpn/server_identity.key \
    --output /var/lib/rvpn/prekey-bundle.json

# Set permissions (bundle is public, but should not be modified)
sudo chmod 644 /var/lib/rvpn/prekey-bundle.json

The prekey bundle contains: - identity_key - Server's Ed25519 public key (for authentication) - identity_x25519_key - X25519 public key derived from identity - signed_prekey - X25519 public key for X3DH (rotated periodically) - prekey_signature - Signature proving prekey authenticity - one_time_prekey - Optional: one-time prekey for enhanced security

A private bundle (prekey-bundle.private.json) is also created - keep this secure and do not distribute it.

5. Configure TLS Certificates

R-VPN requires TLS 1.3 certificates. The recommended approach is Let's Encrypt:

# Install certbot
sudo apt update
sudo apt install certbot

# Get certificate (standalone mode)
sudo certbot certonly --standalone -d vpn.example.com

# Copy certificates to R-VPN directory
sudo cp /etc/letsencrypt/live/vpn.example.com/fullchain.pem /etc/rvpn/cert.pem
sudo cp /etc/letsencrypt/live/vpn.example.com/privkey.pem /etc/rvpn/key.pem

# Set permissions
sudo chmod 600 /etc/rvpn/key.pem
sudo chmod 644 /etc/rvpn/cert.pem

# Set up auto-renewal hook
echo '#!/bin/bash
cp /etc/letsencrypt/live/vpn.example.com/fullchain.pem /etc/rvpn/cert.pem
cp /etc/letsencrypt/live/vpn.example.com/privkey.pem /etc/rvpn/key.pem
chmod 600 /etc/rvpn/key.pem
chmod 644 /etc/rvpn/cert.pem
systemctl restart rvpn-server' | sudo tee /etc/letsencrypt/renewal-hooks/deploy/rvpn-server
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/rvpn-server

Using Existing Certificates

If you have certificates from another provider:

# Copy your certificate and key
sudo cp /path/to/your/cert.pem /etc/rvpn/cert.pem
sudo cp /path/to/your/key.pem /etc/rvpn/key.pem

# Set permissions
sudo chmod 600 /etc/rvpn/key.pem
sudo chmod 644 /etc/rvpn/cert.pem

Configuration

Create /etc/rvpn/server.toml:

[server]
# Bind address (default port 443 for stealth)
bind_address = "0.0.0.0:443"

# TLS certificates
tls_cert_file = "/etc/rvpn/cert.pem"
tls_key_file = "/etc/rvpn/key.pem"

# Server identity
identity_key_file = "/etc/rvpn/server_identity.key"

# Prekey bundle file (for consistent keys across restarts)
prekey_bundle_file = "/var/lib/rvpn/prekey-bundle.json"

# X3DH prekey settings
prekey_rotation_hours = 168      # Rotate weekly
one_time_prekey_count = 100      # Maintain 100 OTPKs

# WebSocket path (hidden endpoint for VPN connections)
websocket_path = "/connect"

# HTTP port for ACME challenges and redirect (optional)
http_port = 80
redirect_http_to_https = true

# Optional: Decoy website root (serves normal website to non-VPN visitors)
# decoy_root = "/var/www/html"

[server.rate_limit]
max_connections_per_ip = 5
max_handshakes_per_minute = 10

[server.network]
nat_enabled = true
dhcp_range = "10.200.0.0/24"
dns_servers = ["1.1.1.1", "8.8.8.8"]

Configuration Options

Option Default Description
bind_address 0.0.0.0:443 Address and port to bind to
tls_cert_file certs/cert.pem Path to TLS certificate
tls_key_file certs/key.pem Path to TLS private key
identity_key_file server_identity.key Path to server identity key
prekey_bundle_file - Path to prekey bundle (for key consistency)
websocket_path /connect WebSocket endpoint path
http_port - HTTP port for ACME/redirect (disabled if not set)
redirect_http_to_https true Redirect HTTP to HTTPS
decoy_root - Path to decoy website files
prekey_rotation_hours 168 Prekey rotation interval (hours)
one_time_prekey_count 100 Number of one-time prekeys to maintain

Running the Server

Manual Start (Testing)

# Run with config file
sudo rvpn-server --config /etc/rvpn/server.toml

# Run with verbose logging
sudo rvpn-server --config /etc/rvpn/server.toml -v

# Run with custom bind address
sudo rvpn-server --config /etc/rvpn/server.toml --bind 0.0.0.0:8443

Systemd Service (Production)

Create /etc/systemd/system/rvpn-server.service:

[Unit]
Description=R-VPN Server
After=network.target
Wants=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/rvpn-server --config /etc/rvpn/server.toml
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rvpn-server

# Security hardening (optional, adjust as needed)
NoNewPrivileges=false
ProtectSystem=false
ProtectHome=false

[Install]
WantedBy=multi-user.target

Enable and start the service:

# Reload systemd
sudo systemctl daemon-reload

# Enable service to start on boot
sudo systemctl enable rvpn-server

# Start the service
sudo systemctl start rvpn-server

# Check status
sudo systemctl status rvpn-server

# View logs
sudo journalctl -u rvpn-server -f

Firewall Configuration

Using UFW (Ubuntu/Debian)

# Allow HTTPS port
sudo ufw allow 443/tcp

# Allow HTTP for ACME/redirect (optional)
sudo ufw allow 80/tcp

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status

Using iptables

# Allow HTTPS
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow HTTP for ACME/redirect (optional)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Save rules (Debian/Ubuntu)
sudo apt install iptables-persistent
sudo netfilter-persistent save

# Save rules (RHEL/CentOS)
sudo service iptables save

Using firewalld

# Add HTTPS service
sudo firewall-cmd --permanent --add-service=https

# Add HTTP service (optional)
sudo firewall-cmd --permanent --add-service=http

# Reload firewall
sudo firewall-cmd --reload

Security Features

Built-in Rate Limiting

The server includes built-in rate limiting to prevent abuse:

  • Connection rate limiting: Limits failed handshakes per IP (default: 10 failures per minute)
  • Scanner protection: Automatically categorizes and silently drops scanner/probe attempts
  • Connection limits: Configurable max connections per IP

TLS 1.3 Only

R-VPN enforces TLS 1.3 for all connections. Older TLS versions are rejected.

Log Rotation

Set up log rotation to prevent disk space issues:

Create /etc/logrotate.d/rvpn:

/var/log/rvpn/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    sharedscripts
    postrotate
        systemctl reload rvpn-server 2>/dev/null || true
    endscript
}

Testing

Check Server Status

# Check if service is running
sudo systemctl status rvpn-server

# Check logs
sudo journalctl -u rvpn-server -f

# Check listening ports
sudo ss -tlnp | grep 443
# or
sudo netstat -tlnp | grep 443

Test WebSocket Endpoint

# Test WebSocket connection (requires wscat or similar)
npm install -g wscat
wscat -c wss://vpn.example.com/connect

# Or using curl to test HTTPS
curl -I https://vpn.example.com/

Test with Client

From a client machine:

# Download prekey bundle
curl -o prekey-bundle.json https://vpn.example.com/prekey-bundle.json

# Connect with client
rvpn --server wss://vpn.example.com/connect --config client.toml

Distributing Prekey Bundle to Clients

Clients need the prekey bundle to establish encrypted connections. Distribution methods:

Host the bundle on your server:

# Copy bundle to web directory
sudo mkdir -p /var/www/html
sudo cp /var/lib/rvpn/prekey-bundle.json /var/www/html/
sudo chmod 644 /var/www/html/prekey-bundle.json

Clients download:

curl -o prekey-bundle.json https://vpn.example.com/prekey-bundle.json

Option 2: Out-of-band Distribution

# Secure copy to client
scp /var/lib/rvpn/prekey-bundle.json user@client:/path/to/

Option 3: Embed in Client Package

Include the bundle in your client configuration package.

Troubleshooting

Server fails to start

# Check for port conflicts
sudo ss -tlnp | grep 443

# Check config file syntax
cat /etc/rvpn/server.toml

# Check file permissions
ls -la /etc/rvpn/
ls -la /var/lib/rvpn/

TLS certificate issues

# Verify certificate
openssl x509 -in /etc/rvpn/cert.pem -text -noout

# Check certificate expiry
openssl x509 -in /etc/rvpn/cert.pem -noout -dates

# Test TLS connection
openssl s_client -connect vpn.example.com:443 -tls1_3

Connection issues

# Check firewall
sudo iptables -L -n | grep 443

# Check server is listening
sudo ss -tlnp | grep rvpn

# Enable verbose logging
sudo rvpn-server --config /etc/rvpn/server.toml -vv

Next Steps