Open-source project
trailofbits/algo avatar
trailofbits/algo

Algo VPN ships an anti-features list that rules out anonymity and L2TP by name

Set up a personal VPN in the cloud

30,470 stars2,375 forksPythonAGPL-3.0

At a glance

What is it?
Algo is a set of Ansible scripts from Trail of Bits that build a personal WireGuard or IPsec VPN on a cloud machine, and it is explicit about what it refuses to be: no legacy protocols, no Tor, no anonymity or censorship claims. It suits someone who wants a small server they control and can read end to end, and it puts two irreversible answers in front of you during the run.
Who is it for?
Use Algo if you want a VPN you can read, rebuild and destroy, on a provider you already have an account with, and answer the key retention prompt with yes unless you are certain you will never add a user. Do not use it if you are looking for anonymity or censorship resistance, because the project rules both out in its own words, and read the configuration warnings before the run rather than after, because two of the answers you give there are expensive to change.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day 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 November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • trailofbits/algo30,470 ★ · +94
Star history
Repository2026-09-132026-11-14
trailofbits/algo30.4k30.5k

94 Stars in the last 62 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The anti-features list is the clearest page in the repository

Most projects have a list of what they do. This one has a list of what it will not do, and it is more informative than the feature list above it. It does not support legacy cipher suites or protocols such as L2TP, IKEv1 or RSA. It does not install Tor, OpenVPN or other servers it considers risky. It does not depend on the security of TLS. And then two lines that matter more than the rest: it does not claim to provide anonymity or censorship avoidance, and it does not claim to protect you from four named intelligence services, the last of which is a joke about a flying pasta monster. The consequence for a reader is unusual and useful. If you are looking for a tool to reach a blocked site, this file tells you that is not what it is for, before you spend an afternoon deploying one. If you want a small VPN you own and can read, that is exactly what it claims to be.

Two answers during the run are expensive to take back

The deployment steps contain two warnings that are easy to skim. The first is in the configuration step: you edit a configuration file, list the users you want, and create a unique user for each device, and the file then says that changing your mind about the other options later may require you to deploy a brand new server. The second appears later, in the client section, and is sharper. If you use IPsec and want to add or delete users after deployment, you must have answered yes at a prompt asking whether you want to retain the keys, because that answer preserves the certificate authority that user management depends on. Answer no and the authority is not kept, so adding a user later means starting again.

It is a set of scripts, not a package you can import

The Python manifest describes a project that explicitly is not a library. Package discovery is turned off on purpose, with a comment saying that Algo is not a Python package and an empty module list to match. The manifest still exists, and it is useful: it names the project, records a version, and sets the minimum interpreter to 3.11. What it does not do is give you anything to import. The interface is a set of entry points at the root of the repository instead: a script for Unix-like systems, a PowerShell script for Windows, a wrapper for running inside a container, and a third that shows the environment. Playbooks sit alongside them for the server, the clients, the cloud host, the users and a teardown. So if your plan was to call Algo from your own provisioning code, the answer in the manifest is that there is no such surface, and the only supported path is running the script.

Ansible is pinned to one version, and each cloud provider brings its own extra

The dependency list is short and mostly floors, with two exact pins. The automation tool is pinned to a single release with an equality constraint, and one address parsing library is pinned the same way, while the cryptography, template and YAML libraries are pinned only at a minimum. QR code generation comes from a small library, which matches the feature that says the tool generates a QR code per user. Then there are seven optional dependency groups, one for each of several hosting providers, and a comment above them says they are installed automatically based on the provider you select. So choosing Hetzner installs one client library and choosing Microsoft Azure installs five, which is a fair picture of how much each provider's API surface differs. The consequence of the exact Ansible pin is that a provider needing a newer automation release is not an option until the project moves the pin, and that pin is the first thing to check before you pick a host.

The container installs from a lockfile with a tool fetched from a latest tag

The image build is worth reading closely, because it mixes two approaches. The base is an Alpine-based Python 3.12 image, and a comment records that the Rust toolchain was removed because it was not needed once a different installer was adopted. The Python side is properly locked: the manifest and the lock file are copied and the install is run with the lock enforced and development dependencies excluded, then the collections for the cloud modules are installed from a requirements file through the same tool:

bash
uv sync --locked --no-dev
uv run ansible-galaxy collection install -r requirements.yml

The installer itself, though, is copied from another project's image using that image's latest tag, with a comment saying this is deliberate so it updates automatically. So the versions of your Python dependencies are pinned and the version of the thing doing the pinning is not, which means two builds of the same commit can behave differently. The build also writes a small file recording the platform it was built on and the platform it targets, which is the kind of detail that saves an argument later.

The image creates an unprivileged user and then explains why it runs as root

The container definition contains one of the more honest comments in the project. It creates a user with a fixed numeric identifier and no home directory, and it creates the working and configuration directories up front. Then a comment says the working directory must stay owned by root for the run to work with all capabilities dropped, and explains why: root without the override capability cannot write into files owned by someone else. A later comment says the container runs as root for bind mount compatibility, and that the wrapper script handles the data volume permissions and needs root for that. The data directory is given to the unprivileged user in the meantime, which is the arrangement that lets you drop capabilities when you are not bind mounting. So the two facts sit together: by default the process is root inside the container, and the ability to run it with every capability removed is a property of the mount layout rather than of the base image.

A teardown playbook sits in the repository, and four linters guard the YAML

The repository root is mostly playbooks, and one of them is a teardown. Alongside the main entry playbook there are separate plays for the server, for clients, for the cloud host, for users, and one whose name is the opposite of the others, which is the point: destroying a server is treated as a first-class operation rather than something you improvise with a console. Around them sit a role directory, a playbook directory, a module library, an inventory file, an Ansible configuration file and a requirements file for collections. The quality tooling is spread across four systems rather than one: an Ansible linter configuration, a YAML linter configuration, a pre-commit configuration, and a pytest configuration with a tests directory. That is the shape of a project whose output is mostly YAML that talks to remote machines, and the cost is that a change has to satisfy four different opinions about it before it lands.

Six years between version 1.1 and 2.0, and the manifest still says beta

The release history explains the current state and also the project's age. Version 1.1 was published in 2019, version 2.0.0 in August 2025, and version 2.0.1 the following November, with the last push to the main branch recorded on 2026-10-01. The release names are not even consistent with each other, alternating between two spellings of the project's name with and without a space. The more useful detail is in the manifest, where the version string is a beta of 2.0.0 while 2.0.1 is already published. So a tool that reads the version out of the repository gets a prerelease string for a line that has had two stable releases. The six year gap matters for anyone following older instructions: the deployment process, the supported clients and the configuration file have all had time to change since version 1.1, and the file's own description of it is a blog post from 2016.

Editorial conclusion

Use Algo if you want a VPN you can read, rebuild and destroy, on a provider you already have an account with, and answer the key retention prompt with yes unless you are certain you will never add a user. Do not use it if you are looking for anonymity or censorship resistance, because the project rules both out in its own words, and read the configuration warnings before the run rather than after, because two of the answers you give there are expensive to change.

Frequently asked questions

How do I deploy Algo VPN?

Four steps: open an account with a supported cloud provider, get a copy of the scripts by downloading a ZIP or cloning the repository, edit the configuration file to list one user per device you plan to connect, and run the script for your platform, which is a different command on macOS and Linux than on Windows. The first run installs the required Python environment, which needs version 3.11 or newer, and later runs start immediately.

Which cloud providers does Algo VPN support?

The file names DigitalOcean, which it calls the most user friendly, plus Amazon Lightsail, Amazon EC2, Vultr, Microsoft Azure, Google Compute Engine, Scaleway, DreamCompute, Linode, other OpenStack-based hosting, CloudStack-based hosting and Hetzner Cloud, and it also supports installing to your own Ubuntu server for advanced users. Several providers have an optional dependency group in pyproject.toml, installed based on the provider you select.

Does Algo VPN support L2TP or OpenVPN?

No, and the file says so under its anti-features. It rules out legacy cipher suites and protocols including L2TP, IKEv1 and RSA, and it does not install Tor or OpenVPN. What it supports is IKEv2 with strong cryptography, and WireGuard, with generated configuration files and QR codes for the client platforms.

Official sources

  1. License: AGPL-3.0
  2. Project website
  3. README
  4. Releases
  5. trailofbits/algo on GitHub
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/trailofbits-algo.svg)](https://hysenlabs.com/projects/trailofbits-algo)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/trailofbits-algo.svg)](https://hysenlabs.com/projects/trailofbits-algo)

Was this useful?