WG-QUICK(8)

πŸ“¦ version 3.1.20260812, in nixpkgs unstable

✨ WG-QUICK(8) ✨

okay bestie, listen up πŸ’– this is the manual page for wg-quick, which lives in the WireGuard section 8 of your man pages (the system administration girlies section, periodt). it's the little script that makes WireGuard go brrr without you having to type forty commands. let's get into it πŸ¦‹


🌸 NAME 🌸

wg-quick β€” set up a WireGuard interface simply. that's it. that's the whole job. simple. slay. πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

wg-quick [ up | down | save | strip ] [ CONFIG_FILE | INTERFACE ]

four little verbs, one of them, plus a file or an interface. iconic. πŸ‘‘


πŸ’œ DESCRIPTION πŸ’œ

bestie, this is an extremely simple script for easily bringing up a WireGuard interface, and it's suitable for a few common use cases. not all the use cases. a few. know the difference 🫢

use up to add and set up an interface, and use down to tear down and remove an interface.

running up does a whole little routine: it adds a WireGuard interface, brings up the interface with the supplied IP addresses, sets up mtu and routes, and optionally runs pre/post up scripts. multitasking queen ✨

running down optionally saves the current configuration, removes the WireGuard interface, and optionally runs pre/post down scripts.

running save saves the configuration of an existing interface without bringing the interface down. she's respectful like that πŸ’–

use strip to output a configuration file with all wg-quick(8)-specific options removed, suitable for use with wg(8).


so like, what even is CONFIG_FILE? it's a configuration file whose filename is the interface name followed by .conf. otherwise, INTERFACE is an interface name, with configuration found at /etc/wireguard/INTERFACE.conf, searched first, followed by distro-specific search paths. first place first, then the distro does its little thing 🌈

generally speaking (ngl this is important), this utility is just a simple script that wraps invocations to wg(8) and ip(8) in order to set up a WireGuard interface. it is designed for users with simple needs, and users with more advanced needs are highly encouraged to use a more specific tool, a more complete network manager, or otherwise just use wg(8) and ip(8), as usual. no shade, she's just telling you she's a simple girl and you should get a real tool if you need more 😌


πŸ¦‹ CONFIGURATION πŸ¦‹

the configuration file adds a few extra configuration values to the format understood by wg(8) in order to configure additional attributes of an interface. it handles the values that it understands, and then it passes the remaining ones directly to wg(8) for further processing. she takes what she knows, hands off the rest. delegating icon πŸ’…

it infers all routes from the list of peers' allowed IPs, and automatically adds them to the system routing table. and if one of those routes is the default route (0.0.0.0/0 or ::/0), then it uses ip-rule(8) to handle overriding of the default gateway. automatic. no cap 🧚

the configuration file will be passed directly to wg(8)'s setconf sub-command, with the exception of the following additions to the Interface section, which are handled by this tool:

  • Address β€” a comma-separated list of IP (v4 or v6) addresses (optionally with CIDR masks) to be assigned to the interface. may be specified multiple times. stack those addresses, queen πŸ‘‘
  • DNS β€” a comma-separated list of IP (v4 or v6) addresses to be set as the interface's DNS servers, or non-IP hostnames to be set as the interface's DNS search domains. may be specified multiple times. upon bringing the interface up, this runs resolvconf -a tun.INTERFACE -m 0 -x and upon bringing it down, this runs resolvconf -d tun.INTERFACE. if these particular invocations of resolvconf(8) are undesirable, the PostUp and PostDown keys below may be used instead. so you got options, bestie ✨
  • MTU β€” if not specified, the MTU is automatically determined from the endpoint addresses or the system default route, which is usually a sane choice. however, to manually specify an MTU to override this automatic discovery, this value may be specified explicitly. let her cook, or take the wheel yourself πŸ“
  • Table β€” controls the routing table to which routes are added. there are two special values: off disables the creation of routes altogether, and auto (the default) adds routes to the default table and enables special handling of default routes. two moods: off and auto πŸ’€
  • PreUp, PostUp, PreDown, PostDown β€” script snippets which will be executed by bash(1) before/after setting up/tearing down the interface, most commonly used to configure custom DNS options or firewall rules. the special string %i is expanded to INTERFACE. each one may be specified multiple times, in which case the commands are executed in order. order matters, she's not chaotic (mostly) 🌸
  • SaveConfig β€” if set to true, the configuration is saved from the current state of the interface upon shutdown.
⚠️ heads up: with SaveConfig, any changes made to the configuration file before the interface is removed will therefore be overwritten. so like, write your edits after she's down, or she'll eat them 😭

recommended INTERFACE names include wg0 or wgvpn0 or even wgmgmtlan0. however, the number at the end is in fact optional, and really any free-form string [a-zA-Z0-9_=+.-]{1,15} will work. so even interface names corresponding to geographic locations would suffice, such as cincinnati, nyc, or paris, if that's somehow desirable. name your tunnel after your city, main character energy fr fr πŸ™οΈ


πŸ”₯ EXAMPLES πŸ”₯

these examples draw on the same syntax found for wg(8), and a more complete description may be found there. bold lines below are for options that extend wg(8).

the following might be used for connecting as a client to a VPN gateway for tunneling all traffic:

[Interface]
Address = 10.200.100.8/24
DNS = 10.200.100.1
PrivateKey = oK56DE9Ue9zK76rAc8pBl6opph+1v36lm7cXXsQKrQM=

[Peer]
PublicKey = GtL7fZc/bLnqZldpVofMCD6hDjrK28SsdLxevJ+qtKU=
PresharedKey = /UwcSPg38hW/D9Y3tcS1FOV0K1wuURMbS0sesJEP5ak=
AllowedIPs = 0.0.0.0/0
Endpoint = demo.wireguard.com:51820

the Address field is added here in order to set up the address for the interface. the DNS field indicates that a DNS server for the interface should be configured via resolvconf(8). the peer's allowed IPs entry implies that this interface should be configured as the default gateway, which this script does. she read your mind and did it πŸ’–


building on the last example, one might attempt the so-called "kill-switch", in order to prevent the flow of unencrypted packets through the non-WireGuard interfaces, by adding the following two lines PostUp and PreDown lines to the [Interface] section:

PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i
fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i
fwmark) -m addrtype ! --dst-type LOCAL -j REJECT

the PostUp and PreDown fields have been added to specify an iptables(8) command which, when used with interfaces that have a peer that specifies 0.0.0.0/0 as part of the AllowedIPs, works together with wg-quick's fwmark usage in order to drop all packets that are either not coming out of the tunnel encrypted or not going through the tunnel itself. (note that this continues to allow most DHCP traffic through, since most DHCP clients make use of PF_PACKET sockets, which bypass Netfilter.) when IPv6 is in use, additional similar lines could be added using ip6tables(8). no leaks, bestie 🫢


or, perhaps it is desirable to store private keys in encrypted form, such as through use of pass(1):

PreUp = wg set %i private-key <(pass WireGuard/private-keys/%i)

cryptographic secrecy, but make it cute πŸ”


for use on a server, the following is a more complicated example involving multiple peers:

[Interface]
Address = 10.192.122.1/24
Address = 10.10.0.1/16
SaveConfig = true
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=
ListenPort = 51820

[Peer]
PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
AllowedIPs = 10.192.122.3/32, 10.192.124.1/24

[Peer]
PublicKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=
AllowedIPs = 10.192.122.4/32, 192.168.0.0/16

[Peer]
PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=
AllowedIPs = 10.10.10.230/32

notice the two Address lines at the top, and that SaveConfig is set to true, indicating that the configuration file should be saved on shutdown using the current status of the interface. she's keeping receipts ✨


a combination of the Table, PostUp, and PreDown fields may be used for policy routing as well. for example, the following may be used to send SSH traffic (TCP port 22) traffic through the tunnel:

[Interface]
Address = 10.192.122.1/24
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=
ListenPort = 51820
Table = 1234
PostUp = ip rule add ipproto tcp dport 22 table 1234
PreDown = ip rule delete ipproto tcp dport 22 table 1234

[Peer]
PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
AllowedIPs = 0.0.0.0/0

policy routing but make it ✨selective✨


these configuration files may be placed in any directory, putting the desired interface name in the filename:

# wg-quick up /path/to/wgnet0.conf

for convenience, if only an interface name is supplied, it automatically chooses a path in /etc/wireguard/:

# wg-quick up wgnet0

this will load the configuration file /etc/wireguard/wgnet0.conf. see? convenience queen πŸ‘‘

the strip command is useful for reloading configuration files without disrupting active sessions:

# wg syncconf wgnet0 <(wg-quick strip wgnet0)

zero downtime, zero drama, we love to see it 🌈


πŸ’… SEE ALSO πŸ’…

wg(8), ip(8), ip-link(8), ip-address(8), ip-route(8), ip-rule(8), resolvconf(8).

(the whole ip family showed up. it's giving family reunion πŸŽ€)


🫢 AUTHOR 🫢

wg-quick was written by Jason A. Donenfeld. for updates and more information, a project page is available on the World Wide Web. thank you for your service king πŸ‘‘


that's the whole page bestie!! this one's from the ZX2C4 girlies, dated 2016 January 1, and it's filed under WG-QUICK(8). go set up a tunnel and be free πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from