- migrate persisted server data storage from `/gluetun/servers.json` to `/gluetun/servers/`
- add `STORAGE_SERVERS_ENABLED=on` to enable or disable on-disk server data storage
- add `STORAGE_SERVERS_DIRECTORY_PATH=/gluetun/servers` to configure where per-provider server files are stored
- keep backward compatibility with legacy `STORAGE_FILEPATH=/gluetun/servers.json`
- automatically read and migrate legacy `/gluetun/servers.json` into the new `/gluetun/servers/` layout when needed
- try to remove the legacy servers file after a successful migration to the new storage directory
- switch persisted server data from one large JSON file to a manifest plus per-provider JSON files
- add `UPDATER_PREFER_DIRECT_DOWNLOAD` to allow preferring direct download of provider server data
- keep deprecated updater flags `-enduser` and `-maintainer` as no-op warnings for backward compatibility
- preserve compatibility checks so persisted server data is discarded when its schema version no longer matches the built-in data
- allow preferred persisted provider data to override built-in data when versions match
- servers data now lives at https://github.com/qdm12/gluetun-servers/tree/main/pkg/servers
- force to set `DNS_UPSTREAM_RESOLVER_TYPE=plain` to avoid any confusion/security hole
- force to set `DNS_UPSTREAM_PLAIN_ADDRESSES` to addresses only with port 53
- main reason being it's a burden to always define sentinel errors at global scope, wrap them with `%w` instead of using a string directly
- only use sentinel errors when it has to be checked using `errors.Is`
- replace all usage of these sentinel errors in `fmt.Errorf` with direct strings that were in the sentinel error
- exclude the sentinel error definition requirement from .golangci.yml
- update unit tests to use ContainersError instead of ErrorIs so it stays as a "not a change detector test" without requiring a sentinel error
- handle timed out connections the same as closed connections
- close connection on TLS handshake failure
- improve mutex handling during connection renewal and retrieval
- add option `IPV6_CHECK_ADDRESSESES=[2001:4860:4860::8888]:53,[2606:4700:4700::1111]:53`
- gluetun needs access to the addresses above through the host firewall, to test ipv6 support before setting up the vpn
- start DNS server before healthcheck
- do not fallback to plaintext anymore
- allow to use plain addresses with a port different than 53, system-wide
- do not wait for the DNS server and rely on healtcheck only
- firewall log level is still fully controlled by `LOG_LEVEL`
- iptables log level defaults to `info` even if global log level is `debug` to minimize the amount of debug logs
- iptables log level is only set to debug if retro-compatible `FIREWALL_DEBUG=on` or if `FIREWALL_IPTABLES_LOG_LEVEL=debug`
- amneziawg is now a VPN protocol and no longer a Wireguard implementation
- Use it with VPN_TYPE=amneziawg
- document AMNEZIAWG_* options in Dockerfile
- document amneziawg support in readme
- separate amneziawg settings and code from wireguard
- re-use code from wireguard whenever possible
- Remove `DNS_SERVER` (aka DOT) option: the DNS server forwarder part is now always enabled (see below why)
- Remove `DNS_KEEP_NAMESERVER`: the container will always use the built-in DNS server forwarder, because it can handle now local names with local resolvers (see #2970), it can use the `plain` upstream type (see https://github.com/qdm12/gluetun/commit/5ed6e8292278b54bb5081de0e8ccd0d63a275b3c) AND you can use `DNS_UPSTREAM_PLAIN_ADDRESSES` (see below)
- Replace `DNS_ADDRESS` with `DNS_UPSTREAM_PLAIN_ADDRESSES`:
- New CSV format with port, for example `ip1:port1,ip2:port2`
- requires `DNS_UPSTREAM_TYPE=plain` to be set to use `DNS_UPSTREAM_PLAIN_ADDRESSES` (unless using retro `DNS_ADDRESS`)
- retrocompatibility with `DNS_ADDRESS`. If set, force upstream type to plain and empty user-picked providers. 127.0.0.1 is now ignored since it's always set to this value internally.
- Warning log on using private upstream resolvers updated
- Warning log if using a private IP address for the plain DNS server which is not in your local subnets
All in all, this greatly simplifies code and available options (less options for the same features is a win). It also allows you to specify multiple plain DNS resolvers on ports other than 53 if needed.
- prevent dns plaintext manipulation both the periodic update and when running in cli mode
- possibly higher reliability on poor connections versus UDP
- drop `-dns` flag in update command
- for now no configuration allowed since it makes everything rather complex
- Fix#3179
- I believe specifying tcp4, tcp6 or tcp-client does not change anything versus tcp + remote ip address
- I believe specifying udp4 or udp6 does not change anything versus tcp + remote ip address
- Simplify firewall code to not account for tcp-client etc.
- restore if IPv4 set all policies fails
- fix deadlock when using iptables custom rules
- fix setting ipv6 rules when running runMixedIptablesInstruction
- all operations rollback on failure
- disabling the firewall means rolling back to its state before enabling it
- aligns with nftables atomicity feature
- prevent leaks for connections made the first ~10 milliseconds when Gluetun starts
- seems critical, but in practice this very rarely happen and it very hard to reproduce
- Fix DNS blocklists slow downloads, fix#3102
- Leave 35s timeout for updaters
- Set timeouts to 1s for local calls
- Set timeouts to 5s for LAN VPN calls and small external calls
- Set timeouts to 10s external VPN API calls
- this makes PMTUD TCP reliable
- this only works on kernels with the mark module
- on kernels without the mark module, the icmp pmtud mtu found is used
- Existing option `WIREGUARD_MTU` , if set, disables PMTUD and is used
- New option `PMTUD_ICMP_ADDRESSES=1.1.1.1,8.8.8.8` and `PMTUD_TCP_ADDRESSES=1.1.1.1:443,8.8.8.8:443`
- ICMP PMTUD now targets external-by-default IP addresses
- New TCP PMTUD (binary search only) as a second MTU confirmation and fallback mechanism.
- Force set TCP MSS to MTU - IP header - TCP base header - "magic 20 bytes" 🎆
- Fix#3108
- force users to set a timestamp as the current one if manually editing servers.json which they should not do anyway
- favor future servers data updates through a container image pull to override older user-defined data
- easier debug logs flow
- MAY cost less conntrack-ed slots on the VPN server
- resets id and sequence to 1 when reconnecting VPN
- resets id and sequence to 1 after 5 minutes
- resets id and sequence to 1 if sequence is complete (65535)
- Specify fallback ICMP IP addresses
- Defaults changed from 1.1.1.1 to 1.1.1.1,8.8.8.8
- Small periodic check cycles through addresses as it fails and moves to retry
- Specify fallback addresses
- Defaults changed from cloudflare:443 to cloudflare:443,github.com:443
- Startup check runs a parallel dial to each of the addresses specified with a global 6s timeout
- Full periodic check cycles through addresses as it fails and moves to retry
- `-proton-username` flag for cli update
- `-proton-password` flag for cli update
- `UPDATER_PROTONVPN_USERNAME` option for periodic updates
- `UPDATER_PROTONVPN_PASSWORD` option for periodic updates
- For example: `{"auth":"basic","username":"me","password":"pass"}`
- For example`{"auth":"apiKey","apikey":"xyz"}`
- For example`{"auth":"none"}` (I don't recommend)
- This route has nothing to do with openvpn specifically
- Remove the `ed` in `portforwarded` to accomodate future routes such as changing the state of port forwarding
- maintaining retrocompatibility with `/v1/openvpn/portforwarded`
- maintaining retrocompatibility with `/openvpn/portforwarded`
- Moved to its own handler `/v1/portforward` instead of `/v1/vpn/portforward` to reduce the complexity of the vpn handler
- Migrate `DOT` to `DNS_SERVER`
- Migrate `DOT_PROVIDERS` to `DNS_UPSTREAM_RESOLVERS`
- Migrate `DOT_PRIVATE_ADDRESS` to `DNS_PRIVATE_ADDRESSES`
- Migrate `DOT_CACHING` to `DNS_CACHING`
- Migrate `DOT_IPV6` to `DNS_UPSTREAM_IPV6`
- Cloudflare's 1.1.1.1 seems more reliable than the VPN server public IP address you connect to
- This can still be changed back to 0.0.0.0 to use the VPN server IP address if needed
- Alpine / iptables-legacy bug introduced in Alpine 3.22
- Alpine: what the hell? Stop introducing breaking changes in iptables on every god damn release!
- Added safety to prevent panics/errors when skipping CI checks (shame on me, sometimes)
- Opens new possibilities for end to end integration tests. PRs accepted!
- You should really leave it to `on` ⚠️
- Turn it to `off` if you have trust issues with the healthcheck. Don't then report issues if the connection is dead though.
- run small check every 60s, from 15s
- small check (icmp/dns) initial timeout from 3s to 10s
- small check (icmp/dns) timeout increase from 1s to 10s
- full check initial timeout increased from 10s to 20s
- full check extra timeout increase from 3s to 10s
- New option: `HEALTH_ICMP_TARGET_IP` defaults to `0.0.0.0` meaning use the VPN server public IP address.
- Options removed: `HEALTH_VPN_INITIAL_DURATION` and `HEALTH_VPN_ADDITIONAL_DURATION` - times and retries are handpicked and hardcoded.
- Less aggressive checks and less false positive detection
- Reduce silly image pull rate limiting from docker hub registry
- still rely on docker hub registry to pull golang and alpine images since these are not on ghcr.io
See [release notes](https://github.com/qdm12/godevcontainer/releases/tag/v0.21.0)
Notably:
- Go upgraded from 1.23 to 1.25
- golangci-lint upgraded to v2.4.0
- Alpine upgraded from 3.20 to 3.22
- Disable package comment requirement by gopls' staticcheck
- Pull container image from ghcr.io
- do not log dial error twice
- DNS subserver shuts down without waiting for connections to finish (UDP server would hang sometimes)
- DNS over TLS dialer uses tls.Dialer instead of wrapping connection with tls.Client
- connection type is just `tls` instead of `dns over tls` to reduce repetition in logs
- exchange errors contain the request question in their context
- `PUBLICIP_API` accepts a comma separated list of ip data sources, where the first one is the base default one, and sources after it are backup sources used if we are rate limited.
- `PUBLICIP_API` defaults to `ipinfo,ifconfigco,ip2location,cloudflare` such that it now has `ifconfigco,ip2location,cloudflare` as backup ip data sources.
- `PUBLICIP_API_TOKEN` accepts a comma separated list of ip data source tokens, each corresponding by position to the APIs listed in `PUBLICIP_API`.
- logs ip data source when logging public ip information
- assume a rate limiting error is for 30 days (no persistence)
- ready for future live settings updates
- consider an ip data source no longer banned if the token changes
- keeps track of ban times when updating the list of fetchers
- remove Windows without WSL step
- update 'remote containers extension' to 'dev containers extension'
- remove invalid warning on directories creation
- simplify customizations section
- remove "publish a port" since it can be done at runtime now
- remove "run other services" since it's rather unneeded in this case
- expand documentation on custom welcome script and where to specify the bind mount
- use bullet points instead of subsections headings
- No point periodically fetch the public IP address. Could not find anything mentioning why this was added.
- Simplification of the publicip loop code
- `PUBLICIP_ENABLED` (on, off) can be set to enable or not public ip data fetching on VPN connection
- `PUBLICIP_PERIOD=0` still works to indicate to disable public ip fetching
- `PUBLICIP_PERIOD` != 0 means to enable public ip fetching
- Warnings logged when using `PUBLICIP_PERIOD`
- Faster start up
- Clearer error messages
- Allow for more Gluetun-specific customization
- DNSSEC validation is dropped for now (it's sort of unneeded)
- Fix#137
- Build API IP address using the first 2 bytes of the gateway IP and adding `128.1` to it
- API IP address is valid for both OpenVPN and Wireguard
- Fix#2320
- `STORAGE_FILEPATH=` disables storing to and reading from a local servers.json file
- `STORAGE_FILEPATH` defaults to `/gluetun/servers.json`
- Fix#2074
- Disallow setting a server filter when there is no choice available
- Allow setting an invalid server filter when there is at least one choice available
- Log at warn level when an invalid server filter is set
- Fix#2337
- Split `VPN_ENDPOINT_IP` in `OPENVPN_ENDPOINT_IP` and `WIREGUARD_ENDPOINT_IP`
- Split `VPN_ENDPOINT_PORT` in `OPENVPN_ENDPOINT_PORT` and `WIREGUARD_ENDPOINT_PORT`
- Fixes bad usage of Wireguard config file endpoint for OpenVPN #2347
- Retro-compatible with `OPENVPN_USER` + `OPENVPN_PASSWORD`
- No more reading for the OpenVPN auth file
- Allow to use PIA port forwarding with Wireguard
- Prevents requesting the public IP address N times after N VPN failures
- Fetching runs with a context local to the 'single run'
- Single run writes single run result to a channel back to the caller, RunOnce is now blocking
- Healthcheck timeout is no longer fixed to 3 seconds
- Healthcheck timeout increases from 2s to 4s, 6s, 8s, 10s
- No 1 second wait time between check retries after failure
- VPN internal restart may be delayed by a maximum of 10 seconds
- Retro-compatible variable key CONTROL_SERVER_ADDRESS was never defined
- Old variable key CONTROL_SERVER_PORT was removed in v3.28.0 and no complain so far
- Private key from `/run/secrets/wireguard_private_key` (path configurable with `WIREGUARD_PRIVATE_KEY_SECRETFILE`)
- Preshared key from `/run/secrets/wireguard_preshared_key` (path configurable with `WIREGUARD_PRESHARED_KEY_SECRETFILE`)
- Addresses from `/run/secrets/wireguard_addresses` (path configurable with `WIREGUARD_ADDRESSES_SECRETFILE`)
A service start error can happen if the service is started after the Wireguard VPN tunnel is up, but the tunnel does not work. The VPN is then internally restarted, causing the service start error, so it should not be treated as a critical error.
- Update URLs logged by program
- Update README.md links
- Update contributing guide link
- Update issue templates links
- Replace Wiki issue template by link to Gluetun Wiki repository issue creation
- Set program announcement about Github wiki new location
- remove `UPDATER_VPN_SERVICE_PROVIDERS` in docker-compose config
- remove Slack channel link (don't have time to check it)
- Update Wireguard native integrations support list
- Netlink linux tagged files
- Netlink linux || darwin tagged files
- Create non-implemented files for NOT linux
- Create non-implemented files for NOT linux and NOT darwin
- Specify wireguard netlink integration test as for linux only
- Move `Addr` and its `String` method to `types.go`
- Move `IsWireguardSupported` to `wireguard.go` to have `family.go` OS independant
- Remove dependency on vishvananda/netlink in `ipv6.go`
- Move `Link` to `types.go`
- Move `Route` to `types.go`
- Move `Rule` and its `String` method to `types.go`
- `OPENVPN_IPV6` removed
- Affects OpenVPN
- Use the same mechanism for OpenVPN and Wireguard
- Check only once at program start since this is unlikely to change at runtime
- Log if IPv6 is supported
- Remove `IPv6` boolean from settings structs
- Move IPv6 detection as a method on NetLinker
- Extract base64 data from PEM files and secret files
- Environment variables are not PEM encoded and only the base64 data
- Affects OpenVPN certificate, key and encrypted key
- `internal/updater/html` package
- Add unit tests for slickvpn updating code
- Change shared html package to be more share-able
- Split html utilities in multiple files
- Fix processing .ovpn files with prefix space
Authored by @Rohaq
Co-authored-by: Quentin McGaw <quentin.mcgaw@gmail.com>
- Fix Slowloris attacks on HTTP servers
- Force set default of 5 minutes for pprof read timeout
- Change `ShutdownTimeout` to time.Duration since it cannot be set to 0
- Run only on base repository
- Rename job from `dockerHubDescription` to `docker-hub-description`
- Limit permissions of job to read only
- Remove unneeded names for steps
* Fragment was defined in `OpenVPNProviderSettings` but was not written to the OpenVPN configuration file.
* Added two additional ciphers to the configuration for ExpressVPN
Authored-by: barino86 <barino@mac.com>
- Exported `Fetcher` interface
- Inject `Fetcher` to publicip loop and updaters
- Get public IP and information at the same time
- Only query ipinfo.io
- Make `MultiInfo` part of the `Fetch` object
- Fix CLI operation not setting DNS server
- Fix periodic operation not setting DNS server
- Set DNS address for resolution once at start for both CLI and periodic operation
- Inject resolver to each provider instead of creating it within
- Use resolver settings on every call to `.Resolve` method, instead of passing it to constructor
- Move out minServers check from resolver
- Each provider interface can now fetch updated servers data
- Rename each provider updater subpackage name to `updater`
- Updater constructor does not take a settings struct
- Updater update method takes in a slice of provider strings
- Pass min servers to resolve call
- Set settings when constructing resolver
- Construct resolver in each provider updater
- No more common resolver for all providers
- settings: get filter choices from storage for settings validation
- updater: update servers to the storage
- storage: minimal deep copying and data duplication
- storage: add merged servers mutex for thread safety
- connection: filter servers in storage
- formatter: format servers to Markdown in storage
- PIA: get server by name from storage directly
- Updater: get servers count from storage directly
- Updater: equality check done in storage, fix#882
- Remove unneeded ctx error check in cyberghost updating code
- Move global scope caser to function local scope
- Return error if updating a single provider in `UpdateServers`
- Add comments on different error paths in `UpdateServers`
- Do not export updater interface
- Export updater struct
- Define local interfaces where needed
- More restrictive updater loop interface in http control server
- Inject `Updater` into updater loop as an interface
- From `pia` to `private internet access`
- From `perfectprivacy` to `perfect privacy`
- From `vpnunlimited` to `vpn unlimited`
- This is done to match string constants in the code for another refactor
- Reset each of these providers servers version to `1`.
- `HEALTH_TARGET_ADDRESS` to replace `HEALTH_ADDRESS_TO_PING`
- Remove `github.com/go-ping/ping` dependency
- Dial TCP the target address, appending `:443` if port is not set
- Accept output traffic from all default routes through VPN interface
- Accept output from all default routes to outbound subnets
- Accept all input traffic on ports for all default routes
- Add IP rules for all default routes
- Move validation functions from `internal/constants` to `internal/configuration/settings/validation`
- Concatenate all OpenVPN constants in `internal/constants/openvpn.go`
- `BLOCK_NSA` has precedence over `BLOCK_SURVEILLANCE`
- `HEALTH_OPENVPN_DURATION_ADDITION` has precedence over `HEALTH_VPN_DURATION_ADDITION`
- `HEALTH_OPENVPN_DURATION_INITIAL` has precendence over `HEALTH_VPN_DURATION_INITIAL`
- Chain of precedence: `PROXY` > `TINYPROXY` > `HTTPPROXY`
- Chain of precedence: `PROXY_LOG_LEVEL` > `TINYPROXY_LOG` > `HTTPPROXY_LOG`
- `PROTOCOL` has precendence over `OPENVPN_PROTOCOL`
- `IP_STATUS_FILE` has precendence over `PUBLICIP_FILE`
- `SHADOWSOCKS_PORT` has precedence over `SHADOWSOCKS_LISTENING_ADDRESS`
- `SHADOWSOCKS_METHOD` has precedence over `SHADOWSOCKS_CIPHER`
- Better settings tree structure logged using `qdm12/gotree`
- Read settings from environment variables, then files, then secret files
- Settings methods to default them, merge them and override them
- `DNS_PLAINTEXT_ADDRESS` default changed to `127.0.0.1` to use DoT. Warning added if set to something else.
- `HTTPPROXY_LISTENING_ADDRESS` instead of `HTTPPROXY_PORT` (with retro-compatibility)
- Only trigger on push and PR to master
- Do not push images for branches
- Add fork only workflow
- Add dependabot only workflow
- Do not trigger ci workflow from forked/dependabot PRs
- Perfect privacy to accept AES-256-CBC and AES-256-GCM
- Cyberghost default cipher set to AES-256-GCM
- `OPENVPN_CIPHER` accept comma separated cipher values
- Use `ncp-ciphers` for OpenVPN 2.4
- Filter was not effective
- Is to be deprecated in v4 anyway
- Bump NordVPN server model version to `3`
- Remove `Name` field from NordVPN server model
- Use the built-in healthcheck vpn restart mechanism instead
- Restarting with `ping-restart` or `ping-exit` would only restart with the same `remote` connection
- Specify `ping` options as VPN specific to ensure the server doesn't disconnect us
- Retro-compatibility: `OPENVPN_CUSTOM_CONFIG` set implies `VPNSP=custom`
- Change: `up` and `down` options are not filtered out
- Change: `OPENVPN_INTERFACE` overrides the network interface defined in the configuration file
- Change: `PORT` overrides any port found in the configuration file
- Feat: config file is read when building the OpenVPN configuration, so it's effectively reloaded on VPN restarts
- Feat: extract values from custom file at start to log out valid settings
- Maint: `internal/openvpn/extract` package instead of `internal/openvpn/custom` package
- Maint: All providers' `BuildConf` method return an error
- Maint: rename `CustomConfig` to `ConfFile` in Settings structures
- Feat: allow to change VPN type at runtime
- Feat: allow to change interface name at runtime
- Maint: Add cleanup method to cleanup VPN loop on a vpn shutdown
- Change: allow VPN inputs ports only when tunnel is up
- Defaults to `1.1.1.1`
- Add more Ping integration tests with different addresses
- Add unit test pinging 127.0.0.1
- Add comment explaining why we need to use ICMP instead of UDP
- `HEALTH_OPENVPN_DURATION_INITIAL` renamed to `HEALTH_VPN_DURATION_INITIAL` with retro-compatiblity
- `HEALTH_OPENVPN_DURATION_ADDITION` renamed to `HEALTH_VPN_DURATION_ADDITION` with retro-compatiblity
- Defaults to `strong` instead of strong certificate string
- No impact on Docker images since variable is set to `strong` in Dockerfile
- Only read `PIA_ENCRYPTION` if service provider is PIA
- No more global variables
- Inject merged servers to configuration package
- Fix#566: configuration parsing to use persisted servers.json
- Move server data files from `internal/constants` to `internal/storage`
- Take in `src` as `*net.IPNet` instead of `net.IP`
- Take `dst` IP network
- Debug logged `ip rule` dynamically built
- Add unit tests for all IP rules functions
- Use IVPN's HTTP API instead of their .zip file
- Unit tests for API and GetServers
- Paves the way for Wireguard
- Update server information for IVPN
- Add `ISP` filter for IVPN
- `internal/wireguard` client package with unit tests
- Implementation works with kernel space or user space if unavailable
- `WIREGUARD_PRIVATE_KEY`
- `WIREGUARD_ADDRESS`
- `WIREGUARD_PRESHARED_KEY`
- `WIREGUARD_PORT`
- `internal/netlink` package used by `internal/wireguard`
- Fix: custom config with custom network interface name for firewall
- Keep VPN tunnel interface in firewall state
- Vul fix: only allow traffic through vpn interface when needed
- Adapt code to adapt to network interface name
- Remove outdated TUN and TAP constants
- Add VPN field to ServerSelection struct
- Set VPN type to server selection at start using VPN_TYPE
- Change OpenVPNConnection to Connection with Type field
- Rename Provider GetOpenVPNConnection to GetConnection
- Rename GetTargetIPOpenVPNConnection to GetTargetIPConnection
- Rename PickRandomOpenVPNConnection to PickRandomConnection
- Add 'OpenVPN' prefix to OpenVPN specific methods on connection
- Moved from openvpn package to tun package
- TUN check verifies Rdev value
- TUN create
- Inject as interface to main function
- Add integration test
- Clearer log message for end users if tun device does not exist
- Remove unix package (unneeded for tests)
- Remove tun file opening at the end of tun file creation
- Do not mock unix.Mkdev (no OS operation)
- Remove Tun operations from OpenVPN configurator
- Move network protocol from ServerSelection to OpenVPNSelection child
- Move PIA encryption preset from ServerSelection to OpenVPNSelection child
- Move custom port from ServerSelection to OpenVPNSelection child
- Paves the way for Wireguard
- VPN struct contains Type, Openvpn and Provider configurations
- OpenVPN specific options (e.g. client key) moved from Provider to Openvpn configuration struct
- Move Provider configuration from OpenVPN configuration to VPN
- HTTP control server returns only openvpn settings (not provider settings)
- Allow multiple comma separated values for CYBERGHOST_GROUP
- Defaults to all UDP groups
- If TCP is enabled, defaults to all TCP groups
- Check groups specified match the protocol
- Default Cyberghost group to empty
- Adjust formatting and messages
See https://blog.windscribe.com/openvpn-security-improvements-and-changes-7b04ea49222
> OpenVPN compression phaseout is in progress and will be completed by August 3rd 2021.
If you downloaded configs from this page before you saw this message, you need to re-download them now, or simply remove the compress or comp-lzo flags from the config that you downloaded after July 20th 2021.
- Server information, versions and timestamps together in internal/constants/servers.json
- breaking change: updater cli uses -enduser instead of -file
- breaking change: updater cli uses -maintainer instead of -stdout
- Fix: replace special last a character with 'a' from Bogota for PrivateVPN
- Feat: do not write out servers and timestamp if no change was detected
- Openvpn and Unbound do not receive OS signals
- Openvpn and Unbound run in a different process group than the entrypoint
- Openvpn and Unbound are gracefully shutdown by the entrypoint
- Update golibs with a modified command package
- Update dns to v1.9.0 where Unbound is luanched in its own group
- Install g++ in base image before copying code
- Install xcputranslate in base image before copying code
- Install golangci-lint in base image before copying code
- Install golangci-lint using go get directly
- Order of threads to shutdown (control then tickers then health etc.)
- Rely on closing channels instead of waitgroups
- Move exit logs from each package to the shutdown package
- Fallback on IP from configuration file if DNS resolution fails
- Download both TCP and UDP zip files to detect support for each
- Filter servers by supported network protocol
-
- Require at least 80% of number of servers now to pass
- Each provider is in its own package with a common structure
- Unzip package with unzipper interface
- Openvpn package with extraction and download functions
- Parallel resolver to resolve multiple hosts
- Repeat resolver to repeat resolution for a single host
- Additional parameters for fault toleration
- Do not update servers if e.g. > 10% DNS resolutions failed
- resolver package in updater package
- Bind mount for root only
- Support for Windows Hyperv bind mounts
- Run go mod tidy after go mod download
- Use :z flag for possibly shared bind mounts
- Bind mount zsh_history
- Bind mount docker config directory
- Feature/Bugfix: Block all IPv6 traffic with `ip6tables` by default
- Feature: Adapt existing firewall code to handle IPv4 and IPv6, depending on user inputs and environment
- Maintenance: improve error wrapping in the firewall package
- OS custom internal package for file system interaction
- Remove fileManager external dependency
- Closer API to Go's native API on the OS
- Create directories at startup
- Better testability
- Move Unsetenv to os interface
- CRUD REST HTTP server
- `/v1` HTTP server prefix
- Retrocompatible with older routes (redirects to v1 or handles the requests directly)
- DNS, Updater and Openvpn refactored to have a REST-like state with new methods to change their states synchronously
- Openvpn, Unbound and Updater status, see #287
- Only accepts HTTP 1.x protocols
- Only checks the credentials when the method is `CONNECT` or the request URL is absolute
- More logging on authorization failures
- Removes the authorization headers before forwarding the HTTP(s) requests
- Refers to #298
* Reads the client key from /gluetun/client.key
* Read the client certificate from /gluetun/client.crt
* Additional checks for client key and client certificate validity
* Fix client key file parsing if environment variable isn't present
- [VS code dev containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) installed
- [Docker](https://www.docker.com/products/docker-desktop) installed and running
## Setup
1. Create the following files and directory on your host if you don't have them:
```sh
touch ~/.gitconfig ~/.zsh_history
mkdir -p ~/.ssh
```
1. **For OSX hosts**: ensure the project directory and your home directory `~` are accessible by Docker.
1. Open the command palette in Visual Studio Code (CTRL+SHIFT+P).
1. Select `Dev-Containers: Open Folder in Container...` and choose the project directory.
## Customization
For any customization to take effect, you should "rebuild and reopen":
1. Open the command palette in Visual Studio Code (CTRL+SHIFT+P)
2. Select `Dev-Containers: Rebuild Container`
Changes you can make are notably:
- Changes to the Docker image in [Dockerfile](Dockerfile)
- Changes to VSCode **settings** and **extensions** in [devcontainer.json](devcontainer.json).
- Change the entrypoint script by adding a bind mount in [devcontainer.json](devcontainer.json) of a shell script to `/root/.welcome.sh` to replace the [current welcome script](https://github.com/qdm12/godevcontainer/blob/master/shell/.welcome.sh). For example:
```json
// Welcome script
{
"source": "/yourpath/.welcome.sh",
"target": "/root/.welcome.sh",
"type": "bind"
},
```
- More options are documented in the [devcontainer.json reference](https://containers.dev/implementors/json_reference/).
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
## Contributors
Thanks for all the contributions, whether small or not so small!
- [@JeordyR](https://github.com/JeordyR) for testing the Mullvad version and opening a [PR with a few fixes](https://github.com/qdm12/gluetun/pull/84/files) 👍
- [@rorph](https://github.com/rorph) for a [PR to pick a random region for PIA](https://github.com/qdm12/gluetun/pull/70) and a [PR to make the container work with kubernetes](https://github.com/qdm12/gluetun/pull/69)
- [@JesterEE](https://github.com/JesterEE) for a [PR to fix silly line endings in block lists back then](https://github.com/qdm12/gluetun/pull/55) 📎
- [@elmerfdz](https://github.com/elmerfdz) for a [PR to add timezone information to have correct log timestampts](https://github.com/qdm12/gluetun/pull/51) 🕙
- [@Juggels](https://github.com/Juggels) for a [PR to write the PIA forwarded port to a file](https://github.com/qdm12/gluetun/pull/43)
- [@gdlx](https://github.com/gdlx) for a [PR to fix and improve PIA port forwarding script](https://github.com/qdm12/gluetun/pull/32)
- [@janaz](https://github.com/janaz) for keeping an eye on [updating things in the Dockerfile](https://github.com/qdm12/gluetun/pull/8)
Thanks for taking the time to fill out this bug report!
⚠️ Your issue will be instantly closed as not planned WITHOUT explanation if:
- you do not fill out **the title of the issue** ☝️
- you do not provide the **Gluetun version** as requested below
- you provide **less than 10 lines of logs** as requested below
- type:dropdown
id:urgent
attributes:
label:Is this urgent?
description:|
Is this a critical bug, or do you need this fixed urgently?
If this is urgent, note you can use one of the [image tags available](https://github.com/qdm12/gluetun-wiki/blob/main/setup/docker-image-tags.md) if that can help.
options:
- "No"
- "Yes"
- type:input
id:host-os
attributes:
label:Host OS
description:What is your host OS?
placeholder:"Debian Buster"
- type:dropdown
id:cpu-arch
attributes:
label:CPU arch
description:You can find it on Linux with `uname -m`.
options:
- x86_64
- aarch64
- armv7l
- "386"
- s390x
- ppc64le
- type:dropdown
id:vpn-service-provider
attributes:
label:VPN service provider
options:
- AirVPN
- Custom
- Cyberghost
- ExpressVPN
- FastestVPN
- Giganews
- HideMyAss
- IPVanish
- IVPN
- Mullvad
- NordVPN
- Privado
- Private Internet Access
- PrivateVPN
- ProtonVPN
- PureVPN
- SlickVPN
- Surfshark
- TorGuard
- VPNSecure.me
- VPNUnlimited
- VyprVPN
- Windscribe
validations:
required:true
- type:dropdown
id:docker
attributes:
label:What are you using to run the container
options:
- docker run
- docker-compose
- Portainer
- Kubernetes
- Podman
- Unraid
- Other
validations:
required:true
- type:input
id:version
attributes:
label:What is the version of Gluetun
description:|
Copy paste the version line at the top of your logs.
It MUST be in the form `Running version latest built on 2020-03-13T01:30:06Z (commit d0f678c)`.
validations:
required:true
- type:textarea
id:problem
attributes:
label:"What's the problem 🤔"
placeholder:"That feature does not work..."
validations:
required:true
- type:textarea
id:logs
attributes:
label:Share your logs (at least 10 lines)
description:Nosensitive information is logged out except when running with `LOG_LEVEL=debug`.
render:plain text
validations:
required:true
- type:textarea
id:config
attributes:
label:Share your configuration
description:Share your configuration such as `docker-compose.yml`. Ensure to remove credentials.
title: 'VPN provider support: NAME OF THE PROVIDER'
labels: ":bulb: New provider"
---
Important notes:
- There is no need to support both OpenVPN and Wireguard for a provider, but it's better to support both if possible
- We do **not** implement authentication to access servers information behind a login. This is way too time consuming unfortunately
- If it's not possible to support a provider natively, you can still use the [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
## For Wireguard
Wireguard can be natively supported ONLY if:
- the `PrivateKey` field value is the same across all servers for one user account
- the `Address` field value is:
- can be found in a structured (JSON etc.) list of servers publicly available; OR
- the same across all servers for one user account
- the `PublicKey` field value is:
- can be found in a structured (JSON etc.) list of servers publicly available; OR
- the same across all servers for one user account
- the `Endpoint` field value:
- can be found in a structured (JSON etc.) list of servers publicly available
- can be determined using a pattern, for example using country codes in hostnames
If any of these conditions are not met, Wireguard cannot be natively supported or there is no advantage compared to using a custom Wireguard configuration file.
If **all** of these conditions are met, please provide an answer for each of them.
## For OpenVPN
OpenVPN can be natively supported ONLY if one of the following can be provided, by preference in this order:
- Publicly accessible URL to a structured (JSON etc.) list of servers **and attach** an example Openvpn configuration file for both TCP and UDP; OR
- Publicly accessible URL to a zip file containing the Openvpn configuration files; OR
- Publicly accessible URL to the list of servers **and attach** an example Openvpn configuration file for both TCP and UDP
Closed issues are **NOT** monitored, so commenting here will likely NOT be seen.
If you think this is *still unresolved* and have **more information** to bring, please either
re-open this issue or create another issue.
❤️😠 temporarily help the Gluetun community and fight the AI slop scam website `gluetun[dot]com` by setting `BORINGPOLL_GLUETUNCOM=on` on the latest image.
See [the option in the wiki for more information](https://github.com/qdm12/gluetun-wiki/blob/main/setup/options/others.md)
This is an automated comment setup because @qdm12 is the sole maintainer of this project
which became too popular to monitor closed issues.
Guidance for coding agents working in this repository.
## Scope and priorities
- Keep changes minimal and targeted. Feel free to do light refactors that are relevant to the modifications.
- Breaking changes:
- Do not introduce breaking usage behavior (cli flags, environment variables, etc.) unless explicitly agreed.
- Do not introduce breaking changes for the Go API in the `pkg/` directory.
- If a compatibility break seems beneficial, stop and ask for confirmation before implementing it.
- Update or add tests when behavior changes.
## Go coding conventions
### General guidelines
- Use explicit, descriptive variable names by default.
- Notable bad examples: `req`, `resp`, `cfg`, `v`
- Allowed short-name exceptions:
- indexes such as `i`, `j`
-`ctx` for `context.Context`
-`t` for `*testing.T` and `b` for `*testing.B`
-`ctrl` for `*gomock.Controller`
-`err` for `error`, `errs` for `[]error`
-`wg` for `*sync.WaitGroup`
- Avoid using global variables except for:
- exported sentinel errors that are used outside the package boundaries
- regular expressions defined with `regexp.MustCompile`
- variables set by the build pipeline, such as `Version` and `BuildDate`
- Constants
- Prefer defining them inline in a function if it's only used in that function, rather than at the package level.
- Each one should be defined right above where it's used, instead of having multiple defined at the same place in a `const ()` block
- If one is only used in a single production code function, define it right above it so it's more local for readability.
- Do not define constants when constants exist in other packages, for example `http.StatusBadRequest` or `log.LevelDebug`.
- Structs
- Prefer defining them inline in a function if it's only used in that function, rather than at the package level.
- Do not use the short if form, prefer the longer one
- Follow modern Go, according to the Go version defined in go.mod. Prefer modern constructs when equivalent:
- Example: use `for i := range 5` rather than `for i := 0; i < 5; i++`.
- Example: use `new("string")` rather than helper wrappers such as `stringPtr("string")`.
- Example: no need to pin variables in for loops when using them in goroutines or subtests.
- Use `New(...) *Item` constructor per package. Each package should ideally only have one constructor, although this is not a strict rule. The constructor should return a pointer to the struct, and not an interface.
- Always prefer using context-aware functions, for example:
-`exec.CommandContext` rather than `exec.Command`
-`http.NewRequestWithContext` rather than `http.NewRequest`
- Never export a symbol unless absolutely necessary.
- Always use the most restrictive builtin types. For example prefer `uint` over `int` if it's only zero or positive. Prefer `uint16` is the max value is 65535.
- Prefer using builtin types whenever possible AND do not define single field structs unless necessary
- Prefer splitting a code line only when it triggers the `lll` linter, do not split a command or arguments list for each element
- Use `netip` types instead of `net` types whenever possible
- Use constants instead of variables whenever possible, especially function-local inline constants.
- Prefer using pure functions over methods when possible. Especially if the method does not need any fields from the receiving struct, it should be a pure function.
- Do not use `time.Sleep`, prefer using a `time.Timer` with a `select` statement also listening on a context cancelation
-`panic`:
- should only be used when a programming error is encountered and you should NOT return errors for programming errors (such as passing nil objects)
- Its counterpart `recover` should not really be used, except for testing a panic in test code (or use `assert.PanicsWithValue`).
### Directory structure and file naming
- Executable main packages with a single `main()` function must be in the `cmd` directory.
Prefer having top level logic and have a longer `main()` function rather than having an `internal/app` package.
- Code lives by default in subpackages within the `internal` directory
- Code needing to be imported by external Go modules must be in subpackages within the `pkg` directory
- Example code especially using the `pkg` directory must be in `main` packages within the `examples` directory, each with a single `main.go` function.
- If AND only if the repository is a Go library and not a Go application, you may have Go files at the root of the project to simplify import paths. Most of the code should still be in subpackages in the `internal` directory.
- Interfaces should be defined in `interfaces.go` files for each package. If there are unexported interfaces which need to be mocked, which is rare, they should be defined in `interfaces_local.go` files.
- Mock files are
-`mocks_generate_test.go` which only contains `//go:generate` directives for generating mocks, and no actual code
-`mocks_test.go` which contains the generated mocks from exported interfaces and no other code, and is ignored in coverage reports
-`mocks_local_test.go` (rare) which contains the generated mocks from unexported interfaces and no other code, and is ignored in coverage reports
- NEVER generate an exported mock in a non test file, prefer re-generating files across packages.
- Package naming
- Your package name should be the same as the directory containing it, **except for the `main` package**
- Use single words for package names
- Do not use generic names for package names such as `utils` or `helpers`
- Package nesting
- Try to avoid nesting packages by default
- You can nest packages if you have different implementations for the same interface (e.g. a store interface)
- You can nest packages if you start having a lot of Go files (more than 10) and it really does make sense to make subpackages
### Linting
The linter is `golangci-lint` with the configuration defined in `.golangci.yml`.
To exclude code from linting, prefer using, when absolutely necessary, command comments `//nolint:<linter>`.
This allows the `nolintlint` linter to detect and report unnecessary `//nolint` comments later.
You can notably use `//nolint:lll` and, for good valid reasons, `//nolint:gosec`. Sometimes `//nolint:mnd` when it just doesn't make sense to extract a constant such as `n = n << 4`
Always prefer placing `//nolint` comments on the same code line where the error comes from, and not above a code block.
### Mocking
Mocking works with the `go.uber.org/mock` library, and the `mockgen` tool.
- Mocks from exported interfaces are generated using go generate commands in `mocks_generate_test.go` files, and stored in `mocks_test.go` files, using:
- Mocks from unexported interfaces are generated using go generate commands in `mocks_generate_test.go` files, and stored in `mocks_local_test.go` files. The source file for unexported interfaces is `interfaces_local.go`. The go generate command is similar to:
- Mocks from external interfaces are generated using go generate commands in `mocks_generate_test.go` files, and stored in `mocks_<package-name>_test.go` files, using:
- Define mocks in the subtest, not in the parent test. You can also have a function returning the mocks as a field of the test case struct, which takes in the subtest `*testing.T` as argument, and call it in the subtest to get the mocks.
- **Never** use `gomock.Any()` as argument. Always use concrete, precise arguments. You might need to define a custom GoMock matcher for your argument in some very niche and corner cases.
- **Never** use `.AnyTimes()` on mocks. Always define the number of times a certain mock call should be called, with `.Times(3)` for example.
- **Always** set the `.Return(...)` on the mock if the function returns something.
- Avoid using **mock helpers** functions, prefer a bit of repetition than tight coupling and dependency
- Always define the gomock controller `ctrl` in the subtest and not in the parent test, or a subtest mock failing will crash all the other subtests.
### main.go
- Make the program OS signal aware, so it attempts a graceful shutdown when interruped. Force quit the program on a second interrupt signal.
### Formatting
The Go formatter used is gofumpt.
### Errors
- Always prefer wrapping errors with some context with `fmt.Errorf("doing this: %w", err)`
- Use `errors.New("error message")` when creating a 'bottom' constant string error without additional context, instead of `fmt.Errorf`
- In rare cases, you can just use `return err` notably:
- If the function is called **recursively**, since we don't wrap the wrapping multiple times for each recursion
- If the current function only statement is the call to another function, for example:
```go
func (s *Struct) Fetch() error {
return fetch() // do not wrap the error
}
```
- When wrapping errors, use verbs ending in "ing" and no "failed to" or "cannot" to avoid redundancy. For example, use `fmt.Errorf("resolving host: %w", err)` rather than `fmt.Errorf("failed to resolve host: %w", err)`.
- When wrapping an error, the context should NEVER contain variables injected as arguments in the function returning an error, to avoid repeating the same variable in multiple error messages.
- Testing errors:
- If the error does not wrap a sentinel error, use `assert.ErrorContains` to check for error messages, rather than `assert.EqualError`, to avoid having to update tests for minor changes in error messages. And use `assert.NoError` to check for no error.
- If the error wraps a sentinel error, use `assert.ErrorIs` to check both for the sentinel error or an expected nil error. You can also check the error message with `assert.ErrorContains`
### User program settings
- For configuration structs, each field Go zero value (i.e. `0` for `int`, `nil` for `*string`) should be an INVALID value in the user sense. This is used to detect when a field is not set, in order to default it, merge it or override it. For example if `""` is not a valid value, the field should be of type `string`. Conversely, if `""` is a valid value, the field should be of type `*string` to distinguish between "not set" and "set to empty string". Notably, boolean fields are ALWAYS of type `*bool` for this reason, since both `true` and `false` are valid values.
- Configuration reading and handling relies on the Go library github.com/qdm12/gosettings please use it whenever appropriate.
- Do not wrap errors coming from `reader.Reader` methods, since they already contain the necessary context.
- All keys passed to `reader.Reader` methods must be in environment variable format, i.e. uppercase with underscores. These get converted to lowercase and dashes for flags notably.
- For each settings structs, define the following methods, which are usually unexported, but can be exported especially for the top level Settings struct, in this order:
- `func (s *Settings) setDefaults()` whichs sets defaults (using `gosettings.Default*` functions) on unset fields
- If the settings need to be patched at runtime, which is rarely the case, define `func (s *Settings) overrideWith(other Settings)` which overrides the settings with another settings struct, only for fields that are set in the other struct (using `gosettings.OverrideWith` functions).
- `func (s Settings) validate() error` which validates the settings, and returns an error if anything is invalid
- `func (s *Settings) read(r *reader.Reader) error` which reads the settings from a gosettings/reader.Reader (which can be from multiple sources, such as environment variables, cli flags, config files etc.)
- `func (s Settings) String() string` which uses `toLinesNode().String()` to return a string representation of the settings
- `func (s Settings) toLinesNode() *gotree.Node` which a github.com/qdm12/gotree `*Node` representing the settings
### Testing
- Use the github.com/stretchr/testify library for assertions
- Most tests should be table tests with parallel subtests
- Prefer map-based table tests of the form `map[string]struct{ ... }`, with the key as the test name.
Use underscores in test names, not spaces, to keep `go test` output searchable.
- Use `testCases` for the table variable name, and `testCase` for each iterated case value.
- Run all tests in parallel:
- call `t.Parallel()` in the top-level test
- call `t.Parallel()` in each subtest
### Libraries to use
- Logging: `github.com/qdm12/log`
- Splash information at program start: `github.com/qdm12/gosplash`
- Long running services (i.e. health server, http prod server, backup loop etc.): `github.com/qdm12/goservices`
- String tree structures: `github.com/qdm12/gotree`
### Extra rules
- Do not use `http.DefaultClient`, use a custom `*http.Client` with a fixed timeout and share with dependency injections.
- Do not check for injected dependencies being `nil`, prefer to just panic on a nil pointer. By default it's fine to panic if a developer injects a dependency `nil`. `nil` does not mean use a default.
- Prefer using a `switch { case ...}` statement over multiple consecutive `if` statements to have shorter code.
- Prefer using `[...]T` instead of `[]T` when the length is fixed and known at compile time, to avoid unnecessary allocations.
## Validation checklist
Run the following before finishing changes:
1. Go building `go build ./...`
1. Go linting `golangci-lint run`
1. Go unit tests `go test ./...`
1. If a module is added or modified, run `go mod tidy`
1. If an interface or mock command is modified, run `go generate -run mockgen ./...`
If a Markdown file is modified and `markdownlint-cli2` is available, run `markdownlint-cli2 "**/*.md"`
If a command is unavailable in the current environment, report it clearly and provide the exact command needed once available.
org.opencontainers.image.title="VPN client for PIA, Mullvad, Windscribe, Surfshark and Cyberghost"\
org.opencontainers.image.description="VPN client to tunnel to PIA, Mullvad, Windscribe, Surfshark and Cyberghost servers using OpenVPN, IPtables, DNS over TLS and Alpine Linux"
org.opencontainers.image.title="VPN swiss-knife like client for multiple VPN providers"\
org.opencontainers.image.description="VPN swiss-knife like client to tunnel to multiple VPN servers using OpenVPN, IPtables, DNS over TLS, Shadowsocks, an HTTP proxy and Alpine Linux"
*Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access,
Mullvad, Windscribe, Surfshark Cyberghost, VyprVPN, NordVPN, PureVPN and Privado VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
1. [**Connect a container**](https://youtu.be/mH7J_2JKNK0)
1. [**Connect LAN devices**](https://youtu.be/qvjrM15Y0uk)
## Features
- Based on Alpine 3.12 for a small Docker image of 52MB
- Supports **Private Internet Access**, **Mullvad**, **Windscribe**, **Surfshark**, **Cyberghost**, **Vyprvpn**, **NordVPN**, **PureVPN** and **Privado** servers
- Supports Openvpn only for now
- DNS over TLS baked in with service provider(s) of your choice
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
- Choose the vpn network protocol, `udp` or `tcp`
- Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices
- Built in Shadowsocks proxy (protocol based on SOCKS5 with an encryption layer, tunnels TCP+UDP)
- Built in HTTP proxy (tunnels HTTP and HTTPS through TCP)
- [Connect other containers to it](https://github.com/qdm12/gluetun#connect-to-it)
- [Connect LAN devices to it](https://github.com/qdm12/gluetun#connect-to-it)
-Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7 🎆
-VPN server side port forwarding for Private Internet Access and Vyprvpn
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
- Subprograms all drop root privileges once launched
- Subprograms output streams are all merged together
- Can work as a Kubernetes sidecar container, thanks @rorph
## Setup
1. On some devices you may need to setup your tunnel kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun`
-[Synology users Wiki page](https://github.com/qdm12/gluetun/wiki/Synology-setup)
1. Launch the container with:
```bash
docker run -d --name gluetun --cap-add=NET_ADMIN \
-e VPNSP="private internet access" -e REGION="CA Montreal" \
-e USER=js89ds7 -e PASSWORD=8fd9s239G \
-v /yourpath:/gluetun \
qmcgaw/private-internet-access
```
or use [docker-compose.yml](https://github.com/qdm12/gluetun/blob/master/docker-compose.yml) with:
```bash
docker-compose up -d
```
Note that you can:
- Change the many [environment variables](#environment-variables) available
- Use `-p 8888:8888/tcp` to access the HTTP web proxy
- Use `-p 8388:8388/tcp -p 8388:8388/udp` to access the Shadowsocks proxy
- Use `-p 8000:8000/tcp` to access the [HTTP control server](#HTTP-control-server) built-in
**If you encounter an issue with the tun device not being available, see [the FAQ](https://github.com/qdm12/gluetun/blob/master/doc/faq.md#how-to-fix-openvpn-failing-to-start)**
1. You can update the image with `docker pull qmcgaw/private-internet-access:latest`. See the [wiki](https://github.com/qdm12/gluetun/wiki/Common-issues#use-a-release-tag) for more information on other tags available.
## Testing
Check the VPN IP address matches your expectations
```sh
docker run --rm --network=container:gluetun alpine:3.12 wget -qO- https://ipinfo.io
```
▶ [Testing Wiki page](https://github.com/qdm12/gluetun/wiki/Testing-the-setup)
## Environment variables
**TLDR**; only set the 🏁 marked environment variables to get started.
💡 For all server filtering options such as `REGION`, you can have multiple values separated by a comma, i.e. `Germany,Singapore`
### VPN
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| 🏁 `VPNSP` | `private internet access` | `private internet access`, `mullvad`, `windscribe`, `surfshark`, `vyprvpn`, `nordvpn`, `purevpn`, `privado` | VPN Service Provider |
| `IP_STATUS_FILE` | `/tmp/gluetun/ip` | Any filepath | Filepath to store the public IP address assigned |
| `PROTOCOL` | `udp` | `udp` or `tcp` | Network protocol to use |
| `PORT_FORWARDING` | `off` | `on`, `off` | Enable port forwarding on the VPN server |
| `PORT_FORWARDING_STATUS_FILE` | `/tmp/gluetun/forwarded_port` | Any filepath | Filepath to store the forwarded port number |
- Mullvad
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| 🏁 `USER` | | | Your user ID |
| `COUNTRY` | | One of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) | VPN server country |
| `CITY` | | One of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) | VPN server city |
| `ISP` | | One of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) | VPN server ISP |
| `PORT` | | `80`, `443` or `1401` for TCP; `53`, `1194`, `1195`, `1196`, `1197`, `1300`, `1301`, `1302`, `1303` or `1400` for UDP. Defaults to TCP `443` and UDP `1194` | Custom VPN port to use |
| `OWNED` | `no` | `yes` or `no` | If the VPN server is owned by Mullvad |
💡 [Mullvad IPv6 Wiki page](https://github.com/qdm12/gluetun/wiki/Mullvad-IPv6)
For **port forwarding**, obtain a port from [here](https://mullvad.net/en/account/#/ports) and add it to `FIREWALL_VPN_INPUT_PORTS`
- Windscribe (see [this](https://github.com/qdm12/gluetun/blob/master/internal/constants/windscribe.go#L43) for the choices of regions, cities and hostnames)
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| 🏁 `USER` | | | Your username |
| 🏁 `PASSWORD` | | | Your password |
| `REGION` | | | Comma separated list of regions to choose the VPN server |
| `CITY` | | | Comma separated list of cities to choose the VPN server |
| `HOSTNAME` | | | Comma separated list of hostnames to choose the VPN server |
| `PORT` | | One from the [this list of ports](https://windscribe.com/getconfig/openvpn) | Custom VPN port to use |
- Surfshark
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| 🏁 `USER` | | | Your **service** username, found at the bottom of the [manual setup page](https://account.surfshark.com/setup/manual) |
| 🏁 `PASSWORD` | | | Your **service** password |
| `REGION` | | One of the [Surfshark regions](https://github.com/qdm12/gluetun/wiki/Surfshark-Servers) | VPN server region |
| `DOT_PRIVATE_ADDRESS` | All private CIDRs ranges | | Comma separated list of CIDRs or single IP addresses Unbound won't resolve to. Note that the default setting prevents DNS rebinding |
| `DNS_UPDATE_PERIOD` | `24h` | i.e. `0`, `30s`, `5m`, `24h` | Period to update block lists and cryptographic files and restart Unbound. Set to `0` to deactivate updates |
| `BLOCK_MALICIOUS` | `on` | `on`, `off` | Block malicious hostnames and IPs with Unbound |
| `BLOCK_SURVEILLANCE` | `off` | `on`, `off` | Block surveillance hostnames and IPs with Unbound |
| `BLOCK_ADS` | `off` | `on`, `off` | Block ads hostnames and IPs with Unbound |
| `UNBLOCK` | |i.e. `domain1.com,x.domain2.co.uk` | Comma separated list of domain names to leave unblocked with Unbound |
| `DNS_PLAINTEXT_ADDRESS` | `1.1.1.1` | Any IP address | IP address to use as DNS resolver if `DOT` is `off` |
| `DNS_KEEP_NAMESERVER` | `off` | `on` or `off` | Keep the nameservers in /etc/resolv.conf untouched, but disabled DNS blocking features |
### Firewall and routing
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| `FIREWALL` | `on` | `on` or `off` | Turn on or off the container built-in firewall. You should use it for **debugging purposes** only. |
| `FIREWALL_VPN_INPUT_PORTS` | | i.e. `1000,8080` | Comma separated list of ports to allow from the VPN server side (useful for **vyprvpn** port forwarding) |
| `FIREWALL_INPUT_PORTS` | | i.e. `1000,8000` | Comma separated list of ports to allow through the default interface. This seems needed for Kubernetes sidecars. |
| `FIREWALL_DEBUG` | `off` | `on` or `off` | Prints every firewall related command. You should use it for **debugging purposes** only. |
| `FIREWALL_OUTBOUND_SUBNETS` | | i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28` | Comma separated subnets that Gluetun and the containers sharing its network stack are allowed to access. This involves firewall and routing modifications. |
| `HTTPPROXY_LOG` | `off` | `on` or `off` | Logs every tunnel requests |
| `HTTPPROXY_PORT` | `8888` | `1024` to `65535` | Internal port number for the HTTP proxy to listen on |
| `HTTPPROXY_USER` | | | Username to use to connect to the HTTP proxy |
| `HTTPPROXY_PASSWORD` | | | Password to use to connect to the HTTP proxy |
| `HTTPPROXY_STEALTH` | `off` | `on` or `off` | Stealth mode means HTTP proxy headers are not added to your requests |
### System
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| `TZ` | | i.e. `Europe/London` | Specify a timezone to use to have correct log times |
| `UID` | `1000` | | User ID to run as non root and for ownership of files written |
| `GID` | `1000` | | Group ID to run as non root and for ownership of files written |
### HTTP Control server
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| `HTTP_CONTROL_SERVER_PORT` | `8000` | `1` to `65535` | Listening port for the HTTP control server |
| `HTTP_CONTROL_SERVER_LOG` | `on` | `on` or `off` | Enable logging of HTTP requests |
### Other
| Variable | Default | Choices | Description |
| --- | --- | --- | --- |
| `PUBLICIP_PERIOD` | `12h` | Valid duration | Period to check for public IP address. Set to `0` to disable. |
| `VERSION_INFORMATION` | `on` | `on`, `off` | Logs a message indicating if a newer version is available once the VPN is connected |
| `UPDATER_PERIOD` | `0` | Valid duration string such as `24h` | Period to update all VPN servers information in memory and to /gluetun/servers.json. Set to `0` to disable. This does a burst of DNS over TLS requests, which may be blocked if you set `BLOCK_MALICIOUS=on` for example. |
## Connect to it
There are various ways to achieve this, depending on your use case.
- <details><summary>Connect containers in the same docker-compose.yml as Gluetun</summary><p>
Add `network_mode: "service:gluetun"` to your *docker-compose.yml* (no need for `depends_on`)
</p></details>
- <details><summary>Connect other containers to Gluetun</summary><p>
Add `--network=container:gluetun` when launching the container, provided Gluetun is already running
</p></details>
- <details><summary>Connect containers from another docker-compose.yml</summary><p>
Add `network_mode: "container:gluetun"` to your *docker-compose.yml*, provided Gluetun is already running
</p></details>
- <details><summary>Connect LAN devices through the built-in HTTP proxy (i.e. with Chrome, Kodi, etc.)</summary><p>
⚠️ You might want to use Shadowsocks instead which tunnels UDP as well as TCP and does not leak your credentials.
The HTTP proxy will not encrypt your username and password every time you send a request to the HTTP proxy server.
1. Setup an HTTP proxy client, such as [SwitchyOmega for Chrome](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=en)
1. Ensure the Gluetun container is launched with:
- port `8888` published `-p 8888:8888/tcp`
1. With your HTTP proxy client, connect to the Docker host (i.e. `192.168.1.10`) on port `8888`. You need to enter your credentials if you set them with `HTTPPROXY_USER` and `HTTPPROXY_PASSWORD`. Note that Chrome does not support authentication.
1. If you set `HTTPPROXY_LOG` to `on`, more information will be logged in the Docker logs
</p></details>
- <details><summary>Connect LAN devices through the built-in *Shadowsocks* proxy (per app, system wide, etc.)</summary><p>
1. Setup a Shadowsocks proxy client, there is a list of [ShadowSocks clients for **all platforms**](https://shadowsocks.org/en/download/clients.html)
- **note** some clients do not tunnel UDP so your DNS queries will be done locally and not through Gluetun and its built in DNS over TLS
- Clients that support such UDP tunneling are, as far as I know:
- iOS: Potatso Lite
- OSX: ShadowsocksX
- Android: Shadowsocks by Max Lv
1. Ensure the Gluetun container is launched with:
- port `8388` published `-p 8388:8388/tcp -p 8388:8388/udp`
1. With your Shadowsocks proxy client
- Enter the Docker host (i.e. `192.168.1.10`) as the server IP
- Enter port TCP (and UDP, if available) `8388` as the server port
- Use the password you have set with `SHADOWSOCKS_PASSWORD`
- Choose the encryption method/algorithm to the method you specified in `SHADOWSOCKS_METHOD`
1. If you set `SHADOWSOCKS_LOG` to `on`, (a lot) more information will be logged in the Docker logs
</p></details>
- <details><summary>Access ports of containers connected to Gluetun</summary><p>
In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to Gluetun,
publish ports `8000` and `9000` for the Gluetun container and access them as you would with any other container
</p></details>
- <details><summary>Access ports of containers connected to Gluetun, all in the same docker-compose.yml</summary><p>
In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to Gluetun, publish port `8000` and `9000` for the Gluetun container.
The docker-compose.yml file would look like:
```yml
version: '3.7'
services:
gluetun:
image: qmcgaw/private-internet-access
container_name: gluetun
cap_add:
- NET_ADMIN
environment:
- USER=js89ds7
- PASSWORD=8fd9s239G
ports:
- 8000:8000/tcp
- 9000:9000/tcp
abc:
image: abc
container_name: abc
network_mode: "service:gluetun"
xyz:
image: xyz
container_name: xyz
network_mode: "service:gluetun"
```
</p></details>
## Private Internet Access port forwarding
When `PORT_FORWARDING=on`, a port will be forwarded on the VPN server side and written to the file specified by `PORT_FORWARDING_STATUS_FILE=/tmp/gluetun/forwarded_port`.
It can be useful to mount this file as a volume to read it from other containers, for example to configure a torrenting client.
For `VPNSP=private internet access` (default), you will keep the same forwarded port for 60 days as long as you bind mount the `/gluetun` directory.
You can also use the HTTP control server (see below) to get the port forwarded.
- Contribute with code: start with [this Wiki page](https://github.com/qdm12/gluetun/wiki/Developement-setup)
- [The list of existing contributors 👍](https://github.com/qdm12/gluetun/blob/master/.github/CONTRIBUTING.md#Contributors)
- [Github workflows](https://github.com/qdm12/gluetun/actions) to know what's building
- [List of issues and feature requests](https://github.com/qdm12/gluetun/issues)
## License
This repository is under an [MIT license](https://github.com/qdm12/gluetun/master/license)
## Support
Sponsor me on [Github](https://github.com/sponsors/qdm12), donate to [paypal.me/qmcgaw](https://www.paypal.me/qmcgaw) or subscribe to a VPN provider through one of my affiliate links:
Feel also free to have a look at [the Kanban board](https://github.com/qdm12/gluetun/projects/1) and [contribute](#Development-and-contributing) to the code or the issues discussion.
Many thanks to @Frepke, @Ralph521, G. Mendez, M. Otmar Weber, J. Perez and A. Cooper for supporting me financially 🥇👍
# Gluetun VPN client
Lightweight swiss-army-knife-like VPN client to multiple VPN service providers
⚠️ This and [gluetun-wiki](https://github.com/qdm12/gluetun-wiki) are the only websites for Gluetun, other websites claiming to be official are scams ⚠️
🗯️ this repository will be migrated to [github.com/passteque/gluetun](https://github.com/passteque/gluetun) on 2026-05-21, which is a Github organization under my sole control, so don't get alarmed if you get redirected in the coming days 😉 Reason being migrating Github sponsors to the Open source collective due to my personal situation, basically annoying paperwork. On the plus side, it will be more transparent and funds donated will only be used for the project. The Docker image names will remain the same.
- Check the Wiki [common errors](https://github.com/qdm12/gluetun-wiki/tree/main/errors) and [faq](https://github.com/qdm12/gluetun-wiki/tree/main/faq)
- [Start a discussion](https://github.com/passteque/gluetun/discussions)
- [Fix the Unraid template](https://github.com/passteque/gluetun/discussions/550)
- Suggestion?
- [Create an issue](https://github.com/passteque/gluetun/issues)
- Happy?
- Sponsor me on [github.com/sponsors/qdm12](https://github.com/sponsors/qdm12)
-Donate to [paypal.me/qmcgaw](https://www.paypal.me/qmcgaw)
- Drop me [an email](mailto:quentin.mcgaw@gmail.com)
- **Want to add a VPN provider?** check [the development page](https://github.com/qdm12/gluetun-wiki/blob/main/contributing/development.md) and [add a provider page](https://github.com/qdm12/gluetun-wiki/blob/main/contributing/add-a-provider.md)
- Supports Wireguard both kernelspace and userspace
- For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Perfect privacy**, **ProtonVPN**, **Surfshark** and **Windscribe**
- For **Cyberghost**, **Private Internet Access**, **PrivateVPN**, **PureVPN**, **Torguard**, **VPN Unlimited** and **VyprVPN** using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
- For custom Wireguard configurations using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
- More in progress, see [#134](https://github.com/passteque/gluetun/issues/134)
- Supports AmneziaWG only with the custom provider for now
- DNS over TLS baked in with service provider(s) of your choice
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
- Choose the vpn network protocol, `udp` or `tcp`
- Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices
- Built in Shadowsocks proxy server (protocol based on SOCKS5 with an encryption layer, tunnels TCP+UDP)
- Built in Socks5 proxy server (tunnels TCP+UDP) - partial credits to @angelakis and @adjscent
- Built in HTTP proxy (tunnels HTTP and HTTPS through TCP)
- [Connect other containers to it](https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-container-to-gluetun.md)
- [Connect LAN devices to it](https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-lan-device-to-gluetun.md)
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7, and even ppc64le 🎆
- Custom VPN server side port forwarding for [Perfect Privacy](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/perfect-privacy.md#vpn-server-port-forwarding), [Private Internet Access](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/private-internet-access.md#vpn-server-port-forwarding), [PrivateVPN](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/privatevpn.md#vpn-server-port-forwarding) and [ProtonVPN](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/protonvpn.md#vpn-server-port-forwarding)
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
- Can work as a Kubernetes sidecar container, thanks @rorph
## Setup
🎉 There are now instructions specific to each VPN provider with examples to help you get started as quickly as possible!
Go to the [Wiki](https://github.com/qdm12/gluetun-wiki)!
[🐛 Found a bug in the Wiki?!](https://github.com/qdm12/gluetun-wiki/issues/new/choose)
Here's a docker-compose.yml for the laziest:
```yml
---
services:
gluetun:
image:qmcgaw/gluetun
# container_name: gluetun
# line above must be uncommented to allow external containers to connect.
# See https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-container-to-gluetun.md#external-container-to-gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp# HTTP proxy
- 8388:8388/tcp# Shadowsocks
- 8388:8388/udp# Shadowsocks
volumes:
- /yourpath:/gluetun
environment:
# See https://github.com/qdm12/gluetun-wiki/tree/main/setup#setup
# See https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list
- UPDATER_PERIOD=
```
🆕 Image also available as `ghcr.io/qdm12/gluetun`
## Fun graphs
[](https://www.star-history.com/#passteque/gluetun&type=date&legend=top-left)
// Cmder handles running subprograms synchronously and asynchronously.
typeCmderstruct{}
funcNew()*Cmder{
return&Cmder{}
}
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.