wgusr 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wgusr-1.0.0/LICENSE +21 -0
- wgusr-1.0.0/PKG-INFO +440 -0
- wgusr-1.0.0/README.md +408 -0
- wgusr-1.0.0/pyproject.toml +60 -0
- wgusr-1.0.0/setup.cfg +4 -0
- wgusr-1.0.0/src/wgusr/__init__.py +3 -0
- wgusr-1.0.0/src/wgusr/__main__.py +6 -0
- wgusr-1.0.0/src/wgusr/activate.py +162 -0
- wgusr-1.0.0/src/wgusr/cli.py +395 -0
- wgusr-1.0.0/src/wgusr/client.py +200 -0
- wgusr-1.0.0/src/wgusr/config.py +85 -0
- wgusr-1.0.0/src/wgusr/ip_pool.py +94 -0
- wgusr-1.0.0/src/wgusr/keys.py +94 -0
- wgusr-1.0.0/src/wgusr/manager.py +445 -0
- wgusr-1.0.0/src/wgusr/sync_io.py +65 -0
- wgusr-1.0.0/src/wgusr/term.py +149 -0
- wgusr-1.0.0/src/wgusr/validators.py +227 -0
- wgusr-1.0.0/src/wgusr.egg-info/PKG-INFO +440 -0
- wgusr-1.0.0/src/wgusr.egg-info/SOURCES.txt +25 -0
- wgusr-1.0.0/src/wgusr.egg-info/dependency_links.txt +1 -0
- wgusr-1.0.0/src/wgusr.egg-info/entry_points.txt +2 -0
- wgusr-1.0.0/src/wgusr.egg-info/requires.txt +11 -0
- wgusr-1.0.0/src/wgusr.egg-info/top_level.txt +1 -0
- wgusr-1.0.0/tests/test_activate.py +186 -0
- wgusr-1.0.0/tests/test_client.py +43 -0
- wgusr-1.0.0/tests/test_term.py +139 -0
- wgusr-1.0.0/tests/test_validators.py +87 -0
wgusr-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 wgusr contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wgusr-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wgusr
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: WireGuard user management tool — add, delete, list, view, clear VPN peers
|
|
5
|
+
Author: wgusr contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/olk/wgusr
|
|
8
|
+
Project-URL: Repository, https://github.com/olk/wgusr
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: System Administrators
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: System :: Networking
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: wgconfig>=1.2.0
|
|
22
|
+
Requires-Dist: wireguard-tools>=0.6.0
|
|
23
|
+
Requires-Dist: pynacl>=1.5.0
|
|
24
|
+
Requires-Dist: qrcode>=7.4.2
|
|
25
|
+
Requires-Dist: pypng>=0.0.21
|
|
26
|
+
Requires-Dist: click>=8.0.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: ruff>=0.7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.11.0; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# wgusr
|
|
34
|
+
|
|
35
|
+
[](https://www.python.org/downloads/)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
WireGuard peer management — add, delete, list, view, and sync VPN users on a `wg-quick` server.
|
|
39
|
+
|
|
40
|
+
`wgusr` edits the `[Peer]` section of your `wg0.conf` directly: it generates keys and preshared keys, allocates VPN IPs from the existing pool, writes per-user client configs and QR codes, and hot-applies changes to the running interface — all under a file lock so concurrent invocations are safe.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Why wgusr?
|
|
45
|
+
|
|
46
|
+
Managing `wg0.conf` by hand means copy-pasting base64 keys, tracking IPs in a spreadsheet, and regenerating QR codes for every new user. `wgusr` automates that plumbing:
|
|
47
|
+
|
|
48
|
+
- **Atomic, locked edits** — `fcntl.flock` + temp-file-rename so a crash mid-write never corrupts your config.
|
|
49
|
+
- **Automatic IP allocation** — derives free IPs from existing `AllowedIPs`; no sidecar pool file.
|
|
50
|
+
- **Key generation in pure Python** — no `wg genkey` subprocess needed.
|
|
51
|
+
- **Client artifacts** — ready-to-scan WireGuard app configs (ASCII QR + PNG QR) written to `<wg-dir>/clients/`.
|
|
52
|
+
- **Hot sync** — apply a single peer or all peers to the live interface without restarting `wg-quick`.
|
|
53
|
+
|
|
54
|
+
## What wgusr does NOT do
|
|
55
|
+
|
|
56
|
+
- Does not install or load the `wireguard` kernel module.
|
|
57
|
+
- Does not bring the interface up (`wg-quick up wg0` is your responsibility).
|
|
58
|
+
- Does not create the `wg-quick@wg0.service` systemd unit (it ships with `wireguard-tools`).
|
|
59
|
+
- Does not configure firewall rules beyond the `nft` `PostUp`/`PostDown` hooks it emits during `init`.
|
|
60
|
+
- Does not provide a web UI.
|
|
61
|
+
|
|
62
|
+
`wgusr` edits the config file; `wg-quick` and the kernel apply it.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Prerequisites
|
|
67
|
+
|
|
68
|
+
- **Python ≥ 3.11**
|
|
69
|
+
- **Root** — required to read/write `/etc/wireguard`.
|
|
70
|
+
- **`wg` and `wg-quick`** from `wireguard-tools` — needed for `init` and `sync` (key generation itself is pure-Python and does not require them).
|
|
71
|
+
- **Loaded `wireguard` kernel module:**
|
|
72
|
+
```sh
|
|
73
|
+
modprobe wireguard
|
|
74
|
+
```
|
|
75
|
+
- **`net.ipv4.ip_forward=1`** — required for the server to route VPN traffic:
|
|
76
|
+
```sh
|
|
77
|
+
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-wireguard.conf
|
|
78
|
+
sysctl --system
|
|
79
|
+
```
|
|
80
|
+
- **`nft` table with `WG_IFACES` sets** — `wgusr init` emits `nft add element … WG_IFACES { wg0 }` in `PostUp`. The sets must exist before `wg-quick up` runs, otherwise the interface fails to start. Create them in e.g. `/etc/nftables.d/wireguard.nft`:
|
|
81
|
+
```
|
|
82
|
+
table ip filter {
|
|
83
|
+
set WG_IFACES { type ifname; }
|
|
84
|
+
}
|
|
85
|
+
table ip nat {
|
|
86
|
+
set WG_IFACES { type ifname; }
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
Apply with: `nft -f /etc/nftables.d/wireguard.nft`.
|
|
90
|
+
- **Systemd unit** — `systemctl enable --now wg-quick@wg0` (or bring the interface up manually).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Installation
|
|
95
|
+
|
|
96
|
+
### Development
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
make install-dev # editable install, includes ruff + mypy
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Release
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
make build # builds dist/wgusr-*.whl and *.tar.gz
|
|
106
|
+
make install # pip install dist/wgusr-*-py3-none-any.whl
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or directly:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
pip install .
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Verify:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
wgusr --version
|
|
119
|
+
wgusr --help
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Quick start
|
|
125
|
+
|
|
126
|
+
### 1. Initialise the interface
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
sudo wgusr init
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`wgusr init` is interactive. It will ask for:
|
|
133
|
+
|
|
134
|
+
| Prompt | Default | Description |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| Listen port | `51820` | UDP port for the server |
|
|
137
|
+
| Server public address | *(required)* | Your server's public hostname or IP, e.g. `vpn.example.com` |
|
|
138
|
+
| VPN network CIDR | `10.0.73.0/24` | Tunnel network; server takes `.1` |
|
|
139
|
+
| Use existing private/public key? | `n` | Generate new keys, paste existing, or read from a file |
|
|
140
|
+
|
|
141
|
+
`init` creates `/etc/wireguard/wg0.conf` with `Address`, `ListenPort`, `PrivateKey`, `SaveConfig = true`, and `PostUp`/`PostDown` nft hooks. It refuses to overwrite an existing config.
|
|
142
|
+
|
|
143
|
+
Bring the interface up:
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
sudo wg-quick up wg0
|
|
147
|
+
sudo systemctl enable --now wg-quick@wg0 # optional: start on boot
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Print the server's public key (needed by clients):
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
sudo wg show wg0 public-key
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2. Add a user
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
sudo wgusr add alice vpn.example.com
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Output:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
user 'alice' added with IP 10.0.73.2
|
|
166
|
+
|
|
167
|
+
Client config: /etc/wireguard/clients/alice-wg0.conf
|
|
168
|
+
|
|
169
|
+
QR code (scan with WireGuard app):
|
|
170
|
+
███████ ...
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Distribute the QR code or the `.conf` file to the client. The client's `[Interface] PrivateKey` and the server's `[Peer] PublicKey` are stored in `/etc/wireguard/clients/`.
|
|
174
|
+
|
|
175
|
+
### 3. Sync the peer to the live interface
|
|
176
|
+
|
|
177
|
+
Changes to `wg0.conf` are not applied automatically — `wg-quick` only reads the config at startup. Use `sync` to push a peer live without restarting anything:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
# sync a single user
|
|
181
|
+
sudo wgusr sync alice
|
|
182
|
+
|
|
183
|
+
# sync all peers at once (wg syncconf)
|
|
184
|
+
sudo wgusr sync --all
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Usage workflow
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
# Create a new interface (one-time)
|
|
193
|
+
sudo wgusr init
|
|
194
|
+
|
|
195
|
+
# Add a peer
|
|
196
|
+
sudo wgusr add alice vpn.example.com # auto IP
|
|
197
|
+
sudo wgusr add bob vpn.example.com --ip 10.0.73.50 # fixed IP
|
|
198
|
+
sudo wgusr add carol vpn.example.com --select-ip # interactive
|
|
199
|
+
|
|
200
|
+
# Push to the live interface
|
|
201
|
+
sudo wgusr sync alice # one peer
|
|
202
|
+
sudo wgusr sync --all # all peers at once
|
|
203
|
+
|
|
204
|
+
# Inspect
|
|
205
|
+
sudo wgusr list # table: USER, IP, PUBKEY
|
|
206
|
+
sudo wgusr view alice # client config + QR
|
|
207
|
+
|
|
208
|
+
# Remove a peer
|
|
209
|
+
sudo wgusr delete alice # by name
|
|
210
|
+
sudo wgusr delete --key <pubkey> # by public key (escape hatch)
|
|
211
|
+
sudo wgusr clear -y # wipe ALL peers (confirmation required)
|
|
212
|
+
|
|
213
|
+
# Short-hand
|
|
214
|
+
wgusr -v alice # equivalent to: wgusr view alice
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `wgusr add` flags
|
|
218
|
+
|
|
219
|
+
| Flag | Description |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `--ip 10.0.73.x` | Assign a specific VPN IP |
|
|
222
|
+
| `--select-ip` | Interactively choose from available IPs |
|
|
223
|
+
| `--dns 1.1.1.1` | DNS server for the client (default: server tunnel IP) |
|
|
224
|
+
| `--keepalive 25` | `PersistentKeepalive` seconds (0 = off) |
|
|
225
|
+
| `--no-psk` | Skip preshared key (not recommended) |
|
|
226
|
+
| `--existing-keys` | Use a provided keypair instead of generating |
|
|
227
|
+
| `--private-key` | Private key (requires `--existing-keys`) |
|
|
228
|
+
| `--public-key` | Public key (requires `--existing-keys`) |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Using wgusr on an existing server
|
|
233
|
+
|
|
234
|
+
`wgusr init` refuses to overwrite an existing `wg0.conf`. For servers you already have running, `wgusr` works immediately — it only reads the `[Interface]` section to learn the address, port, and private key:
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
sudo wgusr list # shows existing peers
|
|
238
|
+
sudo wgusr add dave vpn.example.com # appends a new peer
|
|
239
|
+
sudo wgusr sync dave # push dave live
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Peers added by hand (without `wgusr`) may lack the `# {user}` leading comment. `wgusr` reconciles these automatically from `clients/*.pub` files on every command run.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Example output
|
|
247
|
+
|
|
248
|
+
### `wgusr list`
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
USER IP PUBKEY
|
|
252
|
+
-------------------------------------------------------------------------------------
|
|
253
|
+
alice 10.0.73.2/32 XElbIX...qFE= 1 user(s)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### `wgusr add alice`
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
user 'alice' added with IP 10.0.73.2
|
|
260
|
+
|
|
261
|
+
Client config: /etc/wireguard/clients/alice-wg0.conf
|
|
262
|
+
|
|
263
|
+
QR code (scan with WireGuard app):
|
|
264
|
+
███████
|
|
265
|
+
█ ▄▄▄█
|
|
266
|
+
█ █▄█ █
|
|
267
|
+
...
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### `clients/` directory
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
/etc/wireguard/clients/
|
|
274
|
+
├── alice-wg0.conf # WireGuard app config (full tunnel)
|
|
275
|
+
├── alice-wg0.png # QR code PNG
|
|
276
|
+
├── alice.pri # client's private key
|
|
277
|
+
├── alice.pub # client's public key
|
|
278
|
+
└── alice.psk # preshared key
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Command reference
|
|
284
|
+
|
|
285
|
+
### Global options
|
|
286
|
+
|
|
287
|
+
| Flag | Default | Description |
|
|
288
|
+
|---|---|---|
|
|
289
|
+
| `--wg-dir DIR` | `/etc/wireguard` | WireGuard config directory |
|
|
290
|
+
| `--interface`, `-i` | `wg0` | Interface name |
|
|
291
|
+
| `--clients-dir DIR` | `<wg-dir>/clients` | Where per-user artifacts are stored |
|
|
292
|
+
|
|
293
|
+
### `wgusr init`
|
|
294
|
+
|
|
295
|
+
Interactively create a new `wg0.conf`. One-time setup; refuses to overwrite an existing file.
|
|
296
|
+
|
|
297
|
+
### `wgusr add <user> <endpoint-host>`
|
|
298
|
+
|
|
299
|
+
Add a peer to `wg0.conf`, generate keys, allocate an IP, and write client artifacts.
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
wgusr add alice vpn.example.com
|
|
303
|
+
wgusr -i wg0 add bob 192.168.1.100 --ip 10.0.73.50
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### `wgusr delete <user>`
|
|
307
|
+
|
|
308
|
+
Remove a peer and its client artifacts. Cross-checks the `# {user}` comment against `clients/{user}.pub` before deleting.
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
wgusr delete alice
|
|
312
|
+
wgusr delete --key XElbIX...qFE= # direct public-key delete
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### `wgusr list`
|
|
316
|
+
|
|
317
|
+
List all peers with their VPN IPs and public keys.
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
sudo wgusr list
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### `wgusr view <user>`
|
|
324
|
+
|
|
325
|
+
Print a user's client config and QR code to stdout.
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
sudo wgusr view alice
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### `wgusr sync <user>` / `wgusr sync --all`
|
|
332
|
+
|
|
333
|
+
Apply peer(s) to the live interface via `wg set` (single user) or `wg syncconf` (all).
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
sudo wgusr sync alice # one peer live immediately
|
|
337
|
+
sudo wgusr sync --all # full wg syncconf
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### `wgusr clear`
|
|
341
|
+
|
|
342
|
+
Remove **all** peers and all client artifacts. Requires `--yes` or confirmation prompt.
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
sudo wgusr clear -y
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Reloading the live interface
|
|
351
|
+
|
|
352
|
+
`wg-quick` reads `wg0.conf` only at startup. To apply config changes to a running interface:
|
|
353
|
+
|
|
354
|
+
- **Single peer:** `wgusr sync <user>` — `wg set` updates just that peer, no disruption to others.
|
|
355
|
+
- **All peers:** `wgusr sync --all` — `wg syncconf` does a full atomic reconcile.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## How it works
|
|
360
|
+
|
|
361
|
+
`wgusr` reads and writes `wg0.conf` using the `wgconfig` library. Every mutation:
|
|
362
|
+
|
|
363
|
+
1. Acquires an advisory `fcntl.flock` on `<iface>.lock` (shared for reads, exclusive for writes).
|
|
364
|
+
2. Reconciles `# {user}` leading comments from `clients/*.pub` files.
|
|
365
|
+
3. Writes to a temp file in the same directory (mode 0o600).
|
|
366
|
+
4. Atomically replaces the target via `os.replace` (guaranteed atomic on POSIX).
|
|
367
|
+
|
|
368
|
+
IP addresses are derived from existing peer `AllowedIPs` — no sidecar pool file is needed. `wgusr sync` shells out to `wg set` or `wg syncconf` to push changes into the kernel; it does not restart `wg-quick`.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Backup & recovery
|
|
373
|
+
|
|
374
|
+
`/etc/wireguard/clients/` is the source of truth for all private keys, preshared keys, and client configs. To back up or migrate:
|
|
375
|
+
|
|
376
|
+
```sh
|
|
377
|
+
tar -czf wg-backup.tar.gz /etc/wireguard/wg0.conf /etc/wireguard/clients/
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Security:** `.pri` and `.psk` files are plaintext (mode 0o600). Store backups encrypted at rest and never sync them to untrusted storage.
|
|
381
|
+
|
|
382
|
+
To restore: extract the archive and run `wgusr sync --all` to re-apply all peers.
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Troubleshooting
|
|
387
|
+
|
|
388
|
+
| Symptom | Fix |
|
|
389
|
+
|---|---|
|
|
390
|
+
| `error: 'wg' binary not found` | `apt install wireguard-tools` (or your distro's package) |
|
|
391
|
+
| `wg-quick up wg0` fails on `nft add element` | Define the `WG_IFACES` sets before starting the interface (see Prerequisites) |
|
|
392
|
+
| VPN clients can't reach the internet | `sysctl net.ipv4.ip_forward=1` and add a masquerade rule to your nft/iptables |
|
|
393
|
+
| `wgusr list` shows `(no name)` | Peer lacks a `# {user}` comment; auto-reconciled on the next `wgusr` command |
|
|
394
|
+
| Permission denied in `clients/` | Run `wgusr` as root |
|
|
395
|
+
| `wg-quick@wg0` is running stale config | `sudo wgusr sync --all` to push current conf, or `systemctl restart wg-quick@wg0` |
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Multiple interfaces
|
|
400
|
+
|
|
401
|
+
Manage multiple WireGuard interfaces by passing `--interface`:
|
|
402
|
+
|
|
403
|
+
```sh
|
|
404
|
+
sudo wgusr -i wg1 add dave vpn.example.com
|
|
405
|
+
sudo wgusr -i wg1 sync dave
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Each interface has its own `wg{n}.conf` and its own `PostUp`/`PostDown` hooks. The `PostDown` hook removes **only** that interface from the shared `WG_IFACES` sets (bug fixed in v0.1.1; older versions flushed the entire set).
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Uninstall
|
|
413
|
+
|
|
414
|
+
```sh
|
|
415
|
+
pip uninstall wgusr
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
This removes the CLI. Left behind:
|
|
419
|
+
|
|
420
|
+
- `/etc/wireguard/wg0.conf` — your server config
|
|
421
|
+
- `/etc/wireguard/clients/` — all private keys and client configs
|
|
422
|
+
- The running `wg-quick@wg0` service and the nft ruleset
|
|
423
|
+
|
|
424
|
+
Clean these up manually if no longer needed.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Security notes
|
|
429
|
+
|
|
430
|
+
- All file writes run under `umask 0o077`; artifacts are mode 0o600.
|
|
431
|
+
- Private keys are created with exclusive-create (`O_CREAT | O_EXCL`) — `wgusr` refuses to overwrite an existing key.
|
|
432
|
+
- All user inputs are validated before use: username, interface name, IP address, public key, and keepalive are checked against strict regexes and ranges.
|
|
433
|
+
- Path-traversal guards prevent `wg-dir` or `interface` from escaping the intended directory.
|
|
434
|
+
- After any manual edit to `wg0.conf`, run `wgusr sync --all` to bring the live interface in sync.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## License
|
|
439
|
+
|
|
440
|
+
Licensed under the [MIT License](LICENSE).
|