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.

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

Last updated: March 2026