Skip to content

Skerry Sync: new service - #359

Open
IFindMe wants to merge 4 commits into
tailscale-dev:mainfrom
IFindMe:main
Open

IFindMe wants to merge 4 commits into
tailscale-dev:mainfrom
IFindMe:main

Conversation

@IFindMe

@IFindMe IFindMe commented Oct 3, 2026

Copy link
Copy Markdown

Adds services/skerry-sync/ from templates/service-template:

  • secherkasov/skerry-sync:latest, internal port 8080, Tailnet-only (Serve proxies https://<host>.<tailnet>.ts.net to http://127.0.0.1:8080).
  • SQLite default (./skerry-sync-data/data:/data, image runs as 999:999); PostgreSQL intentionally not wired in.
  • SKERRY_JWT_SECRET required with placeholder safe value; SKERRY_ADMIN_TOKEN empty closes /console and /admin/*.
  • App healthcheck not overridden: image defines HEALTHCHECK (wget -qO- http://localhost:8080/healthz).
  • Service README documents secrets setup, 999:999 pre-create, Tailnet URLs (/, /account, /console), and TLS-via-Serve.
  • Root README.md: Skerry Sync row under Productivity and Collaboration (alphabetized).

Related Issues

  • None.

Verification

  • docker compose config --quiet in services/skerry-sync: PASS.
  • git diff --check: PASS.
  • rumdl check --config .markdownlint.yml README.md services/skerry-sync/README.md: not run, rumdl not installed.
  • Live stack start + Tailnet reachability (/, /account, /console, app register/sync, persistence): not run, needs TS_AUTHKEY and Tailnet access.

Checklist

  • I have performed a self-review of my code and followed the templates structure.
  • I have added verification that the stack works as expected.
  • I have updated necessary documentation (e.g. frontpage README.md ).
  • I have selected the correct label(s) for this PR.

Additional Context

  • Upstream treats trusted-LAN cleartext as acceptable (E2E-encrypted payload), but requires a TLS terminator off-host; here Tailscale Serve provides that HTTPS layer.
  • Upstream refs: server README, guide, image.
  • Note: pushed commit c9541bd is currently on main of the fork; open the PR from that branch.

@jackspiering

Copy link
Copy Markdown
Collaborator

Thanks for the contribution, and for the detailed README work on Skerry Sync. I tested Skerry Sync and Termix on a live Tailnet. Both start healthy and are reachable through Serve, so the substance is good. Several things need to change before merge. The template changed after you branched (#372, #373, #380), so a rebase will pull in most of the structural updates.

Scope and branch

  • The PR holds four services and a script, but it's titled for one. Please open one PR per service, each from its own branch (not your fork's main), and title each as Service: what changes, per CONTRIBUTING.md.
  • Please drop util/cert-export.sh from these PRs. It writes private keys into the current directory. If you want it in the repo, open a separate PR or issue to discuss it first.
  • Please rebase on current main. The PR conflicts today, and the root README.md rows changed in Docs: rework the README and fix the service tables #373 and Docs: remove emojis and tighten the README #380 (no emojis, new table layout). Insert your row alphabetically by bold name, ignoring case.
  • The commits are authored as Your Name <you@example.com>. Please set your git identity.

Skerry Sync

  • Blocking: .env sets SKERRY_JWT_SECRET="REPLACE_WITH_STABLE_SECRET". The server starts with that placeholder (I confirmed this), so anyone who doesn't edit it runs on a secret that is public in the repo, and the :? check never fires. Leave it empty, add a # Required: comment above it (for example # Required: signs the sessions. Generate it with: openssl rand -base64 48), and keep ${SKERRY_JWT_SECRET:?Set SKERRY_JWT_SECRET in .env} in compose.yaml. See CONTRIBUTING.md step 2. The same goes for the commented SKERRY_DB_PASSWORD and POSTGRES_PASSWORD placeholders.
  • Data folder ownership: without a pre-created folder owned by 999:999, the app crash-loops with SQLITE_CANTOPEN. I reproduced it. Please move that step into "Before you start" and keep the fix under the optional "Troubleshooting" section.
  • README structure: please use the template headings in order: At a glance, Before you start, Deviations from the standard setup, First run, optional sections, Links. "Configuration Overview", "Prerequisites", "Volumes", "Tailnet access", "Ports", "Service-specific notes" and "Files to check" are not template headings. The optional PostgreSQL block is a deviation: list it there.
  • .env and compose cleanup: remove #version=1.1, put the TZ comment on its own line, and update the opening comment in compose.yaml to match the current template (it now says "unless it has a default such as ${VAR:-value}").
  • Description: it says PostgreSQL is "intentionally not wired in", but the second commit adds an optional block. Please make the two agree. The checklist items for validation and rumdl are also unchecked.
  • What worked: the image health check (wget on /healthz) passes inside the container, Serve works, /console and /admin/* stay closed without a token, and the database survives a recreate. I couldn't test account registration, because it needs the Skerry client.

Termix

  • README: same template restructure as above. The mkdir and chown step is unnecessary, since the image's entrypoint chowns /app/data itself.
  • .env: the commented DATABASE_URL has quotes inside the URL. Please check that the example works as written.
  • PORT: it's in .env and is also hard-coded in the Serve JSON, which is correct. Say in a comment that the two must match, or drop PORT since the image defaults to 8080.
  • Image path: upstream's compose file uses ghcr.io/termix-ssh/termix:latest. Please confirm which path is canonical.
  • What worked: healthy containers, Serve returns 200, the first account becomes admin, and login works again after a recreate.

Nextcloud and Matrix (not run; please fix and open as separate PRs)

  • Both: neither has a README or a row in the root README.md; their .env and compose.yaml files have trailing whitespace (git diff --check fails); ${SERVICE} appears inside comments, so write "the service".
  • Nextcloud:
    • TS_AUTHKEY= # ... and TAILNET_NAME= # ... set the variables to the comment text, which also breaks OVERWRITECLI_URL. Put comments on their own line.
    • MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD and NEXTCLOUD_ADMIN_PASSWORD are empty with no :? and no # Required: comment.
    • redis:alpine and mariadb:lts need a major or major.minor pin.
    • The commented ports line hard-codes 8085, dns: and TS_ACCEPT_DNS=true are enabled, and the application health check isn't commented per template step 5.
  • Matrix:
    • AllowFunnel is true, which exposes it to the public internet. The standard setup is Tailnet-only, so either turn it off or document it as a deviation with the reason.
    • The Serve Static handlers point to /config/well-known-matrix-*.json, and nothing creates those files.
    • The database container is named db-${SERVICE} instead of app-${SERVICE}-<role>, its data folder is nested inside Synapse's ./${SERVICE}-data mount, and Synapse is never configured to use it. Document the homeserver.yaml setup.
    • POSTGRES_PASSWORD has no :?.
    • Check latest for Synapse and postgres:16-alpine against the upstream recommendation.

Happy to re-test once the split PRs are up.

@jackspiering jackspiering added the new service request to add a new service label Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new service request to add a new service

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants