From 023b3cd4a8db3b96c6637d764f679af4c8c34cda Mon Sep 17 00:00:00 2001 From: Jack Spiering <46534141+jackspiering@users.noreply.github.com> Date: Sat, 10 Oct 2026 02:33:53 +0200 Subject: [PATCH 1/2] Docs: fix the port 53 and OpenPLi guides --- documentation/free-up-port-53.md | 30 ++++++++++++++++++++++++++---- documentation/standard-setup.md | 8 +++++--- documentation/tailscale-on-arm.md | 25 +++++++++++++------------ 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/documentation/free-up-port-53.md b/documentation/free-up-port-53.md index dd088bfd..5f02d63d 100644 --- a/documentation/free-up-port-53.md +++ b/documentation/free-up-port-53.md @@ -4,11 +4,11 @@ A DNS service such as Pi-hole or AdGuard Home needs port 53. This page applies o ## Why port 53 is in use -On Debian-based systems that use `systemd-resolved`, such as Ubuntu Server 22.04 and 24.04, a DNS stub listener runs by default. It listens on `127.0.0.53:53` and answers DNS queries from local applications. A container that publishes port 53 on all host addresses then fails to start, because the port is already taken. +On Debian-based systems that use `systemd-resolved`, such as Ubuntu Server 22.04 and 24.04, a DNS stub listener runs by default. It listens on `127.0.0.53:53` and `127.0.0.54:53` and answers DNS queries from local applications. A container that publishes port 53 on all host addresses then fails to start, because the port is already taken. The `DNSStubListener` option in `/etc/systemd/resolved.conf` controls this listener: -- `DNSStubListener=yes`: `systemd-resolved` listens on `127.0.0.53:53`. This is the default. +- `DNSStubListener=yes`: `systemd-resolved` listens on `127.0.0.53:53` and `127.0.0.54:53`. This is the default. - `DNSStubListener=no`: `systemd-resolved` does not listen on port 53, so another DNS service can use it. ## Steps @@ -25,13 +25,35 @@ The `DNSStubListener` option in `/etc/systemd/resolved.conf` controls this liste DNSStubListener=no ``` -3. Restart the service: +3. Point `/etc/resolv.conf` to the file that lists your upstream DNS servers: ```bash + sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf + ``` + + Do this before the next step. On Ubuntu, `/etc/resolv.conf` points to the stub at `127.0.0.53`. That stub stops answering after the restart, so the host would lose DNS. + +4. Restart the service: + + ```bash + sudo systemctl restart systemd-resolved + ``` + +5. Check that the host still resolves names: + + ```bash + getent hosts github.com + ``` + + The command prints an IP address and the name. If it prints nothing, undo the change and enable the stub listener again: + + ```bash + sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf + sudo sed -i 's/^DNSStubListener=no/#DNSStubListener=yes/' /etc/systemd/resolved.conf sudo systemctl restart systemd-resolved ``` -4. Check that port 53 is free: +6. Check that port 53 is free: ```bash sudo ss -tuln | grep ':53 ' diff --git a/documentation/standard-setup.md b/documentation/standard-setup.md index ad156413..3ac1be3e 100644 --- a/documentation/standard-setup.md +++ b/documentation/standard-setup.md @@ -29,20 +29,22 @@ The application uses `network_mode: service:tailscale` and starts only after the | `IMAGE_URL` | Image of the application. | | `SERVICEPORT` | Port used by the optional `ports` block. The port for Tailscale Serve is set in `compose.yaml`. | | `DNS_SERVER` | DNS server used by the optional `dns` block. | -| `TS_AUTHKEY` | Your Tailscale auth key. Only needed for the first start. | +| `TS_AUTHKEY` | Your Tailscale auth key. Used only when the container is not logged in, for example at the first start or after you delete `./ts/state`. | | `TZ` | Time zone, passed to the application when its image supports it. | +Some stacks need secrets that you choose. Compose stops with an error that starts with `required variable X is missing a value` until you set them. The service README lists them under "Before you start". + ## Data All data stays in the service directory, next to `compose.yaml`. | Path | Content | | ------------------- | ----------------------------------------- | -| `./config` | Tailscale configuration files. | +| `./config` | Holds `serve.json`, the Serve configuration. Compose rewrites it from the `configs` block in `compose.yaml` each time it starts the container, so change `compose.yaml` instead. | | `./ts/state` | Tailscale state, including the device key. | | `./-data/` | Data of the application. | -Keep `./ts/state` when you recreate the stack. Without it, the device joins your Tailnet again as a new device. +Keep `./ts/state` when you recreate the stack. Without it, the device needs a valid auth key and joins your Tailnet as a new device. ## DNS diff --git a/documentation/tailscale-on-arm.md b/documentation/tailscale-on-arm.md index 464e4fb5..fb7c2393 100644 --- a/documentation/tailscale-on-arm.md +++ b/documentation/tailscale-on-arm.md @@ -1,4 +1,4 @@ -# Setting up Tailscale on OpenPLi (ARM Linux) +# Install Tailscale on an OpenPLi set-top box (without Docker) This page describes how to install and configure **Tailscale** on an OpenPLi set-top box using the ARM version of Linux. Because OpenPLi is a lightweight distribution, the usual package manager method may not work. Instead, you may need to use Tailscale’s static binaries and configure an init.d service for automatic startup. @@ -20,11 +20,10 @@ curl -fsSL https://tailscale.com/install.sh | sh ## 2. Download the ARM static binaries -Go to [Tailscale Stable Releases](https://pkgs.tailscale.com/stable/#static) and download the ARM package. -For example: +Go to [Tailscale Stable Releases](https://pkgs.tailscale.com/stable/#static) and download the archive for your architecture: `arm`, `arm64`, `mips`, or `mipsle`. The file names follow the pattern `tailscale__.tgz`, where `` is the current version shown on that page. For an ARM device, for example: ```sh -wget https://pkgs.tailscale.com/stable/tailscale_1.86.2_arm.tgz +wget https://pkgs.tailscale.com/stable/tailscale__arm.tgz ``` --- @@ -34,11 +33,13 @@ wget https://pkgs.tailscale.com/stable/tailscale_1.86.2_arm.tgz Extract the archive and copy the executables into `/usr/sbin`: ```sh -tar zxvf tailscale_1.86.2_arm.tgz -cp tailscale_1.86.2_arm/tailscal* /usr/sbin/ +tar zxvf tailscale_*_arm.tgz +cp tailscale_*_arm/tailscal* /usr/sbin/ chmod +x /usr/sbin/tailscal* ``` +If you downloaded another architecture, replace `arm` in the file names. + This provides both `tailscale` (CLI) and `tailscaled` (daemon). --- @@ -50,7 +51,7 @@ Since OpenPLi does not use `systemd`, we need to create an **init.d service** to Create the service script: ```sh -cat << EOF >/etc/init.d/tailscaled +cat << 'EOF' > /etc/init.d/tailscaled #!/bin/sh DAEMON=/usr/sbin/tailscaled PIDFILE=/var/run/tailscaled.pid @@ -59,20 +60,20 @@ DAEMON_OPTS="--state=/var/lib/tailscale/tailscaled.state --socket=/var/run/tails case "$1" in start) echo "Starting tailscaled" - start-stop-daemon --start --quiet --background --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS + start-stop-daemon --start --quiet --background --make-pidfile --pidfile "$PIDFILE" --exec "$DAEMON" -- $DAEMON_OPTS ;; stop) echo "Stopping tailscaled" - start-stop-daemon --stop --quiet ---retry=TERM/9/KILL/11 --pidfile $PIDFILE - $DAEMON --cleanup - rm -f $PIDFILE + start-stop-daemon --stop --quiet --retry=TERM/9/KILL/11 --pidfile "$PIDFILE" + "$DAEMON" --cleanup + rm -f "$PIDFILE" ;; restart) $0 stop $0 start ;; status) - if [ -f $PIDFILE ] && kill -0 "$(cat $PIDFILE)" 2>/dev/null; then + if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then echo "tailscaled is running" else echo "tailscaled is not running" From cf06055630a0da307a79f805e60c63c802e4957e Mon Sep 17 00:00:00 2001 From: Jack Spiering <46534141+jackspiering@users.noreply.github.com> Date: Sat, 10 Oct 2026 14:34:43 +0200 Subject: [PATCH 2/2] Docs: correct when Compose writes serve.json and where 127.0.0.54 applies Compose writes serve.json when it creates the container or starts a stopped one. docker compose restart keeps the current file. The second stub address 127.0.0.54 exists since systemd 250, so not on Ubuntu 22.04. --- documentation/free-up-port-53.md | 4 ++-- documentation/standard-setup.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/free-up-port-53.md b/documentation/free-up-port-53.md index 5f02d63d..6ea92059 100644 --- a/documentation/free-up-port-53.md +++ b/documentation/free-up-port-53.md @@ -4,11 +4,11 @@ A DNS service such as Pi-hole or AdGuard Home needs port 53. This page applies o ## Why port 53 is in use -On Debian-based systems that use `systemd-resolved`, such as Ubuntu Server 22.04 and 24.04, a DNS stub listener runs by default. It listens on `127.0.0.53:53` and `127.0.0.54:53` and answers DNS queries from local applications. A container that publishes port 53 on all host addresses then fails to start, because the port is already taken. +On Debian-based systems that use `systemd-resolved`, such as Ubuntu Server 22.04 and 24.04, a DNS stub listener runs by default. It listens on `127.0.0.53:53` and, since systemd 250 (for example on Ubuntu 24.04), also on `127.0.0.54:53`. It answers DNS queries from local applications. A container that publishes port 53 on all host addresses then fails to start, because the port is already taken. The `DNSStubListener` option in `/etc/systemd/resolved.conf` controls this listener: -- `DNSStubListener=yes`: `systemd-resolved` listens on `127.0.0.53:53` and `127.0.0.54:53`. This is the default. +- `DNSStubListener=yes`: `systemd-resolved` listens on port 53 of these addresses. This is the default. - `DNSStubListener=no`: `systemd-resolved` does not listen on port 53, so another DNS service can use it. ## Steps diff --git a/documentation/standard-setup.md b/documentation/standard-setup.md index 3ac1be3e..0761f4f9 100644 --- a/documentation/standard-setup.md +++ b/documentation/standard-setup.md @@ -40,7 +40,7 @@ All data stays in the service directory, next to `compose.yaml`. | Path | Content | | ------------------- | ----------------------------------------- | -| `./config` | Holds `serve.json`, the Serve configuration. Compose rewrites it from the `configs` block in `compose.yaml` each time it starts the container, so change `compose.yaml` instead. | +| `./config` | Holds `serve.json`, the Serve configuration. Compose writes it from the `configs` block in `compose.yaml` when it creates the container or starts a stopped one, so change `compose.yaml` instead. `docker compose restart` keeps the current file. | | `./ts/state` | Tailscale state, including the device key. | | `./-data/` | Data of the application. |