94 lines
4.1 KiB
Plaintext
94 lines
4.1 KiB
Plaintext
variant: flatcar
|
|
version: 1.0.0
|
|
|
|
# Headscale (Tailscale) node: advertises 192.168.7.0/24 as a subnet route and
|
|
# offers itself as an exit node.
|
|
#
|
|
# Registered as an EPHEMERAL node: tailscaled runs with in-memory state, so the
|
|
# VM re-authenticates on every boot and headscale drops the node shortly after
|
|
# it goes offline. That requires the preauth key to be both --ephemeral and
|
|
# --reusable, otherwise the second boot fails to register.
|
|
#
|
|
# HEADSCALE_AUTHKEY is templated in from Infisical (see secrets.tmpl) by
|
|
# main.tf, not stored here. It still ends up in plaintext in the rendered
|
|
# Ignition snippet on the node's storage -- see the caveat in flatcar-todo.md.
|
|
|
|
systemd:
|
|
units:
|
|
- name: tailscaled.service
|
|
enabled: true
|
|
contents: |
|
|
[Unit]
|
|
Description=Tailscale node (headscale subnet router + exit node)
|
|
After=docker.service network-online.target versions-fetch.service
|
|
Requires=docker.service
|
|
Wants=network-online.target versions-fetch.service
|
|
[Service]
|
|
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
|
EnvironmentFile=/etc/versions.env
|
|
TimeoutStartSec=0
|
|
# None of these are loaded by default on a stock Flatcar boot, and the
|
|
# container cannot load them itself: it has NET_ADMIN (enough to write
|
|
# iptables rules) but not SYS_MODULE, and the image ships no
|
|
# /lib/modules, so tailscaled's own modprobe fallback fails with
|
|
# "the filter table does not exist". Loading them here works because
|
|
# the container shares the host's network namespace (--network host),
|
|
# so it sees tables created on the host. Without the nat table in
|
|
# particular there is no ts-postrouting chain, which means no SNAT:
|
|
# the exit node cannot work at all and subnet-routed replies are sent
|
|
# back to tailnet addresses the LAN has no route for.
|
|
ExecStartPre=-/usr/sbin/modprobe -a tun iptable_filter iptable_nat ip6table_filter ip6table_nat nf_tables xt_mark
|
|
# Recommended by Tailscale for subnet routers and exit nodes: without
|
|
# this, UDP throughput through the node is roughly halved.
|
|
ExecStartPre=-/usr/bin/bash -c 'ethtool -K $(ip route show 0.0.0.0/0 | cut -d" " -f5) rx-udp-gro-forwarding on rx-gro-list off'
|
|
ExecStartPre=-/usr/bin/docker rm --force tailscaled
|
|
ExecStart=/usr/bin/docker run --name tailscaled \
|
|
--network host --cap-add NET_ADMIN --cap-add NET_RAW \
|
|
--device /dev/net/tun \
|
|
-e TS_AUTHKEY=${headscale_authkey} \
|
|
-e TS_HOSTNAME=oswl-connector \
|
|
-e TS_ROUTES=192.168.7.0/24 \
|
|
-e TS_ACCEPT_DNS=false \
|
|
-e "TS_EXTRA_ARGS=--login-server=https://hs.atlashorizon.net --advertise-exit-node" \
|
|
-e TS_USERSPACE=false \
|
|
$${TAILSCALE_IMAGE}
|
|
ExecStop=/usr/bin/docker stop tailscaled
|
|
Restart=always
|
|
RestartSec=5s
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
- name: dozzle-agent.service
|
|
enabled: true
|
|
contents: |
|
|
[Unit]
|
|
Description=Dozzle Agent
|
|
After=docker.service versions-fetch.service
|
|
Wants=versions-fetch.service
|
|
Requires=docker.service
|
|
[Service]
|
|
# Image tag comes from versions.env; see butane/versions-sync.yaml.
|
|
EnvironmentFile=/etc/versions.env
|
|
TimeoutStartSec=0
|
|
ExecStartPre=-/usr/bin/docker rm --force dozzle-agent
|
|
ExecStart=/usr/bin/docker run --name dozzle-agent \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
-p 7007:7007 \
|
|
$${DOZZLE_IMAGE} agent
|
|
ExecStop=/usr/bin/docker stop dozzle-agent
|
|
Restart=always
|
|
RestartSec=5s
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
|
|
storage:
|
|
files:
|
|
# Forwarding must be on for the subnet route and the exit node to pass
|
|
# traffic at all; the container shares the host netns (--network host), so
|
|
# this has to be set on the host, not inside it.
|
|
- path: /etc/sysctl.d/99-tailscale.conf
|
|
mode: 0644
|
|
contents:
|
|
inline: |
|
|
net.ipv4.ip_forward = 1
|
|
net.ipv6.conf.all.forwarding = 1
|