herdr-core machine add kept failing with "core did not start within 5 s". Cause: hc puts its core socket under XDG_RUNTIME_DIR, which on Unraid is /run/user/0 — created and destroyed per login session by elogind. The socket vanished with the session that started the core, so later clients found an empty directory. The core itself kept running on an unlinked socket, and core.log stayed empty because the failure is client side. Fixed entirely on the Mac with a --via transport that pins XDG_RUNTIME_DIR=/var/run/herdr-rt. Nothing on the server was changed. The transport uses key auth on 192.168.10.20:422, not Tailscale SSH, since --via needs something that asks nothing and the default tailnet ACL demands periodic browser re-auth. Also records the reboot caveat (/ is RAM, so the remote hc binary is lost) with a go-script fix written up but not applied, and corrects the 192.168.31.0/24 note: that shim was created for a Pi-hole that AdGuard replaced. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
11 KiB
MikroTik Tailscale Container Setup
Last Updated: 2026-02-06
Overview
Tailscale VPN running as a container on MikroTik hAP ax³, providing remote access to the home network via the Tailscale mesh network.
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ MikroTik hAP ax³ (192.168.10.1) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Container Network (172.17.0.0/24) │ │
│ │ │ │
│ │ ┌─────────────────────┐ ┌─────────────────────────┐ │ │
│ │ │ AdGuard Home │ │ Tailscale │ │ │
│ │ │ 172.17.0.2 │ │ 172.17.0.3 │ │ │
│ │ │ veth-adguard │ │ veth-tailscale │ │ │
│ │ └─────────────────────┘ └─────────────────────────┘ │ │
│ │ │ │ │ │
│ │ └───────────┬───────────────┘ │ │
│ │ │ │ │
│ │ Gateway: 172.17.0.1 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ NAT Masquerade │
│ │ │
│ WAN (ether1) │
└──────────────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────┐
│ Tailscale Network │
│ 100.x.x.x mesh │
│ │
│ Home Router IP: │
│ 100.74.219.35 │
└─────────────────────┘
Container Details
| Setting | Value |
|---|---|
| Image | tailscale/tailscale:latest |
| Interface | veth-tailscale |
| Container IP | 172.17.0.3/24 |
| Gateway | 172.17.0.1 |
| Tailscale IP | 100.74.219.35 |
| Root dir | usb1/tailscale/root |
| State mount | usb1/tailscale → /var/lib/tailscale |
| DNS | 8.8.8.8 |
| Start on boot | Yes |
| Networking mode | Userspace (TS_USERSPACE=true) |
Environment Variables
| Variable | Value | Purpose |
|---|---|---|
| TS_AUTHKEY | tskey-auth-... | One-time auth key (used during setup) |
| TS_STATE_DIR | /var/lib/tailscale | Persistent state directory |
| TS_USERSPACE | true | Required for MikroTik containers (no /dev/net/tun) |
Network Configuration
veth Interface
/interface veth add address=172.17.0.3/24 gateway=172.17.0.1 name=veth-tailscale
Gateway IP on Interface
/ip address add address=172.17.0.1/24 interface=veth-tailscale comment="Tailscale container gateway"
NAT Masquerade for Internet Access
/ip firewall nat add chain=srcnat action=masquerade src-address=172.17.0.0/24 out-interface-list=WAN comment="Container network NAT"
Firewall Forward Rules
/ip firewall filter add chain=forward action=accept dst-address=172.17.0.0/24 comment="[Container] Forward to container network"
/ip firewall filter add chain=forward action=accept src-address=172.17.0.0/24 comment="[Container] Forward from container network"
Container Setup Commands
Create Mounts
/container mounts add list=ts-state src=usb1/tailscale dst=/var/lib/tailscale
Create Environment Variables
/container envs add list=ts-env key=TS_STATE_DIR value=/var/lib/tailscale
/container envs add list=ts-env key=TS_USERSPACE value=true
/container envs add list=ts-env key=TS_AUTHKEY value=<your-auth-key>
Create Container
/container add remote-image=tailscale/tailscale:latest interface=veth-tailscale \
root-dir=usb1/tailscale/root mountlists=ts-state envlists=ts-env \
dns=8.8.8.8 start-on-boot=yes logging=yes
Management
Check Container Status
/container print
View Logs
/log print where topics~"container" and message~"tailscale"
Start/Stop Container
/container start [find name~"tailscale"]
/container stop [find name~"tailscale"]
Troubleshooting
Container Won't Start (Exit Status 1)
Cause: Missing /dev/net/tun device (default for Tailscale)
Solution: Enable userspace networking mode:
/container envs add list=ts-env key=TS_USERSPACE value=true
Can't Reach Internet from Container
Cause: Missing NAT masquerade or gateway IP
Solution:
- Verify gateway IP on veth interface:
/ip address print where interface=veth-tailscale
- Verify NAT masquerade rule:
/ip firewall nat print where src-address=172.17.0.0/24
Container Not Connecting to Tailscale
- Check DNS resolution works (logs should show no timeout)
- Verify auth key is valid and not expired
- Check firewall isn't blocking outbound HTTPS
Tailscale Network Devices
| Tailscale IP | Device | Status |
|---|---|---|
| 100.74.219.35 | MikroTik hAP ax³ (container) | Online |
| 100.100.208.69 | xtrm-unraid (Unraid plugin, offers exit node) | Online |
| 100.100.208.70 | xtrm-unraid (old node, deleted 2026-11-03) | Removed |
| 100.112.103.7 | hapax3 (old native install) | Offline |
| 100.75.93.123 | mikrotik-tailscale (previous container) | Offline |
Important Notes
-
Userspace Networking Required: MikroTik containers don't have /dev/net/tun access, so TS_USERSPACE=true is mandatory
-
Auth Key: After initial authentication, the key is no longer needed - state is persisted in the mount
-
Container Network: Both AdGuard and Tailscale share the 172.17.0.0/24 network but have separate veth interfaces
-
Accept Routes: If subnet routing is needed, add TS_EXTRA_ARGS="--accept-routes" to environment
Unraid Tailscale Plugin Node — 2026-11-03
The Unraid server runs its own Tailscale node via the Tailscale plugin (not a container), separate from the MikroTik container documented above. It had been logged out since roughly May 2026 and was re-enrolled on 2026-11-03.
| Item | Value |
|---|---|
| Tailscale IP | 100.100.208.69 |
| MagicDNS name | xtrm-unraid.tailf789e1.ts.net |
| Daemon | /usr/local/sbin/tailscaled 1.96.2, -tun tailscale1 |
| State dir | /boot/config/plugins/tailscale/state (survives reboot) |
| Previous IP | 100.100.208.70 — stale node deleted, so a new IP was issued |
Prefs set
| Pref | Value | Reason |
|---|---|---|
--advertise-routes |
none | The old 192.168.31.0/24 advertisement was dropped. That subnet is only the macvlan shim created in /boot/config/go for a Pi-hole at 192.168.31.4. Pi-hole was replaced by AdGuard: there is no such container any more and the address is silent, so nothing reachable lives there. |
| LAN subnet routing | not advertised | The MikroTik container is primary for 192.168.10.0/24, .20, .25, .30. A second advertiser for a subnet Unraid itself sits on would create a routing conflict. |
--advertise-exit-node |
on | Redundant with the hAP today, kept as a fallback on the 24/7 box. Approved in the admin console 2026-11-03 — shows as offers exit node and appears in tailscale exit-node list. |
--accept-routes |
false | Critical. Unraid is on 192.168.10.0/24; accepting the hAP's route for its own subnet would loop. This is why tailscale status reports the health warning "Some peers are advertising routes but --accept-routes is false" — expected here, not a fault. |
--accept-dns |
false | Keeps local AdGuard resolution intact (Unraid AdGuard is config master). |
--ssh |
on | Tailscale SSH. Needed — see the sshd caveat below. |
SSH over Tailscale — the sshd caveat
/etc/ssh/sshd_config on Unraid binds explicitly and has no wildcard:
Port 422
ListenAddress 192.168.10.20 # br0
ListenAddress 192.168.31.250 # br0-shim
So sshd does not listen on 100.100.208.69. Port 422 on the Tailscale IP is
closed and stays closed unless a ListenAddress is added — which needs a go
script, because Unraid regenerates this file per interface at every boot.
Access on the Tailscale IP is served by Tailscale SSH on port 22, handled by
tailscaled itself and authenticated by tailnet identity rather than by an SSH
key:
# direct, independent of the MikroTik subnet router
ssh root@100.100.208.69
ssh root@xtrm-unraid.tailf789e1.ts.net
# port forward — verified 2026-11-03 (Unraid web UI returned HTTP 302)
ssh -N -L 18089:127.0.0.1:80 root@100.100.208.69
The default tailnet ACL uses action: "check", so the first connection in each
period opens a browser re-auth prompt. Fine interactively, but it will stall an
unattended tunnel; switching that rule to accept for autogroup:self in the
admin console removes the prompt.
The other path — via the MikroTik subnet router
Independent of the Unraid node and still working:
ssh -i ~/.ssh/id_ed25519_unraid -p 422 -N -L 18088:127.0.0.1:80 root@192.168.10.20
Forwarding works here only because Unraid's stock sshd config denies it globally and re-enables it for root alone:
AllowTcpForwarding no # limetech - disallow forwarding but see below
...
Match Group root
AllowTcpForwarding yes # limetech - permit only root SSH tunneling
Any non-root account added later will not be able to open tunnels.
Exit node
Approved 2026-11-03. The tailnet now has two exit nodes:
| IP | Node |
|---|---|
100.74.219.35 |
mikrotik-tailscale (primary) |
100.100.208.69 |
xtrm-unraid (fallback, 24/7 box) |
Select one with tailscale set --exit-node=xtrm-unraid. Not exercised in anger
yet — note that without --exit-node-allow-lan-access an exit node cuts the
client's own LAN access, which will break an SSH session that is itself routed
over Tailscale.