Skip to content

Gluetun VPN Proxy

Gluetun provides Docker-managed VPN proxies supporting 50+ VPN providers.

Prerequisites

Docker must be installed and running.

# Linux
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER  # Then log out/in

# Windows/Mac
# Install Docker Desktop: https://www.docker.com/products/docker-desktop/

Quick Start

1. Configuration

Add to ~/.config/unshackle/unshackle.yaml:

proxy_providers:
  gluetun:
    providers:
      windscribe:
        vpn_type: openvpn
        credentials:
          username: "YOUR_OPENVPN_USERNAME"
          password: "YOUR_OPENVPN_PASSWORD"

2. Usage

Use 2-letter country codes directly:

unshackle dl SERVICE CONTENT --proxy gluetun:windscribe:us
unshackle dl SERVICE CONTENT --proxy gluetun:windscribe:uk

Format: gluetun:provider:region

Provider Credential Requirements

OpenVPN (Recommended): Most providers support OpenVPN with just username and password - the simplest setup.

WireGuard: Requires private keys and varies by provider. See the Gluetun Wiki for provider-specific requirements. Note that vpn_type defaults to wireguard if not specified.

Getting Your Credentials

Windscribe (OpenVPN)

  1. Go to windscribe.com/getconfig/openvpn
  2. Log in with your Windscribe account
  3. Select any location and click "Get Config"
  4. Copy the username and password shown

NordVPN (OpenVPN)

  1. Go to NordVPN Service Credentials
  2. Log in with your NordVPN account
  3. Generate or view your service credentials
  4. Copy the username and password

Note

Use service credentials, NOT your account email/password.

WireGuard Credentials (Advanced)

WireGuard requires private keys instead of username/password. See the Gluetun Wiki for provider-specific WireGuard setup.

Configuration Examples

OpenVPN (Recommended)

Most providers support OpenVPN with just username and password:

providers:
  windscribe:
    vpn_type: openvpn
    credentials:
      username: YOUR_OPENVPN_USERNAME
      password: YOUR_OPENVPN_PASSWORD

  nordvpn:
    vpn_type: openvpn
    credentials:
      username: YOUR_SERVICE_USERNAME
      password: YOUR_SERVICE_PASSWORD

WireGuard (Advanced)

WireGuard can be faster but requires more complex credential setup:

# NordVPN/ProtonVPN (only private_key needed)
providers:
  nordvpn:
    vpn_type: wireguard
    credentials:
      private_key: YOUR_PRIVATE_KEY

# Surfshark/Mullvad/IVPN (private_key AND addresses required)
  surfshark:
    vpn_type: wireguard
    credentials:
      private_key: YOUR_PRIVATE_KEY
      addresses: 10.x.x.x/32

# Windscribe (all three credentials required)
  windscribe:
    vpn_type: wireguard
    credentials:
      private_key: YOUR_PRIVATE_KEY
      addresses: 10.x.x.x/32
      preshared_key: YOUR_PRESHARED_KEY

Server Selection

Most providers use SERVER_COUNTRIES, but some use SERVER_REGIONS:

Variable Providers
SERVER_COUNTRIES NordVPN, ProtonVPN, Surfshark, Mullvad, ExpressVPN, and most others
SERVER_REGIONS Windscribe, VyprVPN, VPN Secure

Unshackle handles this automatically - just use 2-letter country codes.

Per-Provider Server Mapping

You can explicitly map region codes to country names, cities, or hostnames per provider:

providers:
  nordvpn:
    vpn_type: openvpn
    credentials:
      username: YOUR_USERNAME
      password: YOUR_PASSWORD
    server_countries:
      us: "United States"
      uk: "United Kingdom"
    server_cities:
      us: "New York"
    server_hostnames:
      us: "us1239.nordvpn.com"

Specific Server Selection

Use a <country><number> region (e.g. us1239) to target a specific server. Unshackle builds the hostname automatically per provider:

Provider Hostname format
NordVPN us1239.nordvpn.com
Surfshark us-1239.prod.surfshark.com
ExpressVPN us-1239.expressvpn.com
CyberGhost us-s1239.cg-dialup.net
Other us1239 (passed as-is to SERVER_HOSTNAMES)

Extra Environment Variables

You can pass additional Gluetun environment variables per provider using extra_env:

providers:
  nordvpn:
    vpn_type: openvpn
    credentials:
      username: YOUR_USERNAME
      password: YOUR_PASSWORD
    extra_env:
      LOG_LEVEL: debug

Global Settings

proxy_providers:
  gluetun:
    providers: {...}
    base_port: 8888           # Starting port (default: 8888)
    auto_cleanup: true        # Remove containers on exit (default: true)
    verify_ip: true           # Verify IP matches region (default: true)
    container_prefix: "unshackle-gluetun"  # Docker container name prefix (default: "unshackle-gluetun")
    auth_user: username       # Proxy auth (optional)
    auth_password: password   # Proxy auth (optional)

Features

  • Container Reuse: First request takes 10-30s; subsequent requests are instant. Containers created by other unshackle processes are auto-detected via docker inspect and reused.
  • Ready Detection: Waits up to 60s for both the HTTP proxy to listen ([http proxy] listening) and the VPN tunnel to come up (initialization sequence completed or public ip address is) before returning the proxy URI. Bails early on fatal or invalid credentials log lines.
  • IP Verification: When verify_ip: true (default), looks up the exit IP via ipinfo.io through the proxy and compares country code to the requested region. Retries 3 times with exponential backoff (1s, 2s, 4s).
  • Concurrent Sessions: Multiple downloads share the same container; ports are allocated thread-safely starting at base_port.
  • Specific Servers: Use --proxy gluetun:nordvpn:us1239 for specific server selection (see table above).
  • Automatic Image Pull: The Gluetun Docker image (qmcgaw/gluetun:latest) is pulled automatically on first use (5 min timeout).
  • Secure Credentials: Credentials are passed via temporary env files (mode 0600), then zero-overwritten and unlinked after docker run. They never appear in process listings.
  • Auto Cleanup: Containers are removed via atexit (Ctrl+C still works normally). Disable with auto_cleanup: false to leave them stopped instead.

Container Management

# View containers
docker ps | grep unshackle-gluetun

# Check logs
docker logs unshackle-gluetun-nordvpn-us

# Remove all containers
docker ps -a | grep unshackle-gluetun | awk '{print $1}' | xargs docker rm -f

Troubleshooting

Docker Permission Denied (Linux)

sudo usermod -aG docker $USER
# Then log out and log back in

VPN Connection Failed

Check container logs for specific errors:

docker logs unshackle-gluetun-nordvpn-us

Common issues: - Invalid/missing credentials - Windscribe WireGuard requires preshared_key (can be empty string, but must be set in credentials) - VPN provider server issues - Container startup timeout (default 60 seconds)

Resources


ExpressVPN HTTPS Proxy

ExpressVPN is a standalone HTTPS proxy provider — it does not use Docker or the gluetun sub-provider system. It authenticates via a browser-extension OAuth flow (Keycloak/PKCE) and returns an authenticated https://cat:<token>@<host>:443 proxy URL.

Prerequisites

An active ExpressVPN subscription is required. The provider resolves proxy-capable locations through ExpressVPN's own API, so no local VPN client or Docker container is needed.

Authentication

The provider uses a token cascade (tried in order):

  1. Cached tokenscache/global/expressvpn_tokens.json (auto-written after first auth; access and refresh tokens are refreshed automatically when they expire).
  2. Exported browser cookiescookies/vpn/expressvpn.txt (also accepted at cookies/vpns/expressvpn.txt). Must contain the KEYCLOAK_IDENTITY and KEYCLOAK_SESSION cookies from auth.expressvpn.com. Used for a one-time PKCE bootstrap that populates the token cache.
  3. Desktop account.json — configured via the account_json key (see below).

Export cookies from a browser that is logged in to auth.expressvpn.com. Any Netscape-format, JSON array, or name=value file is accepted.

Configuration

Add to ~/.config/unshackle/unshackle.yaml under proxy_providers:

proxy_providers:
  expressvpn:
    region_map:
      us: "ny"        # --proxy expressvpn:us  →  New York (default city)
      gb: "london"    # --proxy expressvpn:gb  →  London
      de: "frankfurt" # --proxy expressvpn:de  →  Frankfurt
      es: "madrid"    # --proxy expressvpn:es  →  Madrid
      mx:             # --proxy expressvpn:mx  →  smart/random MX location

region_map maps a country code to a default city preset. An empty (null) value enables smart connection (a random location in that country). The preset is only applied when the CLI query contains no city; an explicit city in the query always takes precedence.

Optional keys

Key Default Description
region_map {} Country → default city presets (see above)
server_map {} Alias → ExpressVPN location slug or direct hostname
cookie_path cookies/vpn/expressvpn.txt Path to exported browser cookies
cache_path cache/global/expressvpn_tokens.json Token cache location
account_json (none) Path to ExpressVPN desktop account.json
refresh_token (none) OAuth refresh token (manual override)
timeout 10.0 HTTP request timeout in seconds

Usage

unshackle dl SERVICE CONTENT --proxy expressvpn:us        # random/smart US location
unshackle dl SERVICE CONTENT --proxy expressvpn:us-ny     # specific city (New York)
unshackle dl SERVICE CONTENT --proxy expressvpn:us-ny-2   # pinned server #2 in New York
unshackle dl SERVICE CONTENT --proxy expressvpn:mx        # random/smart Mexico location
unshackle dl SERVICE CONTENT --proxy expressvpn:es-madrid # specific city (Madrid)

Query format: expressvpn:<country>[-<city>[-<N>]]

  • country — 2-letter country code (e.g. us, gb, de).
  • city — optional city abbreviation or slug matched against location names using first-letter abbreviation (ny → "New York"), exact slug, prefix, then substring strategies.
  • N — optional 1-based server index (e.g. -2 selects the second server in the matched city). If N exceeds the available server count, a random server is selected.

City matching

The city part of the query is matched against ExpressVPN location names using these strategies (in priority order):

  1. First-letter abbreviation — ny matches "New York"
  2. Exact slug — miami matches "Miami"
  3. Prefix match — mia matches "Miami"
  4. Substring match — york matches "New York"

Token cache

After the first successful authentication the token cache is written to cache/global/expressvpn_tokens.json (mode 0600). Subsequent runs refresh expired access/SRT/connection tokens automatically without re-reading cookies.