WG(8)

πŸ“¦ version 3.1.20260812, in nixpkgs unstable

πŸ¦‹ WG(8) β€” wg πŸ¦‹

okay bestie, so like, wg is THE command-line utility for WireGuard. It's the manual page WG(8) and it's giving very much "how do I even configure this tunnel" energy. Sit down, grab a strawberry drink πŸ“, and let's go.


✨ SYNOPSIS ✨

wg [ COMMAND ] [ OPTIONS ]... [ ARGS ]...

πŸ’– DESCRIPTION πŸ’–

so wg is the configuration utility for getting and setting the configuration of WireGuard tunnel interfaces. That's literally its whole job and it ate. πŸ‘‘

but lowkey important: the interfaces themselves don't get created by wg. If you wanna add or remove them, that's ip-link(8)'s moment. And if you wanna set their IP addresses and routing tables, that's ip-address(8) and ip-route(8)'s moment. The wg utility is specifically here to give you a little series of sub-commands for changing the WireGuard-specific aspects of WireGuard interfaces. iykyk.

and ngl, if you don't specify a COMMAND at all, COMMAND just defaults to show. slay, it's got a default. πŸ’…

⚠️ heads up: any sub-command that takes an INTERFACE must be passed an actual WireGuard interface. no fake ones. no vibes-only ones.

🌈 COMMANDS 🌈

πŸ’« show { <interface> | all | interfaces } [public-key | private-key | listen-port | fwmark | peers | preshared-keys | endpoints | allowed-ips | latest-handshakes | persistent-keepalive | transfer | dump]

Shows the current WireGuard configuration and runtime information of the specified <interface>. If you don't specify an <interface>, <interface> defaults to all. 🫢

If you say interfaces, it prints a list of all WireGuard interfaces, one per line, and then it quits. that's it, that's the whole task, bye. πŸ’€

If you give no options after the interface specification, then it prints a list of all attributes in a visually pleasing way β€” like genuinely meant for the terminal, pretty, iconic, main character energy. ✨

Otherwise, it prints the specified information grouped by newlines and tabs, meant to be used in scripts. So like, the script-friendly display. For that script-friendly display, if all is specified, then the first field for all categories of information is the interface name. (yes, every single one. the interface name leads. πŸ“Œ)

And if dump is specified, then several lines are printed:

  • the first line contains, in order, separated by tab: private-key, public-key, listen-port, fwmark
  • subsequent lines are printed for each peer and contain, in order, separated by tab: public-key, preshared-key, endpoint, allowed-ips, latest-handshake, transfer-rx, transfer-tx, persistent-keepalive

no cap, that order matters. 🧚

πŸ’« showconf <interface>

Shows the current configuration of <interface> in the format described by CONFIGURATION FILE FORMAT below. so it's the same tea, just in config-file costume. πŸŽ€

πŸ’« set <interface> [listen-port <port>] [fwmark <fwmark>] [private-key <file-path>] [peer <base64-public-key> [remove] [preshared-key <file-path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...

Sets configuration values for the specified <interface>. This one's the big one, so buckle up. 🎒

  • Multiple peers may be specified. like, as many as you want, go off.
  • If the remove argument is given for a peer, that peer is removed, not configured. it's a delete, not an edit, bestie. πŸ—‘οΈ
  • If listen-port is not specified, or set to 0, the port will be chosen randomly when the interface comes up. chaos port. 🎲
  • Both private-key and preshared-key must be files, because command line arguments are not considered private on most systems. 😭 but if you're using bash(1), you may safely pass in a string by specifying as private-key or preshared-key the expression: <(echo PRIVATEKEYSTRING). iconic workaround, honestly.
  • If /dev/null or another empty file is specified as the filename for either private-key or preshared-key, the key is removed from the device. poof. ✨
  • The use of preshared-key is optional, and may be omitted; it adds an additional layer of symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance. (yes, she's extra AND she's secure. we love her.)
  • If allowed-ips is specified, but the value is the empty string, all allowed ips are removed from the peer.
  • The use of persistent-keepalive is optional and is by default off; setting it to 0 or "off" disables it. Otherwise it represents, in seconds, between 1 and 65535 inclusive, how often to send an authenticated empty packet to the peer, for the purpose of keeping a stateful firewall or NAT mapping valid persistently. like β€” for example, if the interface very rarely sends traffic, but it might at anytime receive traffic from a peer, and it is behind NAT, the interface might benefit from having a persistent keepalive interval of 25 seconds; however, most users will not need this. (most of y'all? not your problem. but now you know. 🫢)
  • The use of fwmark is optional and is by default off; setting it to 0 or "off" disables it. Otherwise it is a 32-bit fwmark for outgoing packets and may be specified in hexadecimal by prepending "0x". hex girlies rise. πŸ”₯

πŸ’« setconf <interface> <configuration-filename>

Sets the current configuration of <interface> to the contents of <configuration-filename>, which must be in the format described by CONFIGURATION FILE FORMAT below. full replace, no survivors, periodt. πŸ’…

πŸ’« addconf <interface> <configuration-filename>

Appends the contents of <configuration-filename>, which must be in the format described by CONFIGURATION FILE FORMAT below, to the current configuration of <interface>. it's the "and also this" of the family. 🌸

πŸ’« syncconf <interface> <configuration-filename>

Like setconf, but it reads back the existing configuration first and only makes changes that are explicitly different between the configuration file and the interface. 🧠✨

This is much less efficient than setconf, but it has the benefit of not disrupting current peer sessions. so like, slower but so much nicer to your connections. tradeoff queen.

The contents of <configuration-filename> must be in the format described by CONFIGURATION FILE FORMAT below.

πŸ’« genkey

Generates a random private key in base64 and prints it to standard output. one job. does it perfectly. πŸ‘‘

πŸ’« genpsk

Generates a random preshared key in base64 and prints it to standard output. same energy, different key type, we stan. πŸŽ€

πŸ’« pubkey

Calculates a public key and prints it in base64 to standard output from a corresponding private key (generated with genkey) given in base64 on standard input.

and like, a private key and a corresponding public key may be generated at once by calling:

$ umask 077
$ wg genkey | tee private.key | wg pubkey > public.key

look at that pipeline. beautiful. no notes. 😭πŸ”₯

πŸ’« help

Shows usage message. that's it. that's the whole vibe. 🫢


okay so that's the commands section wrapped and honestly? she ate. but we are NOT done, because next up is the configuration file format and it's giving INI with a WireGuard twist, so keep scrolling bestie πŸ’œ

🌟 AUTHOR 🌟

okay bestie, moment of appreciation for the icon who made all of this happen 🫢✨

  • wg was written by Jason A. Donenfeld β€” yes, that Jason A. Donenfeld, the main character who literally typed this whole thing into existence πŸ’…πŸ‘‘
  • and if you're the kind of girlie who needs updates and more information (same, honestly, i stalk release notes like they're a group chat πŸ™ˆ), the project page is available on the World Wide Web 🌈

like, go look it up, it's giving "authorized source of truth" energy πŸ’– no cap, that's where the fresh info lives πŸ¦‹


so that's the whole page, bestie πŸŽ€ you made it to the end β€” which is honestly iconic of you πŸ˜­πŸ’œ go forth and tunnel responsibly, and remember: the vibes are encrypted, but the facts were never watered down 🌸✨

lowkey a flex that this page is version ZX2C4, dated 2015 August 13, and filed under section WG(8) β€” screenshot-worthy, fr fr πŸ“ΈπŸ‘‘
πŸ“¦ where this page comes from