Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.github/
.gitignore

# Development environment
# Development environment
.env
.venv/
.ruff_cache/
Expand Down
78 changes: 78 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# See https://pre-commit.com for more information
---
# Apply to all files without committing:
# pre-commit run --all-files
# Update this file:
# pre-commit autoupdate

repos:
# General file checks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-yaml
args: [--allow-multiple-documents]
exclude: '(files/cloud-init/base\.yml|roles/cloud-.*/files/stack\.yaml)'
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-added-large-files
args: ['--maxkb=500']
- id: check-merge-conflict
- id: mixed-line-ending
args: [--fix=lf]

# Python linting with ruff (fast, replaces many tools)
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format

# YAML linting
- repo: https://github.com/adrienverge/yamllint
rev: v1.35.1
hooks:
- id: yamllint
args: [-c=.yamllint]
exclude: '.git/.*'

# Shell script linting
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
exclude: '.git/.*'

# Local hooks that use the project's installed tools
- repo: local
hooks:
- id: ansible-lint
name: Ansible-lint
entry: bash -c 'uv run ansible-lint --force-color || echo "Ansible-lint had issues - check output"'
language: system
types: [yaml]
files: \.(yml|yaml)$
exclude: '^(.git/|.github/|requirements\.yml)'
pass_filenames: false

- id: ansible-syntax
name: Ansible syntax check
entry: bash -c 'uv run ansible-playbook main.yml --syntax-check'
language: system
files: 'main\.yml|server\.yml|users\.yml'
pass_filenames: false

# Configuration for the pre-commit tool itself
default_language_version:
python: python3.11

# Files to exclude globally
exclude: |
(?x)^(
.env/.*|
.venv/.*|
.git/.*|
__pycache__/.*|
.*\.egg-info/.*
)$
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ def test_regression_openssl_inline_comments():
# This pattern SHOULD fail (has inline comments)
problematic = "{{ ['DNS:' + id, # comment ] }}"
assert not validate(problematic), "Should detect inline comments"
# This pattern SHOULD pass (no inline comments)

# This pattern SHOULD pass (no inline comments)
fixed = "{{ ['DNS:' + id] }}"
assert validate(fixed), "Should pass without comments"
```
Expand Down Expand Up @@ -492,4 +492,4 @@ When working on Algo:
4. **Be Conservative**: This is critical infrastructure
5. **Respect Privacy**: No tracking, minimal logging

Remember: People trust Algo with their privacy and security. Every line of code matters.
Remember: People trust Algo with their privacy and security. Every line of code matters.
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

* Clone the repository: `git clone https://github.com/trailofbits/algo.git`
* Run Algo: `./algo` (dependencies installed automatically via uv)
* Install pre-commit hooks: `uv run pre-commit install` (optional, for contributors)
* For local testing, consider using Docker or a cloud provider test instance

Thanks!
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -658,4 +658,4 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ The easiest way to get an Algo server running is to run it on your local system
3. **Set your configuration options.** Open `config.cfg` in your favorite text editor. Specify the users you want to create in the `users` list. Create a unique user for each device you plan to connect to your VPN. You should also review the other options before deployment, as changing your mind about them later [may require you to deploy a brand new server](https://github.com/trailofbits/algo/blob/master/docs/faq.md#i-deployed-an-algo-server-can-you-update-it-with-new-features).

4. **Start the deployment.** Return to your terminal. In the Algo directory, run the appropriate script for your platform:

**macOS/Linux:**
```bash
./algo
```

**Windows:**
```powershell
.\algo.ps1
```

The first time you run the script, it will automatically install the required Python environment (Python 3.11+). On subsequent runs, it starts immediately and works on all platforms (macOS, Linux, Windows via WSL). The Windows PowerShell script automatically uses WSL when needed, since Ansible requires a Unix-like environment. There are several optional features available, none of which are required for a fully functional VPN server. These optional features are described in the [deployment documentation](docs/deploy-from-ansible.md).

That's it! You can now set up clients to connect to your VPN. Proceed to [Configure the VPN Clients](#configure-the-vpn-clients) below.
Expand Down Expand Up @@ -264,6 +264,14 @@ If you've read all the documentation and have further questions, [create a new d

-- [Thorin Klosowski](https://twitter.com/kingthor) for [Lifehacker](http://lifehacker.com/how-to-set-up-your-own-completely-free-vpn-in-the-cloud-1794302432)

## Contributing

See our [Development Guide](docs/DEVELOPMENT.md) for information on:
* Setting up your development environment
* Using pre-commit hooks for code quality
* Running tests and linters
* Contributing code via pull requests

## Support Algo VPN
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CYZZD39GXUJ3E)
[![Patreon](https://img.shields.io/badge/back_on-patreon-red.svg)](https://www.patreon.com/algovpn)
Expand Down
24 changes: 12 additions & 12 deletions algo
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ UV_INSTALL_METHOD=""
# Function to install uv via package managers (most secure)
install_uv_via_package_manager() {
echo "Attempting to install uv via system package manager..."

if command -v brew &> /dev/null; then
echo "Using Homebrew..."
brew install uv && UV_INSTALL_METHOD="Homebrew" && return 0
Expand All @@ -31,7 +31,7 @@ install_uv_via_package_manager() {
echo "Using scoop..."
scoop install uv && UV_INSTALL_METHOD="scoop" && return 0
fi

return 1
}

Expand All @@ -41,7 +41,7 @@ install_uv_ubuntu_alternatives() {
if ! command -v lsb_release &> /dev/null || [[ "$(lsb_release -si)" != "Ubuntu" ]]; then
return 1 # Not Ubuntu, skip these options
fi

echo ""
echo "Ubuntu detected. Additional trusted installation options available:"
echo ""
Expand All @@ -54,7 +54,7 @@ install_uv_ubuntu_alternatives() {
echo ""
echo "3. Continue to official installer script download"
echo ""

while true; do
read -r -p "Choose installation method (1/2/3): " choice
case $choice in
Expand Down Expand Up @@ -104,14 +104,14 @@ install_uv_via_download() {
echo " 3. Verify checksums and install manually"
echo " 4. Then run: ./algo"
echo ""

read -p "Continue with script download? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Installation cancelled. Please install uv manually and retry."
exit 1
fi

echo "Downloading uv installation script..."
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "linux-gnu" && -n "${WSL_DISTRO_NAME:-}" ]] || uname -s | grep -q "MINGW\|MSYS"; then
# Windows (Git Bash/WSL/MINGW) - use versioned installer
Expand All @@ -127,7 +127,7 @@ install_uv_via_download() {
# Check if uv is installed, if not, install it securely
if ! command -v uv &> /dev/null; then
echo "uv (Python package manager) not found. Installing..."

# Try package managers first (most secure)
if ! install_uv_via_package_manager; then
# Try Ubuntu-specific alternatives if available
Expand All @@ -136,26 +136,26 @@ if ! command -v uv &> /dev/null; then
install_uv_via_download
fi
fi

# Reload PATH to find uv (includes pipx, cargo, and snap paths)
# Note: This PATH change only affects the current shell session.
# Users may need to restart their terminal for subsequent runs.
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:/snap/bin:$PATH"

# Verify installation worked
if ! command -v uv &> /dev/null; then
echo "Error: uv installation failed. Please restart your terminal and try again."
echo "Or install manually from: https://docs.astral.sh/uv/getting-started/installation/"
exit 1
fi

echo "✓ uv installed successfully via ${UV_INSTALL_METHOD}!"
fi

# Run the appropriate playbook
case "$1" in
update-users)
update-users)
uv run ansible-playbook users.yml "${@:2}" -t update-users ;;
*)
*)
uv run ansible-playbook main.yml "${@}" ;;
esac
24 changes: 12 additions & 12 deletions algo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ function Test-RunningInWSL {
# Function to run Algo in WSL
function Invoke-AlgoInWSL {
param($Arguments)

Write-Host "NOTICE: Ansible requires a Unix-like environment and cannot run natively on Windows."
Write-Host "Attempting to run Algo via Windows Subsystem for Linux (WSL)..."
Write-Host ""

if (-not (Get-Command wsl -ErrorAction SilentlyContinue)) {
Write-Host "ERROR: WSL (Windows Subsystem for Linux) is not installed." -ForegroundColor Red
Write-Host ""
Expand All @@ -38,7 +38,7 @@ function Invoke-AlgoInWSL {
Write-Host "https://github.com/trailofbits/algo/blob/master/docs/deploy-from-windows.md"
exit 1
}

# Check if any WSL distributions are installed and running
Write-Host "Checking for WSL Linux distributions..."
$wslList = wsl -l -v 2>$null
Expand All @@ -52,13 +52,13 @@ function Invoke-AlgoInWSL {
Write-Host "Then restart your computer and try again."
exit 1
}

Write-Host "Successfully found WSL. Launching Algo..." -ForegroundColor Green
Write-Host ""

# Get current directory name for WSL path mapping
$currentDir = Split-Path -Leaf (Get-Location)

try {
if ($Arguments.Count -gt 0 -and $Arguments[0] -eq "update-users") {
$remainingArgs = $Arguments[1..($Arguments.Count-1)] -join " "
Expand All @@ -67,7 +67,7 @@ function Invoke-AlgoInWSL {
$allArgs = $Arguments -join " "
wsl bash -c "cd /mnt/c/$currentDir 2>/dev/null || (echo 'Error: Cannot access directory in WSL. Make sure you are running from a Windows drive (C:, D:, etc.)' && exit 1) && ./algo $allArgs"
}

if ($LASTEXITCODE -ne 0) {
Write-Host ""
Write-Host "Algo finished with exit code: $LASTEXITCODE" -ForegroundColor Yellow
Expand All @@ -93,7 +93,7 @@ try {
# Check if we're actually running inside WSL
if (Test-RunningInWSL) {
Write-Host "Detected WSL environment. Running Algo using standard Unix approach..."

# Verify bash is available (should be in WSL)
if (-not (Get-Command bash -ErrorAction SilentlyContinue)) {
Write-Host "ERROR: Running in WSL but bash is not available." -ForegroundColor Red
Expand All @@ -102,15 +102,15 @@ try {
Write-Host " wsl" -ForegroundColor Cyan
exit 1
}

# Run the standard Unix algo script
& bash -c "./algo $($Arguments -join ' ')"
exit $LASTEXITCODE
}

# We're on native Windows - need to use WSL
Invoke-AlgoInWSL $Arguments

} catch {
Write-Host ""
Write-Host "UNEXPECTED ERROR:" -ForegroundColor Red
Expand All @@ -121,4 +121,4 @@ try {
Write-Host "2. See troubleshooting guide: https://github.com/trailofbits/algo/blob/master/docs/deploy-from-windows.md"
Write-Host "3. Or use WSL directly: open Ubuntu and run './algo'"
exit 1
}
}
2 changes: 1 addition & 1 deletion docs/aws-credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ If Algo isn't finding your credentials:

If credentials are found but authentication fails:
- Ensure your IAM user has the required permissions (see [EC2 deployment guide](deploy-from-ansible.md))
- Check if you need session tokens for temporary credentials
- Check if you need session tokens for temporary credentials
2 changes: 1 addition & 1 deletion docs/client-apple-ipsec.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ On iOS, connect to the VPN by opening **Settings** and clicking the toggle next

If you enable "Connect On Demand", the VPN will connect automatically whenever it is able. Most Apple users will want to enable "Connect On Demand", but if you do then simply disabling the VPN will not cause it to stay disabled; it will just "Connect On Demand" again. To disable the VPN you'll need to disable "Connect On Demand".

On iOS, you can turn off "Connect On Demand" in **Settings** by clicking the (i) next to the entry for your Algo VPN and toggling off "Connect On Demand." On macOS, you can turn off "Connect On Demand" by opening **System Settings** -> **Network** (or **VPN** on macOS Sequoia 15.0+), finding the Algo VPN in the left column, unchecking the box for "Connect on demand", and clicking Apply.
On iOS, you can turn off "Connect On Demand" in **Settings** by clicking the (i) next to the entry for your Algo VPN and toggling off "Connect On Demand." On macOS, you can turn off "Connect On Demand" by opening **System Settings** -> **Network** (or **VPN** on macOS Sequoia 15.0+), finding the Algo VPN in the left column, unchecking the box for "Connect on demand", and clicking Apply.
4 changes: 2 additions & 2 deletions docs/client-openwrt-router-wireguard.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ This configuration has been verified on TP-Link TL-WR1043ND and TP-Link Archer C
4. Click "Update lists" to refresh the package database
5. Search for and install these packages:
- `wireguard-tools`
- `kmod-wireguard`
- `kmod-wireguard`
- `luci-app-wireguard`
- `wireguard`
- `kmod-crypto-sha256`
Expand Down Expand Up @@ -187,4 +187,4 @@ For optimal privacy, configure your router to use your Algo server's DNS by navi

Store your private keys securely and never share them. Keep OpenWrt and packages updated for security patches. Regularly check VPN connectivity to ensure ongoing protection, and save your configuration before making changes.

This configuration routes ALL traffic from your router through the VPN. If you need selective routing or have specific requirements, consider consulting the [OpenWrt WireGuard documentation](https://openwrt.org/docs/guide-user/services/vpn/wireguard/start) for advanced configurations.
This configuration routes ALL traffic from your router through the VPN. If you need selective routing or have specific requirements, consider consulting the [OpenWrt WireGuard documentation](https://openwrt.org/docs/guide-user/services/vpn/wireguard/start) for advanced configurations.
2 changes: 1 addition & 1 deletion docs/client-windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ You can import multiple `.conf` files for different Algo servers. Give each a de

- Check the main [troubleshooting guide](troubleshooting.md)
- Review [WireGuard documentation](https://www.wireguard.com/quickstart/)
- [Create a discussion](https://github.com/trailofbits/algo/discussions) for help
- [Create a discussion](https://github.com/trailofbits/algo/discussions) for help
4 changes: 2 additions & 2 deletions docs/cloud-amazon-ec2.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ For additional EC2 configuration options, see the [deploy from ansible guide](ht
1. Navigate to Services → IAM → Users
2. Enable multi-factor authentication (MFA) on your root account using Google Authenticator or a hardware token
3. Click "Add User" and create a username (e.g., `algovpn`)
4. Select "Programmatic access"
4. Select "Programmatic access"
5. Click "Next: Permissions"

![The new user screen in the AWS console.](/docs/images/aws-ec2-new-user.png)
Expand Down Expand Up @@ -173,4 +173,4 @@ The cleanest way to remove an Algo deployment is through CloudFormation:

Warning: Deleting a CloudFormation stack will permanently delete your EC2 instance and all associated resources unless you've enabled termination protection. Make sure you're deleting the correct stack and have backed up any important data.

This approach ensures all related AWS resources are properly cleaned up, preventing resource conflicts in future deployments.
This approach ensures all related AWS resources are properly cleaned up, preventing resource conflicts in future deployments.
Loading
Loading