Deploy VPN on Headless Servers
FreeGuard CLI runs natively on headless Linux servers with no desktop environment required. Whether you are securing a cloud instance, protecting a home lab, or routing container traffic through VPN, this guide covers installation, authentication, service configuration, and monitoring for production server deployments.
Why Run VPN on a Server?
Servers handle sensitive traffic: database connections, API calls, backup transfers, and inter-service communication. Running VPN on the server itself ensures all outbound traffic is encrypted without configuring individual applications.
Common use cases:
- Cloud instances accessing geo-restricted APIs
- CI/CD runners that need consistent network identity
- Self-hosted services that benefit from IP masking
- Development servers used by distributed teams
Installation
Ubuntu / Debian
curl -fsSL https://cli.freeguard.com/install.sh | bash
Or install from the APT repository:
curl -fsSL https://cli.freeguard.com/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/freeguard.gpg
echo "deb [signed-by=/usr/share/keyrings/freeguard.gpg] https://apt.freeguard.com stable main" | sudo tee /etc/apt/sources.list.d/freeguard.list
sudo apt update
sudo apt install freeguard-cli
CentOS / RHEL / Fedora
curl -fsSL https://cli.freeguard.com/install.sh | bash
Or use the RPM repository:
sudo rpm --import https://cli.freeguard.com/gpg.key
sudo tee /etc/yum.repos.d/freeguard.repo <<EOF
[freeguard]
name=FreeGuard CLI
baseurl=https://rpm.freeguard.com/stable
gpgcheck=1
gpgkey=https://cli.freeguard.com/gpg.key
EOF
sudo yum install freeguard-cli
Alpine Linux
curl -fsSL https://cli.freeguard.com/install.sh | bash
Alpine users may need to install libc6-compat first:
apk add libc6-compat
curl -fsSL https://cli.freeguard.com/install.sh | bash
Verify Installation
freeguard --version
Headless Authentication
On servers without a browser, you cannot use the default OAuth login flow. FreeGuard CLI provides email-based authentication for headless environments.
Email Login
freeguard login --method email
The CLI prompts you to enter your account email. A verification code is sent to that address. Enter the code in the terminal to complete authentication.
$ freeguard login --method email
Enter your email: [email protected]
Verification code sent. Check your inbox.
Enter code: 483291
Login successful.
Token-Based Login
For automated deployments, use a service token:
freeguard login --method token --token YOUR_SERVICE_TOKEN
Generate service tokens from your account dashboard. Tokens can be scoped to specific servers and have configurable expiration.
Verify Authentication
freeguard status --json | jq '.authenticated'
Running as a systemd Service
For production deployments, run FreeGuard CLI as a systemd service so it starts on boot and restarts on failure.
Create the Service File
sudo tee /etc/systemd/system/freeguard.service <<EOF
[Unit]
Description=FreeGuard VPN
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/freeguard connect --server us-east --no-color
ExecStop=/usr/local/bin/freeguard disconnect
Restart=on-failure
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
EOF
Enable and Start
sudo systemctl daemon-reload
sudo systemctl enable freeguard
sudo systemctl start freeguard
Check Service Status
sudo systemctl status freeguard
View Logs
sudo journalctl -u freeguard -f
Scripting with --json and --no-color
Production scripts should parse structured output rather than human-readable text.
JSON Output
Every command supports --json:
# Connection status
freeguard status --json
Output:
{
"connected": true,
"server": "us-east-1",
"server_name": "New York",
"protocol": "hysteria2",
"uptime": 86400,
"bytes_sent": 1048576,
"bytes_received": 5242880
}
No-Color Mode
Strip ANSI color codes for clean log files:
freeguard status --no-color >> /var/log/freeguard-status.log
Scripting Example
A health-check script that reconnects on failure:
#!/bin/bash
STATUS=$(freeguard status --json 2>/dev/null)
CONNECTED=$(echo "$STATUS" | jq -r '.connected')
if [ "$CONNECTED" != "true" ]; then
echo "$(date): VPN disconnected, reconnecting..." >> /var/log/freeguard-health.log
freeguard connect --server us-east --json >> /var/log/freeguard-health.log 2>&1
fi
Add it to cron for regular checks:
# Check VPN health every 5 minutes
*/5 * * * * /opt/scripts/freeguard-health.sh
Monitoring and Health Checks
Basic Health Check
freeguard status --json | jq -r '.connected'
Returns true or false. Simple enough for any monitoring system.
Integration with Monitoring Tools
Export status to Prometheus, Datadog, or any monitoring system that can execute shell commands:
#!/bin/bash
# prometheus-exporter.sh
STATUS=$(freeguard status --json)
CONNECTED=$(echo "$STATUS" | jq -r '.connected')
UPTIME=$(echo "$STATUS" | jq -r '.uptime')
if [ "$CONNECTED" = "true" ]; then
echo "freeguard_connected 1"
echo "freeguard_uptime_seconds $UPTIME"
else
echo "freeguard_connected 0"
echo "freeguard_uptime_seconds 0"
fi
Alerting
Combine the health check with your alerting system. Example with a simple webhook:
#!/bin/bash
CONNECTED=$(freeguard status --json | jq -r '.connected')
if [ "$CONNECTED" != "true" ]; then
curl -X POST https://hooks.example.com/alert \
-H "Content-Type: application/json" \
-d '{"text": "FreeGuard VPN disconnected on '"$(hostname)"'"}'
fi
Security Considerations
- Run as root: The VPN tunnel requires root privileges to modify network routes. The systemd service runs as root by default.
- Token storage: Service tokens are stored in
~/.config/freeguard/. Ensure appropriate file permissions (chmod 600). - Firewall rules: If you use UFW or iptables, ensure the VPN tunnel interface is allowed.
- Kill switch: Enable the kill switch to block all traffic if VPN disconnects:
freeguard config set kill-switch true.
Next Steps
- FreeGuard CLI — full command reference
- Developer workflow guide — integrate VPN into your development tools
- Pricing — server deployments work with any plan
Last updated: March 2026