Ultradesu 3a4bc23a58
Build and Publish / Build and Publish Docker Image (push) Successful in 3m8s
Added telegram bot
2026-06-30 18:36:53 +03:00
2026-06-29 15:50:25 +03:00
2026-06-30 18:36:53 +03:00
2026-06-30 18:36:53 +03:00
2026-06-29 15:50:25 +03:00
2026-06-29 15:50:25 +03:00
2026-06-29 15:50:25 +03:00
2026-06-30 18:36:53 +03:00
2026-06-30 18:36:53 +03:00
2026-06-29 16:50:03 +03:00
2026-06-30 18:36:53 +03:00

amnezia-fellow

Amnezia VPN client manager written in Rust on top of the public cot framework.

The app uses SQLite as the source of truth, authenticates users through OIDC/SSO, renders AmneziaWG client peers into a Kubernetes Secret, and avoids updating that Secret when the rendered content is byte-for-byte identical.

Quick Start

export AMNEZIA_FELLOW_DATABASE_URL=sqlite://amnezia-fellow.sqlite3?mode=rwc
cargo run -- --listen 127.0.0.1:8000

Open http://localhost:8000/admin/setup to create the first local admin account.

Docker

The image is built by GitHub Actions and published to Docker Hub as ultradesu/amnezia-fellow.

Required repository secrets:

  • DOCKERHUB_USERNAME
  • DOCKERHUB_TOKEN

Publishing runs for version tags matching v*.*.*. A tag like v0.1.0 pushes:

  • ultradesu/amnezia-fellow:v0.1.0
  • ultradesu/amnezia-fellow:0.1.0
  • ultradesu/amnezia-fellow:latest

Local image build:

docker build -t amnezia-fellow .
docker run --rm -p 8000:8000 -v "$PWD/data:/data" amnezia-fellow

Roles

There are two roles:

  • admin: full access, sees all client configs.
  • client: sees and manages only their own configs.

OIDC provisioning is deny-by-default:

  • users in AMNEZIA_FELLOW_OIDC_ADMIN_GROUPS become admin;
  • users in AMNEZIA_FELLOW_OIDC_CLIENT_GROUPS become client;
  • users outside both group lists cannot sign in.

The OIDC groups claim is expected to be groups.

VPN Data Model

SQLite stores all client data needed to restore configs:

  • owner user id
  • display name
  • assigned IPv4 address
  • public key
  • private key
  • enabled flag
  • created/updated timestamps

The Kubernetes Secret is derived from the database. Active clients are rendered into one configured Secret key, peers.conf by default.

Kubernetes Sync

The app is intended to run inside Kubernetes with a ServiceAccount and RBAC that can read and update Secrets and list Pods in the Amnezia namespace.

It reads:

  • server public key from AMNEZIA_FELLOW_K8S_SERVER_SECRET, key server-public-key;
  • node endpoints from AMNEZIA_FELLOW_K8S_ENDPOINTS_SECRET; Secret data keys are used as Amnezia server names in generated vpn:// links;
  • AmneziaWG pods selected by app=amneziawg for config rollout status;
  • writes rendered client peers to AMNEZIA_FELLOW_K8S_CLIENTS_SECRET.

It does not modify the server Secret. Argo/ExternalSecrets can keep managing amneziawg-server, while amnezia-fellow owns only the client Secret content.

UI

The main user interface is /configs. It is an Alpine.js reactive page backed by JSON API endpoints:

  • clients and admins use the same page;
  • the backend filters data by role;
  • admins get an extra manual Secret sync action.
  • clients and admins see AmneziaWG pod rollout status and uptime.

Environment Variables

All settings use AMNEZIA_FELLOW_ prefix. Priority is:

environment variable > database override > compiled default

Variable Description Default
AMNEZIA_FELLOW_DATABASE_URL SQLite connection URL sqlite://amnezia-fellow.sqlite3?mode=rwc
AMNEZIA_FELLOW_LOG_LEVEL Tracing filter info
AMNEZIA_FELLOW_AUTH_PASSWORD_ENABLED Enable password login true
AMNEZIA_FELLOW_AUTH_SSO_ENABLED Enable OIDC login false
AMNEZIA_FELLOW_OIDC_ISSUER OIDC issuer URL empty
AMNEZIA_FELLOW_OIDC_CLIENT_ID OIDC client ID empty
AMNEZIA_FELLOW_OIDC_CLIENT_SECRET OIDC client secret empty
AMNEZIA_FELLOW_OIDC_BUTTON_TEXT SSO button label Sign in with SSO
AMNEZIA_FELLOW_OIDC_ADMIN_GROUPS Comma-separated admin groups empty
AMNEZIA_FELLOW_OIDC_CLIENT_GROUPS Comma-separated client groups empty
AMNEZIA_FELLOW_K8S_NAMESPACE Amnezia namespace amnezia
AMNEZIA_FELLOW_K8S_CLIENTS_SECRET Client peers Secret amneziawg-clients
AMNEZIA_FELLOW_K8S_CLIENTS_SECRET_KEY Secret data key for rendered peers peers.conf
AMNEZIA_FELLOW_K8S_SERVER_SECRET Server config Secret amneziawg-server
AMNEZIA_FELLOW_K8S_ENDPOINTS_SECRET Node endpoints Secret amneziawg-endpoints
AMNEZIA_FELLOW_VPN_CLIENT_CIDR Client address pool 10.8.0.0/16
AMNEZIA_FELLOW_VPN_DNS DNS servers in generated configs 1.1.1.1, 8.8.8.8
AMNEZIA_FELLOW_VPN_MTU MTU in generated configs 1376
AMNEZIA_FELLOW_SWAGGER_ENABLED Serve Swagger UI at /swagger/ false
AMNEZIA_FELLOW_TELEGRAM_BOT_ENABLED Enable Telegram bot/Web App integration false
AMNEZIA_FELLOW_TELEGRAM_BOT_USERNAME Telegram bot username, with or without @ empty
AMNEZIA_FELLOW_TELEGRAM_BOT_TOKEN Telegram bot token used to verify Web App initData empty

Telegram Bot

Configure the bot through the admin Settings page or the matching environment variables:

AMNEZIA_FELLOW_TELEGRAM_BOT_ENABLED=true
AMNEZIA_FELLOW_TELEGRAM_BOT_USERNAME=<BOT_USERNAME>
AMNEZIA_FELLOW_TELEGRAM_BOT_TOKEN=<BOT_TOKEN>

In BotFather, create or reuse the same bot and set its Web App URL to https://<APP_HOST>/configs. The bot should reply with the sender's numeric Telegram ID, and users must open the bot and send /start once before notifications can be delivered.

API

The JSON API is session-authenticated:

  • GET /api/me
  • GET /api/vpn-clients
  • GET /api/vpn-status
  • POST /api/vpn-clients
  • POST /api/vpn-clients/{id}/enabled
  • DELETE /api/vpn-clients/{id}
  • GET /api/vpn-clients/{id}/config returns servers[] with one raw AWG config and one Amnezia vpn:// import link per registered endpoint
  • POST /api/vpn-clients/sync

Development

cargo fmt
cargo check

The project depends on public crates only; cot = "0.6.0" is pulled from crates.io.

S
Description
No description provided
Readme
846 KiB
Languages
Rust 59.8%
HTML 40%
Dockerfile 0.2%