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:
Using Let's Encrypt (Recommended)¶
# 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:
Option 1: HTTPS Download (Recommended)¶
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:
Option 2: Out-of-band Distribution¶
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¶
- Configuration - Full server configuration reference
- Deployment - Production deployment tips
- Client Configuration - Configure client connections