Managing AmneziaWG clients from the command line
amneziawg-installer sets up AmneziaWG 2.0 on Ubuntu and Debian. From there manage_amneziawg.sh takes over the clients: add one, remove one, reissue a config, hand out a QR code or a vpn:// link. The same script reports traffic, takes backups and repairs the kernel module after a kernel upgrade. All of it one command over SSH, with JSON output for scripts and bots.
Typical tasks
Only the subcommand is shown; the full call is sudo bash /root/awg/manage_amneziawg.sh <command>.
| Task | Command |
|---|---|
| Add a phone and get a QR code | add phone |
| Add three devices in one go | add phone laptop tablet |
| Give a guest access for a week | add guest --expires=7d |
| Revoke access | remove guest |
| See who is connected and how much they used | stats |
| Reissue a config after a lost phone | regen phone |
| Back up before touching anything | backup |
| Bring the tunnel back after a kernel upgrade | repair-module |
Every command in one table
The installer puts the script on the server for you; run it as root. The JSON column says what the --json flag returns.
| Command | What it does | JSON |
|---|---|---|
add <name> [name2 ...] | Adds a client: keys, config, QR code and a vpn:// link. Several names at once. --expires= for time-limited access, --psk for a PresharedKey. | object |
remove <name> [name2 ...] | Removes a client and revokes its access. Several names at once. | object |
list | Lists clients. -v adds detail; the JSON form also carries the IPv6 address and a machine-stable status. | array |
stats | Per-client traffic and last handshake. | array |
regen [name ...] | Regenerates the client files, keeping the keys and the address. --reset-routes resets the routing to the current mode. | object |
modify <name> <param> <value> | Changes a single client parameter. | object |
backup | Creates a backup of the server config and the client set. | object |
restore [file] | Restores from a backup and reports whether a rollback happened. | object |
check | Server health: module, service, port, firewall. Alias: status. | object |
diagnose | Self-troubleshooting: kernel, sysctl and UFW, plus --carrier= to compare the obfuscation against a mobile-carrier profile. | human only |
show | Raw awg show output. | human only |
restart | Restarts the AmneziaWG service. | object |
repair-module | Rebuilds the kernel module after a kernel upgrade and brings the tunnel back. Alias: repair. | object |
help | Full usage with every flag. | human only |
A time limit is written as Nh, Nd or Nw: 12h, 7d, 4w. A cron job checks expiry every five minutes and removes what has expired, so nothing has to be cleaned up by hand.
Machine-readable output for scripts and bots
Since v5.21.0 the management commands take --json. It exists so that a bot never has to scrape human text or guess whether a command worked.
Exactly one JSON document
For a command that supports the flag, stdout carries exactly one JSON document per run, on every outcome including a crash or a refused confirmation. Envelope commands return an object, list and stats a bare array. Human messages go to stderr, so the two streams never mix.
The exit code is the source of truth
The ok field mirrors it for bots that only read stdout. A partial failure counts as a failure: add a b where b already exists returns ok:false.
Compatibility is additive
New fields may appear over time; existing ones are never renamed and never change type. list and stats stay bare arrays, as they always were.
Confirmation and non-interactive runs
--json does not imply --yes - they are independent flags. But do not treat the prompt as a safety net: with no terminal there is nobody to ask, and a destructive command proceeds silently. To have such a run refused instead, set AWG_STRICT_CONFIRM=1 - then remove without --yes returns a refusal with rc 1.
A successful add:
{"command":"add","ok":true,"added":1,"failed":0,"applied":true,
"results":[{"name":"phone","status":"created","conf":"/root/awg/phone.conf",
"qr":"/root/awg/phone.png","vpnuri":"/root/awg/phone.vpnuri","expires_at":null}]}
Any failure, including an aborted confirmation:
{"command":"remove","ok":false,"error":"confirmation denied","rc":1}
The error field is human-readable text and may be localized. In code, decide from ok, rc and status instead. Two traps. First, repair-module.rc is the internal module-check code, not the process exit code. Second, a usage error also comes back as an envelope, and command then holds either help or the unknown command itself rather than one of the 14 canonical names. Aliases are canonicalized: the reply always says check and repair-module, however the command was typed.
Client status codes
The status_code field is present in both list --json and stats --json. Unlike the human-facing status, these values do not depend on the language of the script.
| Value | Meaning |
|---|---|
active | Handshake less than 3 minutes ago. |
recent | Handshake within the last 24 hours. |
inactive | No handshake, or a stale one (stats). |
no_handshake | No handshake, or a stale one (list). |
key_error | The client key is missing from the server config. |
no_data | Not enough data to judge. |
awgram, a third-party Telegram bot written in Rust, goes through exactly this interface: it adds and removes clients, reads stats and triggers backups. The full contract lives in ADVANCED.en.md.
FAQ
Do I need a web panel to manage AmneziaWG clients?
manage_amneziawg.sh, which adds, removes, regenerates and lists clients from a single SSH command, and prints machine-readable JSON for scripts and bots. A panel is worth it only if you add and change clients constantly; for a server that is set up once and forgotten, it is one more moving part to keep patched.How do I add a client to an AmneziaWG server?
sudo bash /root/awg/manage_amneziawg.sh add phone. The script generates the keys, writes the config, renders a QR code and a vpn:// link for one-tap import into the Amnezia app, and applies the change to the running interface. Several names can be passed at once: add phone laptop tablet.How do I remove a client and revoke access?
sudo bash /root/awg/manage_amneziawg.sh remove phone. The client key is dropped from the server config and the change is applied to the running interface, so the old config stops connecting right away and there is nothing to reissue. Several names work here too: remove phone laptop.Can I give someone temporary access?
add guest --expires=7d creates a client that stops working after the given period. A duration is written as Nh, Nd or Nw: 12h, 7d, 4w. A cron job checks every five minutes and removes what has expired.Can I manage the server from a script or a bot?
--json. Management commands reply with exactly one JSON document on stdout, including when they fail, and human messages go to stderr. list and stats return a plain array instead, and show and diagnose do not take the flag. A third-party Telegram bot, awgram, already runs on this interface.What does a command return when it fails?
ok:false with a human-readable error and rc. A batch command such as add instead reports the outcome per name inside results[] and sets ok:false, with no rc field. The process exit code is authoritative and ok mirrors it. Do not parse the error text: decide from ok, rc and status.The kernel was upgraded and the tunnel stopped working. What now?
repair-module rebuilds the kernel module through DKMS, loads it and starts the service again. A kernel upgrade does not mean a reinstall.