tprasadtp / protonvpn-docker

ProtonVPN Wireguard Docker Image. Supports ARMv8 (64-bit ) and x86 (64-Bit).
GNU General Public License v3.0
274 stars 24 forks source link
protonvpn protonvpn-container protonvpn-docker protonvpn-wireguard protonwire vpn vpn-docker wireguard
# Protonwire - Docker Wireguard Client for ProtonVPN [![actions-build](https://github.com/tprasadtp/protonvpn-docker/actions/workflows/build.yml/badge.svg)](https://github.com/tprasadtp/protonvpn-docker/actions/workflows/build.yml) [![actions-release](https://github.com/tprasadtp/protonvpn-docker/actions/workflows/release.yml/badge.svg)](https://github.com/tprasadtp/protonvpn-docker/actions/workflows/release.yml) [![version](https://img.shields.io/github/v/tag/tprasadtp/protonvpn-docker?label=version&sort=semver&logo=semver&labelColor=3a3a3a&include_prereleases)](https://github.com/tprasadtp/protonvpn-docker/releases) [![license](https://img.shields.io/github/license/tprasadtp/protonvpn-docker?logo=github&labelColor=3A3A3A)](https://github.com/tprasadtp/protonvpn-docker/blob/master/LICENSE) [![stars](https://img.shields.io/github/stars/tprasadtp/protonvpn-docker?logo=github&labelColor=3a3a3a&style=flat)](https://github.com/tprasadtp/protonvpn-docker/stargazers/) [![slsa-badge][slsa-badge]][slsa-verify-docs] [![cosign-badge][cosign-badge]][cosign-verify-docs] [![actions-metadata](https://github.com/tprasadtp/protonvpn-docker/actions/workflows/metadata.yml/badge.svg)](https://github.com/tprasadtp/protonvpn-docker/actions/workflows/metadata.yml) [![metadata-refresh](https://img.shields.io/badge/dynamic/json?label=metadata&query=timestamp&url=https%3A%2F%2Fprotonwire-api.vercel.app&logo=protonvpn&labelColor=3a3a3a&logoColor=white&color=7f50a6)](https://protonwire-api.vercel.app/) [![metadata-servers](https://img.shields.io/badge/dynamic/json?label=servers&query=server_count&url=https%3A%2F%2Fprotonwire-api.vercel.app&logo=protonvpn&labelColor=3a3a3a&logoColor=white&color=7f50a6)](https://protonwire-api.vercel.app/) [![api-status](https://uptime.betterstack.com/status-badges/v1/monitor/1en46.svg)](https://protonwire.betteruptime.com/)

Features

Container Images

[!WARNING]

gVisor and cgroup v1 are NOT supported!

Images are published at ghcr.io/tprasadtp/protonwire.

Linux Kernel Requirements

[!IMPORTANT]

If running as a container, Wireguard MUST be installed on the host, not the container.

Generating WireGuard Private Key

[!IMPORTANT]

It is recommended to use unique private key for each instance of the the VPN container.

Environment Variables & Config

[!IMPORTANT]

Private key file MUST NOT be world-readable.

Name Default/Required Description
PROTONVPN_SERVER REQUIRED (String) ProtonVPN server to connect to.
WIREGUARD_PRIVATE_KEY Required if not specified via mount or secrets (String) Wireguard Private key
IPCHECK_URL https://icanhazip.com/ (String) URL to check client IP.
IPCHECK_INTERVAL 60 (Integer) Interval between internal health-checks in seconds. Set this to 0 to disable IP checks.
SKIP_DNS_CONFIG false (Boolean) Set this to 1 or true to skip configuring DNS.
KILL_SWITCH false (Boolean) Enable KillSwitch (Experimental)

PROTONVPN_SERVER

This should be server DNS name like, node-nl-01.protonvpn.net or IP address like 91.229.23.180. Server name like NL#1(or NL-1) may work for pro servers, it is not recommended.

[!IMPORTANT]

Script cannot validate if specified server is available under your plan. It is user's responsibility to ensure that server specified is available under your subscription and supports required features, like P2P, Streaming etc. Use --p2p, --streaming, --secure-core flags to enable client side validations.

KillSwitch

[!WARNING]

This feature is experimental and is NOT covered by semver compatibility guarantees.

Kill-Switch is not a hard kill-switch but more of an internet kill-switch. LAN addresses, Link-Local addresses and CGNAT (also Tailscale) addresses remain reachable. Unlike most VPN containers, kill-switch is implemented via routing policies, routing priorities and custom route tables rather than firewall rules.

Usage


ProtonVPN WireGuard Client

Usage: protonwire [OPTIONS...]
or: protonwire [OPTIONS...] c|connect [SERVER]
or: protonwire [OPTIONS...] d|disconnect
or: protonwire [OPTIONS...] check
or: protonwire [OPTIONS...] disable-killswitch
or: protonwire [OPTIONS...] server-info [SERVER]

Options:
  -k, --private-key FILE|KEY    Wireguard private key or
                                file containing private key
      --service                 Run as service
      --service-status-file     Use status file created by --service
                                for healthchecks. Only valid when both process
                                are running within the same container.
      --metadata-url URL        Server metadata endpoint URL
      --check-interval INT      IP check interval in seconds (default 60)
      --check-url URL           IP check endpoint URL
      --skip-dns-config         Skip configuring DNS.
                                (Useful for Kubernetes and Consul)
      --kill-switch             Enable killswitch (Experimental)
      --p2p                     Verify if specified server supports P2P
      --streaming               Verify if specified server supports streaming
      --tor                     Verify if specified server supports Tor
      --secure-core             Verify if specified server supports secure core
  -q, --quiet                   Show only errors
  -v, --verbose                 Show debug logs
  -h, --help                    Display this help and exit
      --version                 Display version and exit

Examples:
  protonwire connect nl-1       Connect to server nl-1
  protonwire d --kill-switch    Disconnect from current server and disable kill-switch
  protonwire verify [SERVER]    Check if connected to a server

Files:
  /etc/protonwire/private-key   WireGuard private key

Environment:
  WIREGUARD_PRIVATE_KEY         WireGuard private key or file
  PROTONVPN_SERVER              ProtonVPN server
  IPCHECK_INTERVAL              Custom IP check interval in seconds (default 60)
  IPCHECK_URL                   IP check endpoint URL (must be https://)
  SKIP_DNS_CONFIG               Set to '1' to skip configuring DNS
  KILL_SWITCH                   Set to '1' to enable killswitch (Experimental)
  DEBUG                         Set to '1' to enable debug logs

Health-checks

Docker Compose

If entire stack is in a single compose file, then network_mode: service:protonwire on the services which should be routed via VPN. If the VPN stack is NOT in same compose file use network_mode: container:<protonwire-container-name>.

As an example, run caddy web-server, proxying https://ip.me, via VPN using the compose config given below. Once the stack is up, visiting the http://localhost:8000, or curl -s http://localhost:8000 should show VPN's country and IP address.

version: '2.3'
services:
  protonwire:
    container_name: protonwire
    # Use semver tags or sha256 hashes of manifests.
    # using latest tag can lead to issues when used with
    # automatic image updaters like watchtower/podman.
    image: ghcr.io/tprasadtp/protonwire:latest
    init: true
    restart: unless-stopped
    environment:
      # Quote this value as server name can contain '#'.
      PROTONVPN_SERVER: "node-nl-96.protonvpn.net"  # NL-FREE#100070
      # Set this to 1 to show debug logs for issue forms.
      DEBUG: "0"
      # Set this to 0 to disable kill-switch.
      KILL_SWITCH: "1"
    # NET_ADMIN capability is mandatory!
    cap_add:
      - NET_ADMIN
    # sysctl net.ipv4.conf.all.rp_filter is mandatory!
    # net.ipv6.conf.all.disable_ipv6 disables IPv6 as protonVPN does not support IPv6.
    # 'net.*' sysctls are not required on application containers,
    # as they share network stack with protonwire container.
    sysctls:
      net.ipv4.conf.all.rp_filter: 2
      net.ipv6.conf.all.disable_ipv6: 1
    volumes:
      - type: tmpfs
        target: /tmp
      - type: bind
        source: private.key
        target: /etc/protonwire/private-key
        read_only: true
    ports:
      - 8000:80
  # This is sample application which will be routed over VPN
  # Replace this with your preferred application(s).
  caddy_proxy:
    image: caddy:latest
    network_mode: service:protonwire
    command: |
      caddy reverse-proxy \
          --change-host-header \
          --from :80 \
          --to https://ip.me:443

[!IMPORTANT]

  • It is essential to expose/publish port(s) on protonwire container, instead of application container.
  • SHOULD NOT run the container as privileged. Adding capability CAP_NET_ADMIN AND defined sysctls should be sufficient.
  • Value for PROTONVPN_SERVER must be enclosed within quotes as server name can contain '#'

Podman

This section covers running containers via podman. But for deployments use podman's systemd integration.

[!IMPORTANT]

  • The above example publishes container port 8000 to host port 8000. You MUST change these to match your application container(s).
  • To publish additional ports from other containers using this VPN (usually done via argument --publish <host-port>:<container-port>), it MUST be done on protonwire container.
  • --sysctl flags are important! without these, container cannot create/manage WireGuard interface.
  • mode=600 in secret mount is important, as script refuses to use private key with insecure permissions.
  • If using pods, sysctls MUST be defined on the pod no the protonwire container.

Docker

[!IMPORTANT]

  • To publish additional ports from other containers using this VPN, it MUST be done on the protonwire container!
  • --sysctl and --cap-add flags are important! without these, container cannot create or manage WireGuard interfaces or routing.
  • docker rootless should also work just fine for most users, but is considered experimental.

Troubleshooting & FAQ

See Troubleshooting and FAQ

SLSA Provenance

[![slsa-badge-level3][slsa-badge-full-level3]][slsa-level3]

All artifacts provided by this repository meet SLSA L3. See docs for more info.

Cosign Images

All artifacts provided by this repository are signed using cosign. See docs for more info.

Building

Building requires task, go crane and docker with buildx plugin.