Library / SDK
ProtonVPN/proton-vpn-gtk-app avatar
ProtonVPN/proton-vpn-gtk-app

proton-vpn-gtk-app and the reality of building Proton's Linux client

Official ProtonVPN Linux app

789 stars116 forksPythonGPL-3.0

At a glance

What is it?
proton-vpn-gtk-app is the official Proton VPN desktop client for Linux, written in Python with GTK. It covers the authenticated user experience end to end, but a developer building it from source needs Proton's internal package registry, and the release process is driven from versions.yml.
Who is it for?
Use this repository if you are a Python developer working on Proton's Linux desktop client or a user who wants the packaged app rather than a source build. It is the wrong starting point for a headless server, for scripted or containerised VPN use, or for anything that needs its own account signup flow, since the README says signup happens on the website.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The GTK app stops where the website starts

The repository holds one thing: the Proton VPN GTK app, the official Linux desktop client, copyright held by Proton AG and licensed under GPL-3.0. The scope is stated plainly in the description: the app is intended for every Proton VPN service user and gives authenticated users full access to the available functionality, while the user signup process is handled on the website.

That division of labour shapes everything else in the project. There is no account creation code to review or extend, and no plan selection or payment flow. What you are looking at is the desktop experience for people who already have an account: sign in, pick a server, connect, and manage the connection from a graphical window. The code lives under `proton/app/gtk`, which the README identifies as the GTK app source folder.

The language choice is Python, with `pygobject` and `pycairo` among the runtime dependencies in setup.py. That is the standard GTK binding stack for Python, and it means the app is a Python application wearing a GTK interface rather than a native toolkit program.

The audience is therefore fairly specific: desktop Linux users who want a GUI, and developers who maintain or extend that GUI. It is not a generic VPN toolkit. Nothing in the repository suggests it is meant to be embedded as a library in other projects, and the packaging setup is aimed at distribution packages rather than a pip install for end users.

A source build needs Proton's internal package registry

This is the part that decides whether a source build is practical for you. The README states that the required packages are listed in setup.py under `install_requires` and `extra_require`, and that as of now these packages will not be available on pypi. That means `pip install proton-vpn-gtk-app` from the public index is not the path.

To install Proton's own components you need to configure pip to use their internal registry, using a personal access token with the `api` scope:

bash
pip config set global.index-url https://__token__:{GITLAB_TOKEN}@{GITLAB_INSTANCE}/api/v4/groups/{GROUP_ID}/-/packages/pypi/simple

Note that this writes to your global pip configuration, not to a project local file. Anyone who builds on a shared machine is changing the default index for all their Python work, which is worth keeping in mind before running it on a workstation.

The runtime dependency list in setup.py reads like a service client: `proton-vpn-api-core`, `proton-core`, `pygobject`, `pycairo`, `dbus-python`, `packaging`, `distro` and `requests`. The first two are Proton's own libraries, and `dbus-python` suggests the app talks to a session or daemon over D-Bus, which is typical for a Linux VPN client that needs to keep a tunnel alive outside the lifetime of a GUI window.

Cloning the submodules and creating the virtual environment

The repository carries a `.gitmodules` file, and the README tells you to pull in the nested repositories after cloning:

bash
git submodule update --init --recursive

The `--recursive` flag matters here because Proton's dependencies are themselves split across repositories. Skipping it leaves you with a tree that cannot import.

With the submodules in place, the environment setup is the standard Python pair of a virtual environment and a requirements install:

bash
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

The requirements file is a single editable reference to the project itself with its development extras:

bash
-e ".[development]"

Those development extras, listed in setup.py, include `proton-keyring-linux`, `behave` and `pyotp`. The keyring package points at Linux secret storage for credentials, `pyotp` is the one time password library needed for two factor login, and `behave` is the behaviour driven test runner used by the integration suite.

One detail worth flagging: the README notes that these packages will not be available on pypi. If you plan to contribute, you need access to the internal registry before anything else, and the token handling is a manual step that happens once per machine rather than something the build scripts arrange for you.

Logs and settings live under the Proton cache and config directories

Two paths are documented for the running application, and they tell you where to look when something misbehaves.

Application logs are written to `~/.cache/Proton/VPN/logs/`. This is a cache directory by convention, so it is fair to assume a cleanup tool could remove it, and worth knowing before you treat old logs as permanent records.

User settings are kept in `~/.config/Proton/VPN/`. That is the XDG style configuration location, so the app follows the convention rather than inventing a path of its own.

For a desktop client, this split matters more than it might for a library. When a user reports that the app will not connect, the first two places to look are the settings directory, where a stored server preference or a stale account state can be the cause, and the log directory, where the D-Bus handshake and API calls are recorded. Both are per user, so a headless or multi user deployment has to account for that.

The README does not document how to reset the app to a clean state, so removing `~/.config/Proton/VPN/` by hand is the obvious reset procedure and is also the natural thing to script for a support workflow.

Debian and rpm packaging live in the repository

Two packaging folders sit at the top level. The `debian` folder contains all Debian related data, for easy package compilation, and `rpmbuild` holds the equivalent for rpm and Fedora. The presence of both in one repository means the same source tree targets both major Linux packaging worlds, and any change to install paths, service files or dependencies has to be reflected in two places.

The translation story is handled in setup.py. A custom `build_py` subclass runs `msgfmt` over the `.po` files found in `proton/vpn/app/gtk/locale` and writes compiled `.mo` files into the build tree under a `binaries` directory, one per locale, named after the application domain `proton-vpn-gtk-app`. The build fails loudly if no `.po` file is found, which is a sensible guard against shipping a package with no translations.

Version numbers are not hard coded in setup.py. Instead the version is read out of `versions.yml` with a regular expression over the first line of that file, and the same file is the single source of truth for the packaging metadata.

The behave integration suite runs headless under Xvfb

The `tests` folder holds the unit and integration test code, and the integration tests are driven by behave. On a normal desktop session you run them directly against the feature files:

bash
behave tests/integration/features

On a headless system, such as a CI runner without an X server, the README points to `Xvfb`, the virtual framebuffer X server. On Debian based distributions the package to install is `xvfb`, and the runner command becomes:

bash
xvfb-run -a behave integration_tests/features

Two things are worth noticing. The `-a` flag lets `xvfb-run` pick a free display number automatically, which matters when integration tests run in parallel. And the path in this command differs from the one in the previous example, `integration_tests/features` rather than `tests/integration/features`. The README carries both spellings, so check which one exists in the tree you have before assuming a failing command means a broken environment.

A GUI client with an integration suite driven by behave is a reasonable structure, since the suite can express user facing scenarios rather than only unit level calls. The cost is that the suite needs a display, which is exactly why the Xvfb path exists.

versions.yml drives both releases and develop builds

Versioning is handled by one file and a pair of scripts, and the rules are specific enough to be worth knowing before you open a merge request. The README says plainly: do not edit versions.yml in merge requests.

Develop builds are stamped by CI as `<next release>rc<UTC timestamp>`, for example `4.18.8rc202610060949`, produced by `scripts/devtools/dev_version.py`. These values are never committed. Release versions are written by the release merge request using `scripts/devtools/release_version.py`, which reads the commit subjects since the previous release and maps conventional commit types to version bumps: `feat!` produces a major, `feat` a minor, and `fix`, `chore`, `i18n` and other conventional types a patch.

A third script, `scripts/create_changelogs.py`, generates `debian/changelog`, the rpm spec file and `CHANGELOG.md` from the same versions.yml data. So the changelog and the package metadata cannot drift apart, because they come from one source.

That design has a cost worth stating: the version bump is derived from commit messages, so a commit written carelessly produces the wrong release number. The convention is not a suggestion, it is the input to the release tooling.

Where this client is the wrong tool

There are clear cases where this repository does not fit. A headless Linux box, a container, or a server with no desktop session has no GTK interface to run, and the integration test guidance in this repository confirms the app is a windowed program that assumes a display. If you need a VPN connection in a script, in a systemd unit, or inside a container image, this is not the component to build on.

The dependency wall is the second boundary. Because the Proton packages are not on pypi and the registry requires a GitLab personal access token, an outside contributor or a company that has not been granted registry access cannot complete a source build. For those people the supported route is the packaged release, which the README says is available from the Proton VPN official website download page for Linux.

The absence of GitHub releases in the repository is worth noting too. There is no release history to browse on the project page, no tag listing to check a specific version against, and no changelog in the usual GitHub format. The `CHANGELOG.md` file is generated during packaging, so it may not reflect every commit.

Finally, the GPL-3.0 licence matters for anyone planning to reuse the code rather than run it. The repository points to `COPYING.md` and `LICENSE` for licensing information and `CONTRIBUTING.md` for the contribution policy. Modifying and redistributing the app carries obligations under that licence, and embedding its pieces in a proprietary product would be a different question from running the app as shipped. Take your own advice on that point, not a summary from this article.

Editorial conclusion

Use this repository if you are a Python developer working on Proton's Linux desktop client or a user who wants the packaged app rather than a source build. It is the wrong starting point for a headless server, for scripted or containerised VPN use, or for anything that needs its own account signup flow, since the README says signup happens on the website. Before you commit to a source build, confirm you can reach Proton's internal GitLab package registry with a personal access token, and check whether the deb or rpm packaging folders match the distribution you target.

Frequently asked questions

How do I install the Proton VPN GTK app on Linux?

The README points to the Proton VPN official website download page for Linux for the latest stable release. A source build additionally requires Proton's internal package registry, since the required packages are not available on pypi.

Where does the proton-vpn-gtk-app store its logs and settings?

App logs are stored under the `~/.cache/Proton/VPN/logs/` directory and user settings under `~/.config/Proton/VPN/`.

Can I run the proton-vpn-gtk-app integration tests without a display?

Yes. The README says the behave integration tests can run on headless systems using Xvfb, for example `xvfb-run -a behave integration_tests/features`, with the `xvfb` package installed on Debian based distributions.

How is the version number decided in proton-vpn-gtk-app?

Release versions come from `scripts/devtools/release_version.py`, which maps commit subjects since the previous release to major, minor or patch bumps, and `scripts/create_changelogs.py` generates the Debian changelog, the rpm spec and CHANGELOG.md from versions.yml. Merge requests should not edit versions.yml.

Does proton-vpn-gtk-app handle account signup?

No. The README states that the app provides full access to functionality for authenticated users and that the user signup process is handled on the website.

When was the proton-vpn-gtk-app repository last updated?

The repository is not archived and the last push was on 2026-10-19. The repository has no GitHub releases, so the commit history and the generated CHANGELOG.md are the places to look for version detail.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. Project website
  4. ProtonVPN/proton-vpn-gtk-app on GitHub
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/protonvpn-proton-vpn-gtk-app.svg)](https://hysenlabs.com/projects/protonvpn-proton-vpn-gtk-app)

Was this useful?