agentleFS
RhovianRhovian/niles/skills/remote-setup/SKILL.md

remote-setup

Skill4 starsChanged 43 days agoApache-2.0View on GitHub

Use when setting up Niles phone access through a Tailscale relay, including Caddy, host tags, shared push and Wake-on-LAN. Fresh installs only; not for migrating existing remote deployments or configuring project setups.

  • Installs packages

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. giandemoncell-prog/claude-skills★ 0same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository13 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

18 rules. About 0 are common, 8 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Ask only for information you cannot discover through authorized access.

    line 18
  2. Very specific:

    Read the deployment's existing config and service state.

    line 19
  3. Very specific:

    Verify type -a niles tailscale, niles --version, niles remote --help, tailscale version --daemon --json, tailscale status --json, and …

    line 30
  4. Very specific:

    Do not use a node key, machine key, DNS name or IP as remote.relay_node.

    line 36
  5. Distinctive:

    Verify its DNS name is listed in CertDomains.

    line 38
  6. Distinctive:

    Use open-source Homebrew tailscaled on macOS.

    line 40
  7. Very specific:

    Check Tailscale operator privileges for the service account.

    line 44
  8. Distinctive:

    Keep its parent directory mode 0700 and file mode 0600, owned by the service user.

    line 100
  9. Distinctive:

    If push is declined, skip initialization and report push as unconfigured.

    line 103
  10. Distinctive:

    If WoL is requested, keep the relay awake on the targets' LAN.

    line 104
  11. Distinctive:

    If a target cannot support WoL, leave it out and report that limitation.

    line 117
  12. Very specific:

    Create a user service for niles remote --port 8765 on each host, using the absolute binary path and an explicit PATH containing tailscale, …

    line 118
  13. Distinctive:

    Create log directories first.

    line 129
  14. Very specific:

    Write hosts.json in the built PWA root.

    line 133
  15. Very specific:

    Write a dedicated Caddyfile outside the web root, e.g.

    line 142
  16. Very specific:

    Check that port 8080 listens only on 127.0.0.1.

    line 184
  17. Very specific:

    Run tailscale serve --bg --https=443 http://127.0.0.1:8080 as the configured operator.

    line 185
  18. Very specific:

    If WoL is configured, test POST /api/hosts/desktop/wake through relay HTTPS with Content-Type: application/json and body null.

    line 208

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Remote setup

Set up an always-on relay that also runs Niles. The request path is phone → Tailscale Serve HTTPS → localhost Caddy → each Niles host's tailnet IPv4 listener. Serve cannot proxy directly to other tailnet IPs: its dialer bypasses Tailscale routes. No CORS, Funnel, public listeners or extra authentication headers are needed.

Inventory before changing anything

  1. Collect the relay and host SSH/access details, OS users running Niles, host display names and routing IDs for the manifest, permitted phone users, and whether push/WoL are wanted. For push collect a mailto: or https: contact URI. Include the relay as a host. For WoL collect target MACs and LAN broadcasts from the operator/network. Ask only for information you cannot discover through authorized access.
  2. Read the deployment's existing config and service state. Inspect tailscale serve status --json, Funnel status, Caddy configuration and listeners, ~/.niles/config.yaml, and Niles user services on every machine. Existing remote deployments need a separate migration plan: stop and report the conflict instead of overwriting services, Serve mounts, push keys or tailnet policy. An occupied Serve root, chosen port or service path is also a conflict, even if unrelated. Preserve unrelated config. Do not use tailscale serve reset. Existing path/Unix-socket mounts gate the whole Serve config: even step 13's HTTP proxy may need sudo. Preserve those mounts and report missing privileges. Tailscale #22117 makes root mandatory for configs containing these mounts; operator privileges no longer suffice.
  3. Verify type -a niles tailscale, niles --version, niles remote --help, tailscale version --daemon --json, tailscale status --json, and tailscale ip -4 on each machine. Require a remote-enabled Niles binary, matching Tailscale CLI/daemon versions >=1.96.2, a running authenticated daemon, and stable tailnet IPv4 addresses. Record the relay's DNS name, Self.ID and IPv4; confirm its stable node ID with tailscale whois --json <relay-tailnet-ip> → Node.StableID. Do not use a node key, machine key, DNS name or IP as remote.relay_node.
  4. On the relay enable MagicDNS and HTTPS certificates in the tailnet DNS settings. Verify its DNS name is listed in CertDomains. The phone joins the same tailnet as a user-owned device: tagged clients have no Serve login header. Use open-source Homebrew tailscaled on macOS. Check the LaunchDaemon's PATH includes the directory containing the tailscale CLI; Homebrew service regeneration can undo this. Keep this PATH check until the relay includes Tailscale #22117, which removes the daemon's sudo --list check. Check Tailscale operator privileges for the service account; if needed, give the operator the exact sudo tailscale set --operator=<user> fix. Report privileged prerequisites that authorized access cannot complete.
  5. Install matching remote-enabled Niles binaries on all hosts and built PWA assets on the relay. Use the release's niles-web.tar.gz with cargo install niles --locked --version <version> --features remote, or a trusted checkout's scripts/install-remote.sh (Node 24, pnpm 10.8.1, Rust 1.89+, OpenSSL). Confirm index.html is at the asset root. Serve only this dedicated built directory plus hosts.json; never serve a checkout, home directory or ~/.niles/. Install Caddy on the relay and record caddy version.

Restrict the tailnet

  1. Merge tags and grants into the existing tailnet policy. Substitute actual owners and users; this fragment is not a replacement policy:

    {
      "tagOwners": {
        "tag:niles-relay": ["autogroup:admin"],
        "tag:niles-host": ["autogroup:admin"]
      },
      "grants": [
        {"src": ["you@example.com"], "dst": ["tag:niles-relay"], "ip": ["tcp:443"]},
        {"src": ["tag:niles-relay"], "dst": ["tag:niles-host"], "ip": ["tcp:8765"]},
        {"src": ["tag:niles-relay"], "dst": ["tag:niles-relay"], "ip": ["tcp:8765"]}
      ]
    }

    Assign only the relay tag to the relay node; assign the host tag to other hosts. The third grant lets the relay reach its own backend. Adapt ports if needed. Inspect all existing grants/ACLs: permissions are additive, so a broad allow rule defeats these restrictions. Preserve needed SSH/admin access; verify policy tests permit chosen phone users on relay:443 and relay on every backend port, and deny unwanted users/devices. Apply tags through the admin console or tailscale set --advertise-tags=..., preserving existing tags. Recheck the relay's stable ID after tagging. Tags control network reachability; the backend additionally pins one exact relay node, not every node with its tag. Tailnet policy reference: https://tailscale.com/docs/reference/syntax/policy-file

Configure hosts and push

  1. Merge this into each host user's ~/.niles/config.yaml, including the relay:

    remote:
      relay_node: nYOUR_RELAY_STABLE_NODE_ID

    remote.allowed_users no longer exists. Every login admitted by Serve and the tailnet policy has shell authority on every configured host. The backend binds tailscale ip -4, not localhost; Caddy must connect to that address even for the relay's own backend so WhoIs sees the relay node.

  2. For push, generate one key with niles remote init --subject mailto:you@example.com on the relay as the Niles user. Securely copy that same ~/.niles/remote/vapid.json to every host user's same path. Keep its parent directory mode 0700 and file mode 0600, owned by the service user. Compare files without printing private contents. Do not generate independent keys, overwrite an existing key, put keys in the web root, or copy subscriptions. If push is declined, skip initialization and report push as unconfigured.
  3. If WoL is requested, keep the relay awake on the targets' LAN. Enable WoL in each target's firmware and OS, determine the correct NIC MAC and subnet broadcast, and add this server-side map only on the relay, alongside its relay_node:

      wake_hosts:
        desktop:
          mac: "01:23:45:67:89:ab"
          broadcast: 192.168.1.255

    IDs must match hosts.json. Invalid targets stop backend startup. No MAC or broadcast address belongs in hosts.json, JavaScript or a phone request. If a target cannot support WoL, leave it out and report that limitation.

  4. Create a user service for niles remote --port 8765 on each host, using the absolute binary path and an explicit PATH containing tailscale, tmux and the agent CLIs. Preserve the user's HOME and credential environment; shell startup files are not loaded. On Linux use ~/.config/systemd/user/niles-remote.service, with After=network-online.target, Restart=on-failure, RestartSec=5 and WantedBy=default.target, then daemon-reload and enable --now; enable user lingering if it must survive logout. On macOS use ~/Library/LaunchAgents/dev.niles.remote.plist, Label=dev.niles.remote, ProgramArguments as an array, RunAtLoad=true, KeepAlive=true and stdout/stderr logs, then launchctl bootstrap gui/<uid> <plist>. Escape paths for the service format; validate with systemd-analyze verify or plutil -lint before loading. Create log directories first. Check startup logs and listener address. Restart after config or key changes.

Configure the relay origin

  1. Write hosts.json in the built PWA root. IDs are unique, match [A-Za-z0-9][A-Za-z0-9_-]*, and stay stable; names are nonempty display text. Choose lowercase IDs: Caddy path matching cannot distinguish IDs by case alone. Example (replace with the inventory):

    {"hosts":[{"id":"relay","name":"Relay"},{"id":"desktop","name":"Desktop"}]}
  2. Write a dedicated Caddyfile outside the web root, e.g. ~/.config/niles/Caddyfile. Replace example IPs with the recorded tailnet IPv4s, and extend one explicit handle_path per manifest host. NILES_WEB_DIR must be an absolute path to the built PWA root, set in Caddy's service environment:

    {
        admin off
        auto_https off
    }
    http://127.0.0.1:8080 {
        bind 127.0.0.1
        handle /api/hosts/*/wake {
            reverse_proxy 100.64.0.1:8765
        }
        handle_path /h/relay/* {
            reverse_proxy 100.64.0.1:8765
        }
        handle_path /h/desktop/* {
            reverse_proxy 100.64.0.2:8765
        }
        @unknown path /api /api/* /h /h/*
        handle @unknown {
            respond 404
        }
        handle {
            root * "{$NILES_WEB_DIR}"
            header /hosts.json Cache-Control no-store
            file_server
        }
    }

    handle_path strips /h/<id>, retaining /api/... and query strings. The wake route retains its full path and always targets the relay. Caddy preserves Serve's Tailscale-User-Login header by default; do not synthesize or append an identity. Caddy streams text/event-stream automatically. Use its normal HTTP transport, not a userspace Tailscale transport. Reference: https://caddyserver.com/docs/caddyfile/directives/reverse_proxy

  3. With NILES_WEB_DIR set, run caddy validate --config <Caddyfile> --adapter caddyfile. Install a separate Caddy service as the relay user, with absolute binary/config paths and that environment, using the same OS service manager as step 10. Check that port 8080 listens only on 127.0.0.1. Start Caddy before Serve. Run tailscale serve --bg --https=443 http://127.0.0.1:8080 as the configured operator. Check Serve status and confirm Funnel is disabled. Serve owns TLS and strips forged identity headers; Caddy is reachable only locally. Reference: https://tailscale.com/docs/features/tailscale-serve

Verify and hand back

  1. From an allowed user-owned tailnet device, require 200 HTML at the relay HTTPS root and a valid, noncached hosts.json. Fetch every /h/<id>/api/sessions and /h/<id>/api/projects; require 200 JSON with api_version=1, the corresponding arrays and Cache-Control: no-store. Check an SSE feed emits its initial snapshot promptly. Confirm an unknown /h/ ID returns 404. A direct request to a backend from a different tailnet node, even with a forged Tailscale-User-Login, must be denied by policy or return 403. Also test an unwanted user cannot access relay HTTPS. Do not treat local spoofed-header curls as proof of end-to-end identity. On failures inspect service logs, policy and proxy paths; stop and report the failed layer rather than claiming installation succeeded.
  2. Open the relay URL on the phone, send a harmless message and verify it at the desk. Install/Add to Home Screen (iOS push requires 16.4+ and the installed app). With all hosts awake and push configured, Enable notifications must register one shared subscription through every host; fix any named failure and retry. Check each public VAPID key matches, trigger a notification per host, and confirm it opens the correct host/session. Rerun registration after adding hosts. Opening notifications needs Tailscale.
  3. If WoL is configured, test POST /api/hosts/desktop/wake through relay HTTPS with Content-Type: application/json and body null; require 204, then check actual wake/reachability and the phone's asleep-host Wake button. A sent packet is not proof of waking; unknown IDs return 404. Never accept a phone-supplied destination.
  4. Record exactly which mounts, files and services this run created. Report the relay URL, host/route inventory, changed files and policy, service/log locations, restart commands, verification results and anything untested. For recovery remove only files/services and the Serve mount created in this run (tailscale serve --bg --https=443 --set-path=/ off), after rechecking ownership; preserve keys, config and unrelated mounts. Upgrade binary and PWA together and close/reopen app windows.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.