From 5244ac3e403b08857ddab31b55f5a0806614f885 Mon Sep 17 00:00:00 2001 From: kommandantredundant Date: Wed, 10 Jun 2026 15:17:12 +0200 Subject: [PATCH 01/11] Added service kitchenowl --- README.md | 1 + services/kitchenowl/.env | 29 +++++++++++ services/kitchenowl/README.md | 12 +++++ services/kitchenowl/docker-compose.yaml | 68 +++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100755 services/kitchenowl/.env create mode 100644 services/kitchenowl/README.md create mode 100755 services/kitchenowl/docker-compose.yaml diff --git a/README.md b/README.md index 1e2ba83..09d07dd 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | ๐Ÿฅ˜ Service | ๐Ÿ“ Description | ๐Ÿ”— Link | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | +| ๐Ÿฅ˜ **Kitchenowl** | A self-hosted smart grocery list and recipe manager with features like expense tracking, weekly meal planner, rich recipe import options and OIDC support. | [Details](services/kitchenowl) | | ๐Ÿฅ˜ **Mealie** | A self-hosted recipe manager and meal planner with features like shopping lists, scaling, and importing. | [Details](services/mealie) | | ๐Ÿฅ˜ **Tandoor Recipes** | A self-hosted recipe manager that also serves as a meal planner that has features such as nutrient tracking, shopping lists, importing and AI. | [Details](services/tandoor) | diff --git a/services/kitchenowl/.env b/services/kitchenowl/.env new file mode 100755 index 0000000..5b50e61 --- /dev/null +++ b/services/kitchenowl/.env @@ -0,0 +1,29 @@ +#version=1.1 +#URL=https://github.com/tailscale-dev/ScaleTail +#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure. + +# Service Configuration +SERVICE=kitchenowl +IMAGE_URL=tombursch/kitchenowl:latest + +# Network Configuration +SERVICEPORT=8080 +DNS_SERVER=9.9.9.9 + +# Tailscale Configuration +TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions. + +# Time Zone setting for containers +TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +# Optional Service variables +# PUID=1000 + +#EXAMPLE_VAR="Environment varibale" + +JWT_SECRET_KEY= # Generate a random string for JWT secret key, e.g., using: openssl rand -base64 32 + +FRONT_URL= # the exact URL of your kitchenowl instance, requred when using OIDC authentication, e.g https://kitchenowl.example.com +OIDC_ISSUER=# your OIDC issuer, e.g https://accounts.google.com +OIDC_CLIENT_ID= # to be generated by your OIDC provider +OIDC_CLIENT_SECRET= # to be generated by your OIDC provider \ No newline at end of file diff --git a/services/kitchenowl/README.md b/services/kitchenowl/README.md new file mode 100644 index 0000000..05aefa7 --- /dev/null +++ b/services/kitchenowl/README.md @@ -0,0 +1,12 @@ +# Kitchenowl with Tailscale Sidecar Configuration + +This Docker Compose configuration sets up [Kitchenowl](https://github.com/TomBursch/kitchenowl) with Tailscale as a sidecar container to securely access your meal planner over a private Tailscale network. By using Tailscale in a sidecar configuration, you can enhance the security and privacy of your Kitchenowl instance, ensuring that it is only accessible within your Tailscale network. + +## Kitchenowl + +[Kitchenowl](https://kitchenowl.org/) is a smart grocery list and recipe manager with features like expense tracking, weekly meal planner and rich recipe import options. This configuration leverages Tailscale to securely connect to your Kitchenowl dashboard, ensuring that your self-hosted interface is protected from unauthorized access and only reachable via your private Tailscale network. You can find options to set up Open ID Connect [here](https://docs.kitchenowl.org/latest/self-hosting/oidc/). + +## Configuration Overview + +In this setup, the `tailscale-kitchenowl` service runs Tailscale, which manages secure networking for the Kitchenowl service. The `app-kitchenowl` service uses the Tailscale network stack via Docker's `network_mode: service:` configuration. This setup ensures that Kitchenowl's web interface is only accessible through the Tailscale network (or locally, if preferred), providing an extra layer of security and privacy for your self-hosted meal planner. +You can find information on how to set up Open ID Connect [here](https://docs.kitchenowl.org/latest/self-hosting/oidc/). Just uncomment the section in both the .env-file and the docker-compose.yaml and set up your parameters in the .env-file to use them! diff --git a/services/kitchenowl/docker-compose.yaml b/services/kitchenowl/docker-compose.yaml new file mode 100755 index 0000000..c89635e --- /dev/null +++ b/services/kitchenowl/docker-compose.yaml @@ -0,0 +1,68 @@ +configs: + ts-serve: + content: | + {"TCP":{"443":{"HTTPS":true}}, + "Web":{"$${TS_CERT_DOMAIN}:443": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:8080"}}}}, + "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}} + +services: +# Make sure you have updated/checked the .env file with the correct variables. +# All the ${ xx } need to be defined there. + # Tailscale Sidecar Configuration + tailscale: + image: tailscale/tailscale:latest # Image to be used + container_name: tailscale-${SERVICE} # Name for local container management + hostname: ${SERVICE} # Name used within your Tailscale environment + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz" + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The : for the healthz endpoint + #- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS + - TS_AUTH_ONCE=true + configs: + - source: ts-serve + target: /config/serve.json + volumes: + - ./config:/config # Config folder used to store Tailscale files - you may need to change the path + - ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path + devices: + - /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work + cap_add: + - net_admin # Tailscale requirement + ports: + - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding port ${SERVICE}PORT to the local network - may be removed if only exposure to your Tailnet is required + # If any DNS issues arise, use your preferred DNS provider by uncommenting the config below + # dns: + # - ${DNS_SERVER} + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 10s # Time to wait before starting health checks + restart: always + + # ${SERVICE} + kitchenowl: + image: ${IMAGE_URL} # Image to be used + network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale + container_name: app-${SERVICE} # Name for local container management + env_file: .env + environment: + - JWT_SECRET_KEY=${JWT_SECRET_KEY} # JWT secret key for authentication - make sure to set this in the .env file + ## Optional for OIDC support - make sure to set these in the .env file if required! + #- FRONT_URL=${FRONT_URL} + #- OIDC_ISSUER=${OIDC_ISSUER} + #- OIDC_CLIENT_ID=${OIDC_CLIENT_ID} + #- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET} + restart: unless-stopped + depends_on: + tailscale: + condition: service_healthy + volumes: + - ./data:/data \ No newline at end of file From 565ab5778e0f19c524b7d274afcec3eb7d07f184 Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:44:54 +0200 Subject: [PATCH 02/11] Update .env file with FRONT_URL and comment out OIDC variables --- services/kitchenowl/.env | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/kitchenowl/.env b/services/kitchenowl/.env index 5b50e61..43895e9 100755 --- a/services/kitchenowl/.env +++ b/services/kitchenowl/.env @@ -23,7 +23,7 @@ TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_tim JWT_SECRET_KEY= # Generate a random string for JWT secret key, e.g., using: openssl rand -base64 32 -FRONT_URL= # the exact URL of your kitchenowl instance, requred when using OIDC authentication, e.g https://kitchenowl.example.com -OIDC_ISSUER=# your OIDC issuer, e.g https://accounts.google.com -OIDC_CLIENT_ID= # to be generated by your OIDC provider -OIDC_CLIENT_SECRET= # to be generated by your OIDC provider \ No newline at end of file +FRONT_URL=https://kitchenowl..ts.net # the exact URL of your kitchenowl instance, required when using OIDC authentication, e.g https://kitchenowl.example.com +#OIDC_ISSUER= # your OIDC issuer, e.g https://accounts.google.com +#OIDC_CLIENT_ID= # to be generated by your OIDC provider +#OIDC_CLIENT_SECRET= # to be generated by your OIDC provider \ No newline at end of file From 2f9521a8e82bc734d09c18f325e0e1fb72d11fdf Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:45:04 +0200 Subject: [PATCH 03/11] Add Tailscale configuration and health check for kitchenowl service --- services/kitchenowl/{docker-compose.yaml => compose.yaml} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename services/kitchenowl/{docker-compose.yaml => compose.yaml} (98%) diff --git a/services/kitchenowl/docker-compose.yaml b/services/kitchenowl/compose.yaml similarity index 98% rename from services/kitchenowl/docker-compose.yaml rename to services/kitchenowl/compose.yaml index c89635e..48921be 100755 --- a/services/kitchenowl/docker-compose.yaml +++ b/services/kitchenowl/compose.yaml @@ -53,6 +53,8 @@ services: network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale container_name: app-${SERVICE} # Name for local container management env_file: .env + volumes: + - ./${SERVICE}-data/:/data environment: - JWT_SECRET_KEY=${JWT_SECRET_KEY} # JWT secret key for authentication - make sure to set this in the .env file ## Optional for OIDC support - make sure to set these in the .env file if required! @@ -60,9 +62,7 @@ services: #- OIDC_ISSUER=${OIDC_ISSUER} #- OIDC_CLIENT_ID=${OIDC_CLIENT_ID} #- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET} - restart: unless-stopped depends_on: tailscale: condition: service_healthy - volumes: - - ./data:/data \ No newline at end of file + restart: unless-stopped \ No newline at end of file From 548267a4cf76dd458861c920556ce7faf63d4bd9 Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:48:29 +0200 Subject: [PATCH 04/11] Enhance README for Kitchenowl with detailed Tailscale integration and key features --- services/kitchenowl/README.md | 54 ++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/services/kitchenowl/README.md b/services/kitchenowl/README.md index 05aefa7..6dc8c93 100644 --- a/services/kitchenowl/README.md +++ b/services/kitchenowl/README.md @@ -1,12 +1,58 @@ # Kitchenowl with Tailscale Sidecar Configuration -This Docker Compose configuration sets up [Kitchenowl](https://github.com/TomBursch/kitchenowl) with Tailscale as a sidecar container to securely access your meal planner over a private Tailscale network. By using Tailscale in a sidecar configuration, you can enhance the security and privacy of your Kitchenowl instance, ensuring that it is only accessible within your Tailscale network. +This Docker Compose configuration sets up **Kitchenowl** with a Tailscale sidecar container, enabling secure, private access to your self-hosted grocery list, recipe manager, and meal planner over your Tailnet. With this setup, your Kitchenowl instance is **not exposed to the public internet** and is only accessible from authorized devices connected via Tailscale. ## Kitchenowl -[Kitchenowl](https://kitchenowl.org/) is a smart grocery list and recipe manager with features like expense tracking, weekly meal planner and rich recipe import options. This configuration leverages Tailscale to securely connect to your Kitchenowl dashboard, ensuring that your self-hosted interface is protected from unauthorized access and only reachable via your private Tailscale network. You can find options to set up Open ID Connect [here](https://docs.kitchenowl.org/latest/self-hosting/oidc/). +[**Kitchenowl**](https://github.com/TomBursch/kitchenowl) is a self-hosted grocery list, recipe manager, and meal planning application designed for households and shared kitchens. It helps you organize shopping lists, recipes, weekly meal plans, pantry items, and household food planning from a central web interface. + +Kitchenowl is useful for families, housemates, and home labs that want a private alternative to cloud-hosted grocery and recipe apps. It supports collaborative lists, recipe import workflows, meal planning, and optional account integration features, making it a practical tool for day-to-day kitchen organization. + +## Key Features + +- ๐Ÿ›’ Shared grocery lists for households and teams +- ๐Ÿฝ๏ธ Recipe management with rich recipe import options +- ๐Ÿ“… Weekly meal planning for organizing upcoming meals +- ๐Ÿ’ธ Expense tracking for grocery and household food costs +- ๐Ÿงบ Pantry and household item organization +- ๐Ÿ‘ฅ Multi-user collaboration for shared kitchens +- ๐Ÿ” Optional OpenID Connect support for external authentication +- ๐Ÿ›ก๏ธ Tailnet-only access when paired with the included Tailscale sidecar + +## Tailscale Integration + +This setup uses a **Tailscale sidecar container** to provide secure private networking for Kitchenowl. The Kitchenowl container shares the Tailscale container's network stack using Docker's `network_mode: service:` pattern. + +Because of this, Kitchenowl does not need to publish ports directly to the host. Instead, you access the web interface through the Tailscale hostname or Tailnet IP assigned to the sidecar. This keeps the service private, reduces exposure, and avoids the need for public DNS, inbound firewall rules, or a public reverse proxy. ## Configuration Overview -In this setup, the `tailscale-kitchenowl` service runs Tailscale, which manages secure networking for the Kitchenowl service. The `app-kitchenowl` service uses the Tailscale network stack via Docker's `network_mode: service:` configuration. This setup ensures that Kitchenowl's web interface is only accessible through the Tailscale network (or locally, if preferred), providing an extra layer of security and privacy for your self-hosted meal planner. -You can find information on how to set up Open ID Connect [here](https://docs.kitchenowl.org/latest/self-hosting/oidc/). Just uncomment the section in both the .env-file and the docker-compose.yaml and set up your parameters in the .env-file to use them! +The Compose stack is built around two services: + +1. **Tailscale sidecar** + Handles authentication to your Tailnet and provides the private network endpoint for the application. + +2. **Kitchenowl application** + Runs the Kitchenowl web interface and uses the Tailscale sidecar's network namespace for secure Tailnet-only access. + +Kitchenowl should be configured with persistent storage so recipes, shopping lists, users, pantry data, meal plans, and application settings are retained across container restarts and updates. Review the provided `compose.yaml` and `.env` file before deployment, especially if you want to enable authentication integrations. + +## OpenID Connect + +Kitchenowl supports OpenID Connect for external authentication providers. This can be useful when integrating Kitchenowl with an existing identity provider such as Authentik, Authelia, Keycloak, or another OIDC-compatible service. + +To enable OIDC in this ScaleTail service, review the commented OIDC sections in both the `.env` file and the `compose.yaml` file. Uncomment the relevant values and fill in the required provider details before starting the stack. + +You can find the upstream Kitchenowl OIDC documentation here: [Kitchenowl OpenID Connect Documentation](https://docs.kitchenowl.org/latest/self-hosting/oidc/). + +## Usage Notes + +Once logged in, create your household, configure users, and begin adding grocery lists, recipes, pantry items, and meal plans. Since Kitchenowl is designed for shared household use, review user permissions and authentication settings before inviting other people to the instance. + +## References + +- [Kitchenowl Website](https://kitchenowl.org/) +- [Kitchenowl GitHub Repository](https://github.com/TomBursch/kitchenowl) +- [Kitchenowl Documentation](https://docs.kitchenowl.org/) +- [Kitchenowl OpenID Connect Documentation](https://docs.kitchenowl.org/latest/self-hosting/oidc/) +- [Tailscale Docker Documentation](https://tailscale.com/kb/1282/docker) \ No newline at end of file From aa64ac45b28a20d0f67dc16d2bfeffc61a424dd2 Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:50:53 +0200 Subject: [PATCH 05/11] Fix formatting in README files by ensuring proper newline at end of file --- README.md | 2 +- services/kitchenowl/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3fa15fb..2a8cb0c 100644 --- a/README.md +++ b/README.md @@ -274,4 +274,4 @@ See [CONTRIBUTING.md](/CONTRIBUTING.md) for guidance on adding services with the ## License -[MIT](https://choosealicense.com/licenses/mit/) \ No newline at end of file +[MIT](https://choosealicense.com/licenses/mit/) diff --git a/services/kitchenowl/README.md b/services/kitchenowl/README.md index 6dc8c93..ac5f3d7 100644 --- a/services/kitchenowl/README.md +++ b/services/kitchenowl/README.md @@ -55,4 +55,4 @@ Once logged in, create your household, configure users, and begin adding grocery - [Kitchenowl GitHub Repository](https://github.com/TomBursch/kitchenowl) - [Kitchenowl Documentation](https://docs.kitchenowl.org/) - [Kitchenowl OpenID Connect Documentation](https://docs.kitchenowl.org/latest/self-hosting/oidc/) -- [Tailscale Docker Documentation](https://tailscale.com/kb/1282/docker) \ No newline at end of file +- [Tailscale Docker Documentation](https://tailscale.com/kb/1282/docker) From 3684ba4a23974a03b3b223c000dfefbcc0bc69c4 Mon Sep 17 00:00:00 2001 From: kommandantredundant Date: Wed, 24 Jun 2026 18:41:59 +0200 Subject: [PATCH 06/11] added service sure finance --- README.md | 1 + services/sure/.env | 43 ++++++++++ services/sure/README.md | 114 +++++++++++++++++++++++++ services/sure/compose.yaml | 169 +++++++++++++++++++++++++++++++++++++ 4 files changed, 327 insertions(+) create mode 100755 services/sure/.env create mode 100644 services/sure/README.md create mode 100755 services/sure/compose.yaml diff --git a/README.md b/README.md index 2a8cb0c..a7c0394 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | ๐Ÿ”„ **Resilio Sync** | A fast, reliable, and simple file sync and share solution. | [Details](services/resilio-sync) | | ๐Ÿ“ **Seafile** | A self-hosted file syncing and collaboration platform with file sharing, versioning, and team library support. | [Details](services/seafile) | | ๐Ÿ—‚๏ธ **Stirling-PDF** | A web application for managing and editing PDF files. | [Details](services/stirlingpdf) | +| ๐Ÿ’ฐ **Sure Finance** | A self-hosted personal finance and budgeting app with optional AI insights. | [Details](services/sure) | | ๐Ÿ“„ **BentoPDF** | A lightweight, self-hosted web app for viewing and managing PDF documents. | [Details](services/bentopdf) | | ๐Ÿ“‹ **Formbricks** | A self-hosted, open-source platform for collecting user feedback, surveys, and NPS. | [Details](services/formbricks) | | ๐Ÿฆ **Subtrackr** | A self-hosted web app to track subscriptions, renewal dates, costs, and payment methods. | [Details](services/subtrackr) | diff --git a/services/sure/.env b/services/sure/.env new file mode 100755 index 0000000..b229c1a --- /dev/null +++ b/services/sure/.env @@ -0,0 +1,43 @@ +#version=1.1 +#URL=https://github.com/tailscale-dev/ScaleTail +#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure. + +# Service Configuration +SERVICE=sure # Service name used as hostname in Tailscale and for container naming (app-${SERVICE}) +TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +# Tailscale Configuration +TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys + +# Database (PostgreSQL) +POSTGRES_USER=sure_user +POSTGRES_PASSWORD=sure_password +POSTGRES_DB=sure_production +DB_HOST=172.28.0.10 # Static IP of db on sure_net (web/worker share tailscale namespace where Docker DNS is overridden by MagicDNS) +DB_PORT=5432 +POSTGRES_HOST=db # Used by the backup service (on sure_net, Docker DNS works) + +# Redis +REDIS_URL=redis://172.28.0.11:6379/1 # Static IP of redis on sure_net (web/worker share tailscale namespace where Docker DNS is overridden by MagicDNS) + +# Sure Application +SECRET_KEY_BASE= #openssl rand -hex 64 +SELF_HOSTED=true +RAILS_FORCE_SSL=true +RAILS_ASSUME_SSL=true +PORT=8070 + +# OpenAI (Optional) +OPENAI_ACCESS_TOKEN= # NOTE: enabling OpenAI will incur costs when you use AI-related features in the app (chat, rules) + +# OIDC Authentication (Optional) +OIDC_ISSUER= # OIDC issuer URL for authentication +OIDC_CLIENT_ID= +OIDC_CLIENT_SECRET= +OIDC_REDIRECT_URI=https:///auth/openid_connect/callback + +# Backup Configuration +SCHEDULE=@daily +BACKUP_KEEP_DAYS=7 +BACKUP_KEEP_WEEKS=4 +BACKUP_KEEP_MONTHS=6 diff --git a/services/sure/README.md b/services/sure/README.md new file mode 100644 index 0000000..4aa53d0 --- /dev/null +++ b/services/sure/README.md @@ -0,0 +1,114 @@ +# Sure with Tailscale Sidecar Configuration + +This Docker Compose configuration sets up [Sure](https://github.com/we-promise/sure) with Tailscale as a sidecar container, enabling secure, private access to your self-hosted personal finance platform over your Tailnet. With this setup, your Sure instance is **not exposed to the public internet** and is only reachable from authorized devices connected via Tailscale. + +## Sure + +[**Sure**](https://sure.am) is a self-hosted personal finance application and a community-maintained fork of the now-archived Maybe Finance project. It is an all-in-one platform for tracking bank accounts, monitoring stocks and crypto holdings, and following your overall net worth โ€” all from a single interface with multi-currency support. + +Sure is built on Ruby on Rails and is designed for individuals and households that want full ownership of their financial data instead of relying on cloud-hosted finance apps. It includes transaction and portfolio tracking alongside optional AI-assisted features, while remaining fully self-hostable with Docker. + +## Key Features + +- ๐Ÿ“Š Net worth tracking across all of your accounts +- ๐Ÿ’ณ Bank, credit card, and cash transaction management +- ๐Ÿ“ˆ Stocks and cryptocurrency portfolio monitoring +- ๐Ÿ’ฑ Multi-currency support for international finances +- ๐Ÿค– Optional AI features (chat, rules) via OpenAI integration +- ๐Ÿ” Optional OpenID Connect (OIDC) single sign-on +- ๐Ÿ”‘ WebAuthn MFA support for passkeys and hardware security keys +- ๐Ÿ›ก๏ธ Tailnet-only access when paired with the included Tailscale sidecar + +## Configuration Overview + +Sure is a **multi-container application**. This stack runs the following services on a dedicated `sure_net` Docker bridge network alongside the Tailscale sidecar: + +- **web** โ€“ the main Rails web application (`ghcr.io/we-promise/sure:stable`), serving the Sure UI on port `3000`. +- **worker** โ€“ a Sidekiq background worker (same image, run with `bundle exec sidekiq`) that processes asynchronous jobs. +- **db** โ€“ a PostgreSQL 16 database storing all Sure data. +- **redis** โ€“ a Redis instance used as the Sidekiq queue and cache. +- **backup** *(optional, behind the `backup` profile)* โ€“ a scheduled PostgreSQL backup container. + +The `tailscale` service authenticates to your Tailnet and provides the private network endpoint. The `web` and `worker` containers share the Tailscale container's network namespace using Docker's `network_mode: service:tailscale` pattern, so they reach the Tailnet directly and publish no ports to the host. + +### Hybrid networking + +This stack uses a hybrid networking approach so that Tailscale and Sure's support containers can coexist: + +- `web` and `worker` use `network_mode: service:tailscale` (Tailnet-only). +- `db`, `redis`, and `backup` run on the `sure_net` bridge network with static IPs. +- The `tailscale` container is attached to `sure_net` so its network namespace can reach the database and Redis. + +Because **MagicDNS is enabled** (`TS_ACCEPT_DNS=true`), Tailscale overrides Docker's embedded DNS inside the `web`/`worker` namespace. This means `web` and `worker` **cannot resolve container names** like `db` or `redis`, so they connect to the database and Redis using their static IPs (`DB_HOST=172.28.0.10`, `REDIS_URL=redis://172.28.0.11:6379/1`) defined in the `.env` file. The `backup` container sits directly on `sure_net`, so it can still use Docker DNS (`POSTGRES_HOST=db`). + +## Tailscale Serve + +The included serve config makes the Sure web UI available over HTTPS on your Tailnet. No host ports are published, so Sure remains reachable only through your Tailnet via the Tailscale hostname or Tailnet IP assigned to the sidecar. + +## Before You Start + +Review and edit the `.env` file before launching the stack. Several values must be set correctly for the app to run and to remain secure: + +- **`TS_AUTHKEY`** โ€“ required; generate an auth key at . +- **`SECRET_KEY_BASE`** โ€“ required and **empty by default**. Generate a unique value with `openssl rand -hex 64` and paste it. +- **`POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB`** โ€“ the defaults (`sure_user` / `sure_password` / `sure_production`) are placeholders and should be changed before deploying for production use. +- **`DB_HOST`, `REDIS_URL`, `POSTGRES_HOST`** โ€“ leave as-is unless you change the static IPs or network layout described above. +- **`TZ`** โ€“ set to your local time zone. + +### Bind mount directories + +The compose file bind-mounts several host directories. Pre-create them so Docker does not create them as root-owned: + +```bash +mkdir -p config ts/state app-storage postgres-data redis-data backups +``` + +## HTTPS / SSL Settings + +The `.env` ships with `RAILS_FORCE_SSL=true` and `RAILS_ASSUME_SSL=true`. Because Tailscale Serve terminates TLS in front of the app, `RAILS_ASSUME_SSL=true` is what tells Rails the connection is secure even though Serve forwards to it over plain HTTP on port `3000`. If you access Sure directly over HTTP through the Tailnet and encounter redirect issues, set both values back to `false`. + +## Troubleshooting + +If stock price or exchange-rate syncs fail with `Failed to open TCP connection to fc.yahoo.com`, DNS is likely resolving Yahoo Finance to IPv6 first, which the container can't reach. Upstream forces IPv4 DNS (`dns: [8.8.8.8, 1.1.1.1]`) on `web`/`worker`; this stack omits it because their DNS is handled by Tailscale (MagicDNS). For the recommended workarounds, see the note in the [Sure Docker self-hosting guide](https://github.com/we-promise/sure/blob/main/docs/hosting/docker.md). + +## Optional Integrations + +### OpenAI (AI features) + +Sure can use OpenAI for AI-powered features such as chat and rules. Set `OPENAI_ACCESS_TOKEN` in `.env` to enable it. **Enabling OpenAI will incur costs on your OpenAI account**, so set appropriate spend limits before adding it. See the [Sure AI documentation](https://github.com/we-promise/sure/blob/main/docs/hosting/ai.md). + +### OpenID Connect (OIDC) + +Sure supports OIDC for external authentication providers such as Google, GitHub, Keycloak, Authentik, Okta, or Azure AD. Fill in `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`, and `OIDC_REDIRECT_URI` in the `.env` file to enable it. The redirect URI should follow the pattern `https:///auth/openid_connect/callback`. See the [Sure OIDC documentation](https://github.com/we-promise/sure/blob/main/docs/hosting/oidc.md). + +### WebAuthn MFA (passkeys) + +If you enable passkeys, Touch ID, Windows Hello, or hardware security keys as MFA credentials, pin the WebAuthn relying party settings (`WEBAUTHN_RP_ID` and `WEBAUTHN_ALLOWED_ORIGINS`) in your environment before registering any passkeys. See the [WebAuthn configuration guide](https://github.com/we-promise/sure/blob/main/docs/hosting/webauthn.md). + +## Usage Notes + +Start the core stack with: + +```bash +docker compose up -d +``` + +On first launch, open the Sure URL on your Tailnet and click **create your account** to register the initial user. There are no default admin credentials โ€” the first account you create becomes your login. + +To run the optional scheduled database backups, include the backup profile: + +```bash +docker compose --profile backup up -d +``` + +Backups are written to the `./backups` directory by default; adjust the retention settings (`SCHEDULE`, `BACKUP_KEEP_DAYS`, `BACKUP_KEEP_WEEKS`, `BACKUP_KEEP_MONTHS`) in `.env` as needed. + +## References + +- [Sure Website](https://sure.am) +- [Sure GitHub Repository](https://github.com/we-promise/sure) +- [Sure Docker Self-Hosting Guide](https://github.com/we-promise/sure/blob/main/docs/hosting/docker.md) +- [Sure OIDC Documentation](https://github.com/we-promise/sure/blob/main/docs/hosting/oidc.md) +- [Sure AI Documentation](https://github.com/we-promise/sure/blob/main/docs/hosting/ai.md) +- [Sure WebAuthn Documentation](https://github.com/we-promise/sure/blob/main/docs/hosting/webauthn.md) +- [Tailscale Docker Documentation](https://tailscale.com/kb/1282/docker) diff --git a/services/sure/compose.yaml b/services/sure/compose.yaml new file mode 100755 index 0000000..c137346 --- /dev/null +++ b/services/sure/compose.yaml @@ -0,0 +1,169 @@ +configs: + ts-serve: + content: | + {"TCP":{"443":{"HTTPS":true}}, + "Web":{"$${TS_CERT_DOMAIN}:443": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:3000"}}}}, + "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}} + +services: +# Make sure you have updated/checked the .env file with the correct variables. +# All the ${ xx } need to be defined there. + # Tailscale Sidecar Configuration + tailscale: + image: tailscale/tailscale:latest # Image to be used + container_name: tailscale-${SERVICE} # Name for local container management + hostname: ${SERVICE} # Name used within your Tailscale environment + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz" + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The : for the healthz endpoint + - TS_ACCEPT_DNS=true # MagicDNS enabled + - TS_AUTH_ONCE=true + configs: + - source: ts-serve + target: /config/serve.json + volumes: + - ./config:/config # Config folder used to store Tailscale files - you may need to change the path + - ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path + devices: + - /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work + cap_add: + - net_admin # Tailscale requirement + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 10s # Time to wait before starting health checks + restart: always + networks: + sure_net: + ipv4_address: 172.28.0.2 + + web: + image: ghcr.io/we-promise/sure:stable + container_name: app-${SERVICE}-web + network_mode: service:tailscale + volumes: + - ./app-storage:/rails/storage + restart: unless-stopped + environment: + - POSTGRES_USER=${POSTGRES_USER:-sure_user} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-sure_password} + - POSTGRES_DB=${POSTGRES_DB:-sure_production} + - SECRET_KEY_BASE=${SECRET_KEY_BASE} + - SELF_HOSTED=${SELF_HOSTED:-true} + - RAILS_FORCE_SSL=${RAILS_FORCE_SSL:-false} + - RAILS_ASSUME_SSL=${RAILS_ASSUME_SSL:-false} + - DB_HOST=${DB_HOST:-172.28.0.10} + - DB_PORT=${DB_PORT:-5432} + - REDIS_URL=${REDIS_URL:-redis://172.28.0.11:6379/1} + - OPENAI_ACCESS_TOKEN=${OPENAI_ACCESS_TOKEN} # NOTE: enabling OpenAI will incur costs when you use AI-related features in the app (chat, rules). Make sure you have set appropriate spend limits on your account before adding this. + - OIDC_ISSUER=${OIDC_ISSUER} # Optional: OIDC issuer URL for authentication (e.g., https://accounts.google.com). If not set, OIDC authentication will be disabled. + - OIDC_CLIENT_ID=${OIDC_CLIENT_ID} # Optional: OIDC client ID for authentication. Required if OIDC_ISSUER is set. + - OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET} # Optional: OIDC client secret for authentication. Required if OIDC_ISSUER is set. + - OIDC_REDIRECT_URI=${OIDC_REDIRECT_URI} # Optional: OIDC redirect URI for authentication. Required if OIDC_ISSUER is set. + # BINDING: "::" # Uncomment for IPv6 dual-stack inside the container + depends_on: + tailscale: + condition: service_healthy + db: + condition: service_healthy + redis: + condition: service_healthy + + worker: + image: ghcr.io/we-promise/sure:stable + container_name: app-${SERVICE}-worker + network_mode: service:tailscale + command: bundle exec sidekiq + volumes: + - ./app-storage:/rails/storage + restart: unless-stopped + depends_on: + tailscale: + condition: service_healthy + db: + condition: service_healthy + redis: + condition: service_healthy + environment: + - POSTGRES_USER=${POSTGRES_USER:-sure_user} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-sure_password} + - POSTGRES_DB=${POSTGRES_DB:-sure_production} + - SECRET_KEY_BASE=${SECRET_KEY_BASE} + - SELF_HOSTED=${SELF_HOSTED:-true} + - RAILS_FORCE_SSL=${RAILS_FORCE_SSL:-false} + - RAILS_ASSUME_SSL=${RAILS_ASSUME_SSL:-false} + - DB_HOST=${DB_HOST:-172.28.0.10} + - DB_PORT=${DB_PORT:-5432} + - REDIS_URL=${REDIS_URL:-redis://172.28.0.11:6379/1} + - OPENAI_ACCESS_TOKEN=${OPENAI_ACCESS_TOKEN} # NOTE: enabling OpenAI will incur costs when you use AI-related features in the app (chat, rules). Make sure you have set appropriate spend limits on your account before adding this. + + db: + image: postgres:16 + container_name: app-${SERVICE}-db + restart: unless-stopped + volumes: + - ./postgres-data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=${POSTGRES_USER:-sure_user} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-sure_password} + - POSTGRES_DB=${POSTGRES_DB:-sure_production} + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB" ] + interval: 5s + timeout: 5s + retries: 5 + networks: + sure_net: + ipv4_address: 172.28.0.10 + + backup: + profiles: + - backup + image: prodrigestivill/postgres-backup-local + container_name: app-${SERVICE}-backup + restart: unless-stopped + volumes: + - ./backups:/backups # Change this path to your desired backup location on the host machine + environment: + - POSTGRES_HOST=${POSTGRES_HOST:-db} + - POSTGRES_DB=${POSTGRES_DB:-sure_production} + - POSTGRES_USER=${POSTGRES_USER:-sure_user} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-sure_password} # pipelock:ignore + - SCHEDULE=${SCHEDULE:-@daily} + - BACKUP_KEEP_DAYS=${BACKUP_KEEP_DAYS:-7} + - BACKUP_KEEP_WEEKS=${BACKUP_KEEP_WEEKS:-4} + - BACKUP_KEEP_MONTHS=${BACKUP_KEEP_MONTHS:-6} + depends_on: + - db + networks: + - sure_net + + redis: + image: redis:latest + container_name: app-${SERVICE}-redis + restart: unless-stopped + volumes: + - ./redis-data:/data + healthcheck: + test: [ "CMD", "redis-cli", "ping" ] + interval: 5s + timeout: 5s + retries: 5 + networks: + sure_net: + ipv4_address: 172.28.0.11 + +networks: + sure_net: + driver: bridge + ipam: + config: + - subnet: 172.28.0.0/16 From 5bfab48d937bfd11dc17deda5caa85bd9002dfca Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:26:04 +0200 Subject: [PATCH 07/11] Refactor .env configuration for the Sure service to improve clarity and organization --- services/sure/.env | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/services/sure/.env b/services/sure/.env index b229c1a..3e42df2 100755 --- a/services/sure/.env +++ b/services/sure/.env @@ -3,11 +3,23 @@ #COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure. # Service Configuration -SERVICE=sure # Service name used as hostname in Tailscale and for container naming (app-${SERVICE}) -TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +SERVICE=sure # Service name (e.g., adguard). Used as hostname in Tailscale and for container naming (app-${SERVICE}). +IMAGE_URL=ghcr.io/we-promise/sure:stable # Docker image URL from container registry (e.g., adguard/adguard-home). + +# Network Configuration +SERVICEPORT= # Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable. +DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable. # Tailscale Configuration -TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys +TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions. + +# Optional Service variables +# PUID=1000 + +#Time Zone setting for containers +TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +# Any Container environment variables are declared below. See https://docs.docker.com/compose/how-tos/environment-variables/ # Database (PostgreSQL) POSTGRES_USER=sure_user From b23df53f2a9474af830213da30d530350e2f415f Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:26:07 +0200 Subject: [PATCH 08/11] Update image references in compose.yaml to use dynamic IMAGE_URL variable --- services/sure/compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/sure/compose.yaml b/services/sure/compose.yaml index c137346..f92e681 100755 --- a/services/sure/compose.yaml +++ b/services/sure/compose.yaml @@ -46,7 +46,7 @@ services: ipv4_address: 172.28.0.2 web: - image: ghcr.io/we-promise/sure:stable + image: ${IMAGE_URL} # Image to be used container_name: app-${SERVICE}-web network_mode: service:tailscale volumes: @@ -78,7 +78,7 @@ services: condition: service_healthy worker: - image: ghcr.io/we-promise/sure:stable + image: ${IMAGE_URL} # Image to be used container_name: app-${SERVICE}-worker network_mode: service:tailscale command: bundle exec sidekiq From 08accf28b8eea6fc5e135953ce23cd72012d08da Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:26:10 +0200 Subject: [PATCH 09/11] Remove Tailscale Serve section from README.md for clarity --- services/sure/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/services/sure/README.md b/services/sure/README.md index 4aa53d0..e271c3e 100644 --- a/services/sure/README.md +++ b/services/sure/README.md @@ -41,10 +41,6 @@ This stack uses a hybrid networking approach so that Tailscale and Sure's suppor Because **MagicDNS is enabled** (`TS_ACCEPT_DNS=true`), Tailscale overrides Docker's embedded DNS inside the `web`/`worker` namespace. This means `web` and `worker` **cannot resolve container names** like `db` or `redis`, so they connect to the database and Redis using their static IPs (`DB_HOST=172.28.0.10`, `REDIS_URL=redis://172.28.0.11:6379/1`) defined in the `.env` file. The `backup` container sits directly on `sure_net`, so it can still use Docker DNS (`POSTGRES_HOST=db`). -## Tailscale Serve - -The included serve config makes the Sure web UI available over HTTPS on your Tailnet. No host ports are published, so Sure remains reachable only through your Tailnet via the Tailscale hostname or Tailnet IP assigned to the sidecar. - ## Before You Start Review and edit the `.env` file before launching the stack. Several values must be set correctly for the app to run and to remain secure: From 8da2c6ff0dff035a7186ef087b481d4e8ac1c7b3 Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:28:38 +0200 Subject: [PATCH 10/11] Set default SERVICEPORT in .env for network configuration --- services/sure/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/sure/.env b/services/sure/.env index 3e42df2..0cd788e 100755 --- a/services/sure/.env +++ b/services/sure/.env @@ -7,7 +7,7 @@ SERVICE=sure # Service name (e.g., adguard). Used as hostname in Tailscale and f IMAGE_URL=ghcr.io/we-promise/sure:stable # Docker image URL from container registry (e.g., adguard/adguard-home). # Network Configuration -SERVICEPORT= # Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable. +SERVICEPORT=3000 # Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable. DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable. # Tailscale Configuration From 791c49a62da2e4f2422f99a907c1d72ee174f98b Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Sat, 27 Jun 2026 20:29:52 +0200 Subject: [PATCH 11/11] Add BentoPDF and Formbricks to the services list in README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a7c0394..a005b6e 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | ๐Ÿ’ฐ **Actual Budget** | A self-hosted personal finance and budgeting app focused on privacy and full data ownership. | [Details](services/actual-budget) | | โš“ **Anchor** | An offline-first, self-hosted note-taking app with sync, attachments, sharing, and optional OIDC authentication. | [Details](services/anchor) | +| ๐Ÿ“„ **BentoPDF** | A lightweight, self-hosted web app for viewing and managing PDF documents. | [Details](services/bentopdf) | | โœ‚๏ธ **ClipCascade** | A self-hosted clipboard manager for syncing and organizing clipboard history. | [Details](services/clipcascade) | | ๐Ÿ—‚๏ธ **Copyparty** | A self-hosted file server with accelerated resumable uploads. | [Details](services/copyparty) | | โœ… **Donetick** | A self-hosted task and checklist manager for productivity. | [Details](services/donetick) | @@ -134,6 +135,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | ๐Ÿ“ **Excalidraw** | A virtual collaborative whiteboard tool. | [Details](services/excalidraw) | | ๐Ÿ“ **Flatnotes** | A simple, self-hosted note-taking app using Markdown files. | [Details](services/flatnotes) | | ๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ป **Forgejo** | A community-driven, self-hosted Git service. | [Details](services/forgejo) | +| ๐Ÿ“‹ **Formbricks** | A self-hosted, open-source platform for collecting user feedback, surveys, and NPS. | [Details](services/formbricks) | | ๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ป **Gitea** | A lightweight, self-hosted Git service with repository hosting, pull requests, and issue tracking. | [Details](services/gitea) | | โœ๏ธ **Ghost** | A modern, open-source publishing platform for blogs and newsletters. | [Details](services/ghost) | | ๐Ÿง‘โ€๐Ÿง‘โ€๐Ÿง’โ€๐Ÿง’ **Gramps Web** | A web-based genealogy platform for collaborative family tree browsing, editing, AI-powered chat, media tagging, mapping, charts, search, and reporting. | [Details](services/grampsweb) | @@ -153,8 +155,6 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | ๐Ÿ“ **Seafile** | A self-hosted file syncing and collaboration platform with file sharing, versioning, and team library support. | [Details](services/seafile) | | ๐Ÿ—‚๏ธ **Stirling-PDF** | A web application for managing and editing PDF files. | [Details](services/stirlingpdf) | | ๐Ÿ’ฐ **Sure Finance** | A self-hosted personal finance and budgeting app with optional AI insights. | [Details](services/sure) | -| ๐Ÿ“„ **BentoPDF** | A lightweight, self-hosted web app for viewing and managing PDF documents. | [Details](services/bentopdf) | -| ๐Ÿ“‹ **Formbricks** | A self-hosted, open-source platform for collecting user feedback, surveys, and NPS. | [Details](services/formbricks) | | ๐Ÿฆ **Subtrackr** | A self-hosted web app to track subscriptions, renewal dates, costs, and payment methods. | [Details](services/subtrackr) | | ๐Ÿ—ƒ๏ธ **Vaultwarden** | An unofficial Bitwarden server implementation written in Rust. | [Details](services/vaultwarden) | | โœ… **Vikunja** | A self-hosted task and project management platform with projects, reminders, labels, recurring tasks, and collaboration features. | [Details](services/vikunja) |