aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/blog/freebsd/factorio-to-nas.md224
-rw-r--r--static/static/factorio-wireguard.drawio.svg3
2 files changed, 227 insertions, 0 deletions
diff --git a/content/blog/freebsd/factorio-to-nas.md b/content/blog/freebsd/factorio-to-nas.md
new file mode 100644
index 0000000..801e361
--- /dev/null
+++ b/content/blog/freebsd/factorio-to-nas.md
@@ -0,0 +1,224 @@
+---
+title: Exposing a FreeBSD jail through wireguard
+description: Migrating my Factorio jail to my home network, routing the traffic from the internet facing vps through wireguard
+date: 2023-01-07
+tags:
+- Factorio
+- FreeBSD
+- jail
+- wireguard
+---
+
+## Introduction
+
+In a previous blog article, I detailed how I [run a Factorio linux jail]({{< ref "factorio-server-in-a-linux-jail.md" >}}) on a small vps (1 vcpu and 2G of ram). After some time growing our bases on the same map with a friend, we started to see the limits of this small server. As I do not have a cloud server more powerful, I chose to migrate this to a former home server (4 cores and 8G of ram).
+
+Since it is on my home network and no longer facing the internet, I needed a way to still expose it from the vps and chose to use wireguard and some pf rules to do so:
+
+![factorio on a home server exposed via wireguard](/static/factorio-wireguard.drawio.svg)
+
+## Preparing the home server
+
+All this is automated with ansible for me, but here is a breakdown of the required configuration.
+
+### Jail Networking
+
+I strive for the simplest setup and this jail just needs the legacy loopback interface way of doing things:
+```sh
+echo 'cloned_interfaces="lo1"' >> /etc/rc.conf
+service netif cloneup
+```
+
+Many jail tutorials will tell you to configure the jail ips in `/etc/rc.conf` too, this is not what I do. It is difficult to automate and I find that having those ips in the `jails.conf` file is a lot more flexible.
+
+### Wireguard
+
+Installing wireguard is as easy as:
+```sh
+pkg install wireguard
+```
+
+The private and public keys for a host can be generated with the following commands:
+```sh
+PRIVATE_KEY=`wg genkey`
+PUBLIC_KEY=`printf $PRIVATE_KEY|wg pubkey`
+echo private_key: $PRIVATE_KEY
+echo public_key: $PUBLIC_KEY
+```
+
+Here is a configuration example of my `/usr/local/etc/wireguard/wg0.conf` that creates a tunnel listening on udp port 342 and has one remote peer:
+```cfg
+[Interface]
+PrivateKey = MzrfXLmSfTaCpkJWKwNlCSD20eDq7fo18aJ3Dl1D0gA=
+ListenPort = 342
+Address = 10.1.2.5/24
+
+[Peer]
+PublicKey = R4A01RXXqRJSY9TiKQrZGR85HsFNSXxhRKKEu/bEdTQ=
+Endpoint = 168.119.114.183:342
+AllowedIPs = 10.1.2.2/32
+PersistentKeepalive = 60
+```
+
+To implement this example you will need to generate two sets of keys. The configuration for the first server will feature the first server's private key in the `[Interface]` section and the second server's public key in the `[Peer]` section, and vice versa for the configuration of the second server.
+
+The `PersistentKeepalive` and `Endpoint` entries are only for the home server, the internet facing vps should not have those.
+
+To activate the interface configuration, use :
+```sh
+service wireguard enable
+echo 'wireguard_interfaces="wg0"' >> /etc/rc.conf
+service wireguard start
+```
+
+### pf firewall
+
+Here is the `/etc/pf.conf` of my home server. It differs from the one on the internet facing vps because it needs to be reachable from my private network:
+```cfg
+scrub in all
+
+table <jails> persist
+table <myself> const { self }
+table <private> const { 10/8, 172.16/12, 192.168/16, fd00::/8 fe80::/10 }
+table <internet> const { 0.0.0.0/0, !10/8, !172.16/12, !192.168/16, ::/0, fe80::/10, !fd00::/8 }
+
+##### Basic rules #####
+nat pass on egress from <jails> to <internet> -> (egress:0)
+rdr-anchor "rdr/*"
+set skip on lo
+block return log
+
+##### This firewall #####
+block drop in on egress
+pass inet proto icmp all icmp-type unreach code needfrag # MTU path discovery
+pass inet proto icmp all icmp-type { echoreq, unreach } # echo reply
+pass inet6 proto icmp6 all
+
+pass in on egress proto tcp from <private> to <myself> port { ssh, http, https, smtp, smtps, submission }
+pass out from <myself> to any
+
+##### VPNs #####
+pass in on egress proto udp from <internet> to <myself> port 342
+pass in on wg0 from <private> to <myself>
+pass out on wg0 from <myself> to <private>
+```
+
+### Linux subsystem
+
+```sh
+service linux enable
+service linux start
+```
+
+## Migrating the jail
+
+Migrating the jail was relatively easy. First I needed to stop the jail and unmount the linux filesystems:
+```sh
+service jail stop factorio
+umount /jails/factorio/proc
+umount /jails/factorio/sys
+```
+
+Then rsync did the trick *(here on the home server) with:
+```sh
+mkdir /jails
+rsync -SHaX factorio.adyxax.org:/jails/factorio /jails/
+```
+
+I migrated the linux fstab entries from one server to the other:
+```cfg
+linprocfs /jails/factorio/proc linprocfs rw,late 0 0
+linsysfs /jails/factorio/sys linsysfs rw,late 0 0
+```
+
+I mount these filesystems on the home server:
+```sh
+mount /jails/factorio/proc
+mount /jails/factorio/sys
+```
+
+I migrated the `/etc/jail.conf.d/factorio.conf` configuration. I needed to adjust the pf prestart rules to include `wg0` in addition to `egress` interface (I keep the egress interface to be able to connect locally too):
+```cfg
+factorio {
+ host.hostname = "factorio";
+ path = /jails/$name;
+ ip4.addr = 127.0.1.1/32;
+ ip6 = "new";
+ ip6.addr = fc00::1/128;
+ exec.system_user = "root";
+ exec.jail_user = "root";
+ exec.clean;
+ exec.prestart = "ifconfig lo1 alias ${ip4.addr}";
+ exec.prestart += "ifconfig lo1 inet6 ${ip6.addr}";
+ exec.prestart += "/sbin/pfctl -t jails -T add ${ip4.addr}";
+ exec.prestart += "/sbin/pfctl -t jails -T add ${ip6.addr}";
+ exec.prestart += "echo \"rdr pass on { egress, wg0 } inet proto udp from any to port 34197 -> ${ip4.addr}\n rdr pass on { egress, wg0 } inet6 proto udp from any to port 34197 -> ${ip6.addr}\" | pfctl -a rdr/jail-$name -f -";
+ exec.poststop = "/sbin/pfctl -t jails -T del ${ip4.addr}";
+ exec.poststop += "/sbin/pfctl -t jails -T del ${ip6.addr}";
+ exec.poststop += "pfctl -a rdr/jail-$name -F nat";
+ exec.poststop += "ifconfig lo1 inet ${ip4.addr} -alias";
+ exec.poststop += "ifconfig lo1 inet6 ${ip6.addr} -alias";
+ exec.start = "/bin/su - factorio -c 'factorio/bin/x64/factorio --start-server factorio/saves/meganoobase.zip' &";
+ exec.stop = "pkill factorio ; sleep 15";
+ mount.devfs;
+}
+```
+
+Here are the necessary bits for `/etc/rc.conf`:
+```sh
+echo 'jail_enable="YES"
+jail_list="factorio"
+service jail start factorio
+```
+
+## pf forwarding rules on the internet facing vps
+
+There are two nat rules necessary:
+```cfg
+rdr pass on egress inet proto udp from <internet> to <myself> port 34197 -> 10.1.2.2 # factorio TODO ipv6
+nat pass on wg0 inet proto udp from <internet> to 10.1.2.2 port 34197 -> (wg0:0)
+```
+
+The first rule rewrites the destination IP of the incoming internet traffic to the wireguard IP of the home server. The second rule rewrites their source IP to the wireguard IP of the internet facing vps.
+
+Since we a routing packets, make sure it is enabled in your `/etc/sysctl.conf`:
+```sh
+sysctl net.inet.ip.forwarding=1
+echo 'net.inet.ip.forwarding=1 >> /etc/sysctl.conf'
+```
+
+Here is the whole pf configuration as an reference:
+```cfg
+scrub in all
+
+table <jails> persist
+table <myself> const { self }
+table <private> const { 10/8, 172.16/12, 192.168/16, fd00::/8 fe80::/10 }
+table <internet> const { 0.0.0.0/0, !10/8, !172.16/12, !192.168/16, ::/0, fe80::/10, !fd00::/8 }
+
+##### Basic rules #####
+nat pass on egress from <jails> to <internet> -> (egress:0)
+rdr-anchor "rdr/*"
+rdr pass on egress inet proto udp from <internet> to <myself> port 34197 -> 10.1.2.2 # factorio TODO ipv6
+nat pass on wg0 inet proto udp from <internet> to 10.1.2.2 port 34197 -> (wg0:0)
+set skip on lo
+block return log
+
+##### This firewall #####
+block drop in on egress
+pass inet proto icmp all icmp-type unreach code needfrag # MTU path discovery
+pass inet proto icmp all icmp-type { echoreq, unreach } # echo reply
+pass inet6 proto icmp6 all
+
+pass in on egress proto tcp from <internet> to <myself> port { ssh, http, https, smtp, smtps, submission, 1337 }
+pass out from <myself> to any
+
+##### VPNs #####
+pass in on egress proto udp from <internet> to <myself> port 342
+pass in on wg0 from <private> to <myself>
+pass out on wg0 from <myself> to <private>
+```
+
+## Conclusion
+
+I love FreeBSD and I love wireguard: it all works perfectly. This blog post is rather long because I got caught up detailing everything, but if something is unclear or if some piece seems missing do not hesitate to [contact me]({{< ref "about-me.md" >}}#how-to-get-in-touch).
diff --git a/static/static/factorio-wireguard.drawio.svg b/static/static/factorio-wireguard.drawio.svg
new file mode 100644
index 0000000..9432b62
--- /dev/null
+++ b/static/static/factorio-wireguard.drawio.svg
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="409px" height="295px" viewBox="-0.5 -0.5 409 295" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2023-01-07T22:47:10.934Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;PowjzcyRRVuM5-xDcO5B&quot; version=&quot;15.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;ZPRT6O2qIPaLcVj74FYs&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 195 183 L 195 123" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 180px; margin-left: 197px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; "><div>Public IP<br /></div></div></div></div></foreignObject><text x="197" y="180" fill="#839496" font-family="Helvetica" font-size="11px">Public IP&#xa;</text></switch></g><path d="M 225 193 L 385 193" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 190px; margin-left: 335px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; "><div>Home network: 192.168.1.0/24</div></div></div></div></foreignObject><text x="335" y="190" fill="#839496" font-family="Helvetica" font-size="11px" text-anchor="middle">Home netwo...</text></switch></g><path d="M 385 193 L 385 233" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 230px; margin-left: 387px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; "><div>.7</div></div></div></div></foreignObject><text x="387" y="230" fill="#839496" font-family="Helvetica" font-size="11px">.7</text></switch></g><path d="M 295 193 L 295 233" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 230px; margin-left: 297px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; ">.3</div></div></div></foreignObject><text x="297" y="230" fill="#839496" font-family="Helvetica" font-size="11px">.3</text></switch></g><rect x="365" y="233" width="12.86" height="25.71" rx="0.86" ry="0.86" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><path d="M 365 237.29 L 377.86 237.29 M 365 245.86 L 377.86 245.86" fill="none" stroke="#6881b3" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><rect x="373.57" y="235.14" width="34.29" height="19.29" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><rect x="386.43" y="254.43" width="8.57" height="4.29" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><path d="M 380 258.29 L 401.43 258.29 L 405.72 263 L 375.71 263 Z" fill="#cccccc" stroke="#6881b3" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 386 261.93 L 393.72 261.93 M 380.43 260.64 L 397.14 260.64 M 381.29 259.36 L 396.72 259.36 M 398 259.36 L 401 259.36 M 398.86 260.64 L 401.86 260.64 M 399.72 261.93 L 402.72 261.93" fill="none" stroke="#6881b3" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><rect x="374.86" y="236.43" width="31.29" height="16.71" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="367.14" cy="248" rx="0.8572" ry="0.8571428571428571" fill="#ffffff" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 270px; margin-left: 386px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; ">Hero</div></div></div></foreignObject><text x="386" y="282" fill="#839496" font-family="Helvetica" font-size="12px" text-anchor="middle">Hero</text></switch></g><rect x="275" y="265.04" width="34.95" height="5.65" rx="0.75" ry="0.75" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><rect x="275" y="258.45" width="34.95" height="5.65" rx="0.75" ry="0.75" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><rect x="275" y="251.85" width="34.95" height="5.65" rx="0.75" ry="0.75" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><rect x="275" y="245.25" width="34.95" height="5.65" rx="0.75" ry="0.75" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><rect x="275" y="238.65" width="34.95" height="5.65" rx="0.75" ry="0.75" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><path d="M 276.55 237.9 L 284.71 233 L 300.24 233 L 308.4 237.9 Z" fill="#cccccc" stroke="#6881b3" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="306.84" cy="267.87" rx="1.5533980582524272" ry="1.5078691923475638" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="306.72" cy="261.27" rx="1.5533980582524272" ry="1.5078691923475638" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="306.84" cy="254.68" rx="1.5533980582524272" ry="1.5078691923475638" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="306.84" cy="248.08" rx="1.5533980582524272" ry="1.5078691923475638" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="306.84" cy="241.48" rx="1.5533980582524272" ry="1.5078691923475638" fill="#ffffff" stroke="none" pointer-events="all"/><path d="M 276.94 269.94 L 278.88 265.8 L 280.83 265.8 L 278.88 269.94 Z M 280.83 269.94 L 282.77 265.8 L 284.71 265.8 L 282.77 269.94 Z M 284.71 269.94 L 286.65 265.8 L 288.59 265.8 L 286.65 269.94 Z M 288.59 269.94 L 290.53 265.8 L 292.48 265.8 L 290.53 269.94 Z M 292.48 269.94 L 294.42 265.8 L 296.36 265.8 L 294.42 269.94 Z M 296.36 269.94 L 298.3 265.8 L 300.24 265.8 L 298.3 269.94 Z M 276.94 263.35 L 278.88 259.2 L 280.83 259.2 L 278.88 263.35 Z M 280.83 263.35 L 282.77 259.2 L 284.71 259.2 L 282.77 263.35 Z M 284.71 263.35 L 286.65 259.2 L 288.59 259.2 L 286.65 263.35 Z M 288.59 263.35 L 290.53 259.2 L 292.48 259.2 L 290.53 263.35 Z M 292.48 263.35 L 294.42 259.2 L 296.36 259.2 L 294.42 263.35 Z M 296.36 263.35 L 298.3 259.2 L 300.24 259.2 L 298.3 263.35 Z M 276.94 256.75 L 278.88 252.6 L 280.83 252.6 L 278.88 256.75 Z M 280.83 256.75 L 282.77 252.6 L 284.71 252.6 L 282.77 256.75 Z M 284.71 256.75 L 286.46 252.6 L 288.4 252.6 L 286.46 256.75 Z M 288.59 256.75 L 290.53 252.6 L 292.48 252.6 L 290.53 256.75 Z M 292.48 256.75 L 294.42 252.6 L 296.36 252.6 L 294.42 256.75 Z M 296.36 256.75 L 298.3 252.6 L 300.24 252.6 L 298.3 256.75 Z M 276.94 250.15 L 278.88 246.01 L 280.83 246.01 L 278.88 250.15 Z M 280.83 250.15 L 282.77 246.01 L 284.71 246.01 L 282.77 250.15 Z M 284.71 250.15 L 286.65 246.01 L 288.59 246.01 L 286.65 250.15 Z M 288.59 250.15 L 290.53 246.01 L 292.48 246.01 L 290.53 250.15 Z M 292.48 250.15 L 294.42 246.01 L 296.36 246.01 L 294.42 250.15 Z M 296.36 250.15 L 298.3 246.01 L 300.24 246.01 L 298.3 250.15 Z M 276.94 243.56 L 278.88 239.41 L 280.83 239.41 L 278.88 243.56 Z M 280.83 243.56 L 282.77 239.41 L 284.71 239.41 L 282.77 243.56 Z M 284.71 243.56 L 286.65 239.41 L 288.59 239.41 L 286.65 243.56 Z M 288.59 243.56 L 290.53 239.41 L 292.48 239.41 L 290.53 243.56 Z M 292.48 243.56 L 294.42 239.41 L 296.36 239.41 L 294.42 243.56 Z M 296.36 243.56 L 298.3 239.41 L 300.24 239.41 L 298.3 243.56 Z" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="275" y="233" width="0" height="0" fill="none" stroke="#6881b3" pointer-events="all"/><path d="M 300.63 268.62 C 300.63 267.77 303.85 267.07 307.82 267.07 C 311.78 267.07 315 267.77 315 268.62 L 315 271.45 C 315 272.31 311.78 273 307.82 273 C 303.85 273 300.63 272.31 300.63 271.45 Z" fill="#cccccc" stroke="#6881b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 300.63 265.04 C 300.63 264.19 303.85 263.49 307.82 263.49 C 311.78 263.49 315 264.19 315 265.04 L 315 267.87 C 315 268.73 311.78 269.42 307.82 269.42 C 303.85 269.42 300.63 268.73 300.63 267.87 Z" fill="#cccccc" stroke="#6881b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 300.63 261.65 C 300.63 260.79 303.85 260.1 307.82 260.1 C 311.78 260.1 315 260.79 315 261.65 L 315 264.29 C 315 265.14 311.78 265.84 307.82 265.84 C 303.85 265.84 300.63 265.14 300.63 264.29 Z" fill="#cccccc" stroke="#6881b3" stroke-miterlimit="10" pointer-events="all"/><path d="M 300.63 268.62 C 300.63 269.48 303.85 270.17 307.82 270.17 C 311.78 270.17 315 269.48 315 268.62 M 300.63 265.04 C 300.63 265.9 303.85 266.59 307.82 266.59 C 311.78 266.59 315 265.9 315 265.04 M 300.63 261.65 C 300.63 262.51 303.85 263.2 307.82 263.2 C 311.78 263.2 315 262.51 315 261.65" fill="none" stroke="#6881b3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 280px; margin-left: 295px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; ">Phoenix</div></div></div></foreignObject><text x="295" y="292" fill="#839496" font-family="Helvetica" font-size="12px" text-anchor="middle">Phoenix</text></switch></g><rect x="161.67" y="183" width="66.67" height="17.24" rx="3.45" ry="3.45" fill="#cccccc" stroke="#6881b3" stroke-width="1.33" pointer-events="all"/><rect x="168.34" y="200.24" width="53.34" height="2.76" fill="#cccccc" stroke="#6881b3" stroke-width="1.33" pointer-events="all"/><path d="M 163.67 187.83 L 167.67 187.83 L 167.67 189.9 L 166.34 189.9 L 166.34 190.59 L 165 190.59 L 165 189.9 L 163.67 189.9 Z M 169.34 187.83 L 173.34 187.83 L 173.34 189.9 L 172 189.9 L 172 190.59 L 170.67 190.59 L 170.67 189.9 L 169.34 189.9 Z M 175 187.83 L 179 187.83 L 179 189.9 L 177.67 189.9 L 177.67 190.59 L 176.34 190.59 L 176.34 189.9 L 175 189.9 Z M 180.67 187.83 L 184.67 187.83 L 184.67 189.9 L 183.34 189.9 L 183.34 190.59 L 182 190.59 L 182 189.9 L 180.67 189.9 Z M 186.34 187.83 L 190.34 187.83 L 190.34 189.9 L 189 189.9 L 189 190.59 L 187.67 190.59 L 187.67 189.9 L 186.34 189.9 Z M 192 187.83 L 196.01 187.83 L 196.01 189.9 L 194.67 189.9 L 194.67 190.59 L 193.34 190.59 L 193.34 189.9 L 192 189.9 Z M 197.67 187.83 L 201.67 187.83 L 201.67 189.9 L 200.34 189.9 L 200.34 190.59 L 199.01 190.59 L 199.01 189.9 L 197.67 189.9 Z M 203.34 187.83 L 207.34 187.83 L 207.34 189.9 L 206.01 189.9 L 206.01 190.59 L 204.67 190.59 L 204.67 189.9 L 203.34 189.9 Z" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="220.34" cy="191.62" rx="5.333600000000001" ry="5.517241379310345" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="211.67" cy="186.45" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="211.67" cy="196.79" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="211.67" cy="191.62" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="205.34" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="199.67" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="194" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="188.34" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="182.67" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="177" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="171.34" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="165.67" cy="194.72" rx="1.3334000000000001" ry="1.3793103448275863" fill="#ffffff" stroke="none" pointer-events="all"/><path d="M 220.34 187.83 L 220.34 195.41 M 216.01 191.62 L 218.67 191.62 M 222.01 191.62 L 224.67 191.62 M 219.01 189.21 L 220.34 187.83 L 221.67 189.21 M 219.01 194.03 L 220.34 195.41 L 221.67 194.03 M 217.34 190.24 L 218.67 191.62 L 217.34 193 M 223.34 190.24 L 222.01 191.62 L 223.34 193" fill="none" stroke="#6881b3" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 210px; margin-left: 195px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; ">FAI's router</div></div></div></foreignObject><text x="195" y="222" fill="#839496" font-family="Helvetica" font-size="12px" text-anchor="middle">FAI's router</text></switch></g><path d="M 195 33 L 195 53 L 195.12 149" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 40px; margin-left: 193px;"><div style="box-sizing: border-box; font-size: 0; text-align: right; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">Public IP</div></div></div></foreignObject><text x="193" y="51" fill="#839496" font-family="Helvetica" font-size="11px" text-anchor="end">Public IP</text></switch></g><rect x="228.34" y="193" width="20" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 210px; margin-left: 230px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; ">.1</div></div></div></foreignObject><text x="230" y="210" fill="#839496" font-family="Helvetica" font-size="12px">.1</text></switch></g><rect x="165" y="13" width="60" height="20" fill="#ffffff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 23px; margin-left: 166px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">VPS</div></div></div></foreignObject><text x="195" y="27" fill="#839496" font-family="Helvetica" font-size="12px" text-anchor="middle">VPS</text></switch></g><path d="M 375 223 Q 375 203 355 198 Q 335 193 320 198 Q 305 203 305 216.63" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 305 221.88 L 301.5 214.88 L 305 216.63 L 308.5 214.88 Z" fill="#82b366" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 216px; margin-left: 339px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #82B366; line-height: 1.2; pointer-events: all; white-space: nowrap; "><div><font style="font-size: 8px">Direct connections</font></div><div><font style="font-size: 8px">are possible</font></div></div></div></div></foreignObject><text x="339" y="219" fill="#82B366" font-family="Helvetica" font-size="11px" text-anchor="middle">Direct connections...</text></switch></g><path d="M 274.5 218 L 274.5 228 L 250 228 Q 240 228 240 218 L 240 28 L 225.5 28 L 225.5 18 L 240 18 Q 250 18 250 28 L 250 218 Z" fill="#ffe6cc" stroke="#d79b00" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 69px; margin-left: 295px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #D79B00; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "><div>Wireguard tunnel</div><div align="left">10.1.2.0/24<br /></div></div></div></div></foreignObject><text x="295" y="72" fill="#D79B00" font-family="Helvetica" font-size="11px" text-anchor="middle">Wireguard tunnel...</text></switch></g><path d="M 165 93 C 141 93 135 113 154.2 117 C 135 125.8 156.6 145 172.2 137 C 183 153 219 153 231 137 C 255 137 255 121 240 113 C 255 97 231 81 210 89 C 195 77 171 77 165 93 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 113px; margin-left: 136px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Internet</div></div></div></foreignObject><text x="195" y="117" fill="#839496" font-family="Helvetica" font-size="12px" text-anchor="middle">Internet</text></switch></g><rect x="275" y="213" width="20" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 223px; margin-left: 285px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #D79B00; line-height: 1.2; pointer-events: all; white-space: nowrap; ">.2</div></div></div></foreignObject><text x="285" y="227" fill="#D79B00" font-family="Helvetica" font-size="12px" text-anchor="middle">.2</text></switch></g><rect x="225" y="0" width="20" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 17px; margin-left: 235px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #D79B00; line-height: 1.2; pointer-events: all; white-space: nowrap; ">.5</div></div></div></foreignObject><text x="235" y="17" fill="#D79B00" font-family="Helvetica" font-size="12px" text-anchor="middle">.5</text></switch></g><rect x="5" y="98" width="12.86" height="25.71" rx="0.86" ry="0.86" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><path d="M 5 102.29 L 17.86 102.29 M 5 110.86 L 17.86 110.86" fill="none" stroke="#6881b3" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><rect x="13.57" y="100.14" width="34.29" height="19.29" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><rect x="26.43" y="119.43" width="8.57" height="4.29" fill="#cccccc" stroke="#6881b3" pointer-events="all"/><path d="M 20 123.29 L 41.43 123.29 L 45.72 128 L 15.72 128 Z" fill="#cccccc" stroke="#6881b3" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 26 126.93 L 33.72 126.93 M 20.43 125.64 L 37.14 125.64 M 21.29 124.36 L 36.72 124.36 M 38 124.36 L 41 124.36 M 38.86 125.64 L 41.86 125.64 M 39.72 126.93 L 42.72 126.93" fill="none" stroke="#6881b3" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/><rect x="14.86" y="101.43" width="31.29" height="16.71" fill="#ffffff" stroke="none" pointer-events="all"/><ellipse cx="7.14" cy="113" rx="0.8572" ry="0.8571428571428571" fill="#ffffff" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 135px; margin-left: 26px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #839496; line-height: 1.2; pointer-events: all; white-space: nowrap; ">Friend's pc</div></div></div></foreignObject><text x="26" y="147" fill="#839496" font-family="Helvetica" font-size="12px" text-anchor="middle">Friend'...</text></switch></g><path d="M 55 113 Q 185 113 190 73 Q 195 33 210 28 Q 225 23 240 33 Q 255 43 245 133 Q 235 223 255 223 Q 275 223 277.91 227.4" fill="none" stroke="#b85450" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 281.21 232.41 L 273.47 227.94 L 277.91 227.4 L 280.14 223.53 Z" fill="#b85450" stroke="#b85450" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 73px; margin-left: 105px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #B85450; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "><div>Connections to</div><div>the public facing vps</div><div>go through wireguard<br /></div></div></div></div></foreignObject><text x="105" y="76" fill="#B85450" font-family="Helvetica" font-size="11px" text-anchor="middle">Connections to...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file