Skip to content

Logchef: new service - #403

Merged
jackspiering merged 2 commits into
tailscale-dev:mainfrom
mr-karan:logchef-new-service
Oct 29, 2026
Merged

jackspiering merged 2 commits into
tailscale-dev:mainfrom
mr-karan:logchef-new-service

Conversation

@mr-karan

@mr-karan mr-karan commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds a stack for Logchef, a log analytics interface for logs that already live in ClickHouse or VictoriaLogs. It queries them with LogchefQL or SQL and keeps its teams, sources and saved queries in a local SQLite file.

One application container behind the Tailscale sidecar, no deviations from the standard setup. The log backend stays outside the stack on purpose: Logchef never stores or copies logs, and bundling an empty ClickHouse would still need a separate shipper before anything was queryable. The README says what to point it at.

Built-in email and password login is enabled, so the stack needs no identity provider. Two secrets are required and use the ${VAR:?} pattern, so Compose stops until they are set:

  • API_TOKEN_SECRET, at least 32 characters
  • ADMIN_PASSWORD, at least 10 characters

Settings come from the config file in the image and are overridden with LOGCHEF_ variables, where a double underscore is one level of TOML nesting.

Disclosure: I maintain Logchef.

Related Issues

Verification

  • docker compose config --quiet from each changed service directory, with dummy values for required variables
  • The stack started, Tailscale is healthy, and the service is reachable through the Tailnet
  • The main function of the service works, and its data survives a restart
  • rumdl check --config .markdownlint.yml . on the whole repository, and git diff --check

Against the published image, which is Alpine based and ships BusyBox wget but no curl:

  • Starts clean from the stack's environment variables with no errors or warnings, and /api/v1/health returns {"status":"success","data":{"status":"ok",...}}. That is the health check command in compose.yaml, run inside the container.
  • Signed in with the bootstrap administrator, added a ClickHouse source (is_connected: true), linked it to a team, and ran SELECT ... WHERE severity_text = 'error' against a seeded table of 5 rows. It returned exactly the 2 matching rows in 5 ms.
  • The source and its data survived a restart, reconnected, and queried again.
  • With ./logchef-data/app owned by root, the container stops with unable to open database file (14). After chown 1000:1000 it starts and writes local.db plus its -wal and -shm files to the host. That is why "Before you start" has the chown step, and why the exact message is in "Troubleshooting": it never mentions permissions.

On a live Tailnet the sidecar joined as logchef-test.dove-climb.ts.net, Tailscale Serve issued the certificate, and https://<name>/api/v1/health answered. Signing in, adding the source, the query and a full docker compose down && up all pass over that address. Details are in a comment below.

Impact on existing users

  • None. New service.

Checklist

  • I have performed a self-review of my code and followed the templates structure.
  • I did not commit a working auth key, password, token, or other credential.
  • The service README uses the headings of the template, in the same order, and is up to date.
  • I added, removed, or renamed the service in the root README.md, in alphabetical order, or this PR does not change the list of services.

Additional Context

ClickHouse uses its native protocol port, 9000, for a source, not the HTTP port 8123. Mixing them up is the most likely setup mistake, so it is called out in "Troubleshooting".

Anyone who pulled ghcr.io/mr-karan/logchef:latest before v2.5.0 should run docker compose pull. Older images shipped a config file that pointed at a path only present in a source checkout, so they exited at startup. Fixed upstream in v2.5.0, which is what latest now resolves to.

@mr-karan

Copy link
Copy Markdown
Contributor Author

Ran the stack end to end on a live Tailnet. All 13 checks pass, from an empty data folder:

== Waiting for the Tailscale sidecar to report healthy
   PASS  tailscale-logchef-test healthy
== Tailnet identity
   PASS  joined the Tailnet as 100.87.31.65
   PASS  MagicDNS name logchef-test.dove-climb.ts.net
== Waiting for the application container to report healthy
   PASS  app-logchef-test healthy
== Health endpoint inside the container
   PASS  /api/v1/health returns ok
== Reaching the service over HTTPS through the Tailnet
   PASS  https://logchef-test.dove-climb.ts.net/api/v1/health served over Tailscale Serve
== Signing in as the bootstrap administrator
   PASS  signed in as admin@example.com
== Adding the ClickHouse source
   PASS  source connected
== Granting access through a team
   PASS  team created
   PASS  source linked to the team
   PASS  administrator added to the team
== Querying the logs
   PASS  query returned the 2 expected error rows
== Recreating the stack to confirm the data survives
   PASS  the source survived and reconnected
== Result: 13 passed, 0 failed

tailscale serve status inside the sidecar:

https://logchef-test.dove-climb.ts.net (tailnet only)
|-- / proxy http://127.0.0.1:8125

The last check is a full docker compose down followed by up, not a container restart, so it exercises the bind mount. The source came back connected and the query returned the same rows.

The run found one real documentation bug, fixed in 3242a06. The data folder is ./${SERVICE}-data/app, but "Before you start" named logchef-data/app literally. Anyone who changes SERVICE, which the .env header invites for a second copy, would create the wrong folder. Docker then creates the right one as root and the container stops with unable to open database file (14), which says nothing about permissions. The README now ties the folder to SERVICE and names that error.

One note for anyone reproducing this, not a problem with the stack: on my host /etc/resolv.conf points at a local resolver that does not forward ts.net to MagicDNS, so the name resolved through public DNS to an unrelated address and TLS failed. Resolving the name to the node's Tailnet address fixed it. Worth knowing if https://<service>.<tailnet>.ts.net fails while tailscale status shows the device.

@jackspiering
jackspiering merged commit adb87c1 into tailscale-dev:main Oct 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🏗️ New Service: Logchef

2 participants