Skip to content
mrcsinPublic

About

User management for the VPN services

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

usher

ci License

User management for the VPN services of one node. You list users and the interfaces each may use in one file; a few seconds after you save it, usher creates their keys, puts them into the running services and writes a ready client config per user and interface. Addresses and keys stay internal: you type names only. An interface is an AmneziaWG interface or an inbound of your Xray config.

usher holds no capabilities and is never in the packet path. Every VPN service runs in its own container with a small management API on a unix socket; usher calls that API and nothing else, so a crash or an upgrade of usher leaves every session running. AmneziaWG is supported through awg-grpc, Xray through its own gRPC API.

How it fits together

flowchart TD
  subgraph docker[Docker services]
    usher[usher]
    awg[awg-grpc]
    subgraph xray[Xray]
      vless[inbound vless-reality]
      hy2[inbound hy2]
    end
  end
  subgraph os[OS network interfaces]
    awg0[awg0]
    awg1[awg1]
  end
  usher -- "USHER_AWG_SOCKET, gRPC" --> awg
  usher -- "USHER_XRAY_SOCKET, gRPC HandlerService" --> xray
  awg -- "awg set" --> awg0
  awg -- "awg set" --> awg1
Loading

usher drives one awg-grpc and one Xray: each variable names one socket. One awg-grpc carries any number of AmneziaWG interfaces, one Xray any number of inbounds, and every name you put in usher.yml is one of them.

The socket is the only control channel, and it has no authentication: any process that can open it controls every peer or user of that service. Each service creates its socket with mode 0660, so usher must belong to the socket's group to open it. The usher image runs as uid and gid 1000, and the example compose file gives both sockets that group.

Through the sockets usher owns every interface awg-grpc reports and every Xray inbound with a tag and a supported protocol: it removes any peer or user that usher.yml does not list.

Users

usher keeps everything under /srv/usher in its container; the example compose file mounts the three directories:

/srv/usher/
├── config/usher.yml                  you write it, usher only reads it
├── state/users.json                  usher writes it, back it up
└── clients/<user>/<interface>.<ext>  usher writes it, hand the files to the users

config/usher.yml:

alice-phone: [awg0]
alice-laptop: [awg0, vless-reality]
bob: []
  • Give each device its own name.
  • A user name has up to 32 lowercase letters, digits, _ and -, and starts with a letter or a digit.
  • Removing a name, or setting it to [], switches the user off. The keys stay, and putting the name back restores the same config.
  • usher checks the file at every change: YAML syntax, the name rules, no user or interface listed twice, and at least one user with an interface, so a truncated file cannot switch everyone off. A file that fails changes nothing: usher logs the error with its line and keeps the last valid file in memory, through any number of failed saves in a row. It never writes usher.yml. After a restart there is no earlier valid file, so usher logs and does nothing until the file is valid.
  • awg-grpc and Xray hold no user state: a restart of either starts it empty. usher holds all of it in state/users.json and puts the users back within 30 s.

For this file clients/ holds:

clients/
├── alice-phone/
│   └── awg0.conf
└── alice-laptop/
    ├── awg0.conf
    ├── vless-reality.json
    └── vless-reality.txt

state/users.json is the only copy of every key, so keep the state volume in the backup set. docs/operations.md covers client isolation, DNS and new keys for a user.

Running

deploy/compose.example.yml runs usher next to awg-grpc and Xray. With one backend, delete the other service and its socket variables from the file. Images are ghcr.io/mrcsin/usher:<version>, such as v0.2.0.

Variable Required Example Meaning
USHER_HOST yes 203.0.113.10 IPv4 address clients connect to, not a host name
USHER_AWG_SOCKET one of the two sockets /run/awg-grpc/awg.sock awg-grpc socket; enables AmneziaWG
USHER_DNS with USHER_AWG_SOCKET 1.1.1.1,1.0.0.1 DNS servers in AmneziaWG configs
USHER_XRAY_SOCKET one of the two sockets /run/xray/api.sock Xray API socket; enables Xray
USHER_XRAY_CONFIG with USHER_XRAY_SOCKET /etc/xray/config.json Xray server config, read-only

USHER_AWG_SOCKET, USHER_XRAY_SOCKET and USHER_XRAY_CONFIG are absolute paths inside the usher container.

USHER_HOST is an address because a client resolves a host name through its DNS server, which sits inside the tunnel. When the tunnel drops, the client cannot resolve the name and does not reconnect.

Besides the sockets, every deployment gives usher read access to the Xray config file and publishes each interface port on the same host port, because client configs carry the port of the interface. usher itself listens on no port. The comments in the example compose file carry the rest of the wiring.

AmneziaWG

An interface is a <name>.conf file of awg-grpc; usher manages its peers only. A user gets the lowest free address of the interface's IPv4 subnet, an X25519 key pair and a preshared key. The client .conf carries that address, USHER_DNS, the obfuscation parameters of the interface and USHER_HOST with the interface port as the endpoint. An interface holds at most 1000 users.

Xray

You write the Xray server config, and usher fills its inbounds with users. An inbound tag is the interface name in usher.yml. usher puts users into the running inbounds through Xray's HandlerService and never writes the config. The .json client config runs a local socks proxy on 127.0.0.1:10808 and an http proxy on 127.0.0.1:10809; the .txt file is a share link. docs/xray.md covers the server config contract, the supported shapes, the x-usher block, TLS trust, client compatibility and config edits.

License

MIT

About

User management for the VPN services

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages