From 62885afd1abdd4ef5324412bc78dc4b41daea2f2 Mon Sep 17 00:00:00 2001 From: Jack Spiering <46534141+jackspiering@users.noreply.github.com> Date: Tue, 13 Oct 2026 23:23:13 +0200 Subject: [PATCH 1/2] Gotify: add optional iGotify container --- services/gotify/.env | 10 ++++++++++ services/gotify/README.md | 26 +++++++++++++++++++++++++- services/gotify/compose.yaml | 25 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/services/gotify/.env b/services/gotify/.env index bb456dc9..56c7ada5 100644 --- a/services/gotify/.env +++ b/services/gotify/.env @@ -23,4 +23,14 @@ TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_tim # Required: password of the user admin that Gotify creates at the first start. GOTIFY_DEFAULTUSER_PASS= +# Optional: set to igotify to also start the iGotify container for the iOS app, see the README. +COMPOSE_PROFILES= + +# iGotify Configuration (only used with the igotify profile) +IGOTIFY_IMAGE_URL=ghcr.io/androidseb25/igotify-notification-assist:latest +# Set the next three values together, after you set up the iGotify app, see the README. +GOTIFY_URLS= +GOTIFY_CLIENT_TOKENS= +SECNTFY_TOKENS= + #EXAMPLE_VAR="Environment variable" diff --git a/services/gotify/README.md b/services/gotify/README.md index ec75f073..3034406d 100644 --- a/services/gotify/README.md +++ b/services/gotify/README.md @@ -12,6 +12,8 @@ This stack runs Gotify with a Tailscale sidecar, as described in [the standard s | Service port | `80` | | Image | `gotify/server` | | Data | `./gotify-data/app/data` | +| iGotify image | `ghcr.io/androidseb25/igotify-notification-assist` (optional) | +| iGotify data | `./gotify-data/igotify` (optional) | ## Before you start @@ -19,7 +21,8 @@ Set `GOTIFY_DEFAULTUSER_PASS` in `.env`. It is the password of the user `admin` ## Deviations from the standard setup -None. +- **Optional iGotify container.** The Compose service `igotify` (container `app-gotify-igotify`) only runs when the `igotify` profile is active. It shares the network of the Tailscale sidecar, like the application, and stores its data in `./gotify-data/igotify`. See [iGotify for iPhone and iPad](#igotify-for-iphone-and-ipad). +- **iGotify port.** iGotify listens on port `8080` for its API and device pages. Tailscale Serve does not publish it, but it is reachable at the Tailscale IP address of the device when your Tailnet policy allows it. ## First run @@ -31,7 +34,28 @@ In the Gotify app, use `https://gotify..ts.net` as the server address. Earlier versions of this stack set `GOTIFY_DEFAULTUSER_PASS=admin` in `compose.yaml`. The value is now empty in `.env`, and Compose stops with an error until you set it. Gotify reads it only at the first start, so a new value does not change the password of an existing installation. If you still log in as `admin` with the password `admin`, change the password in the web interface. +## Configuration + +### iGotify for iPhone and iPad + +Gotify has no iOS app. [iGotify](https://github.com/androidseb25/iGotify-Notification-Assistent) fills that gap: the optional `igotify` container listens to Gotify and forwards each message to the iGotify app on your iPhone or iPad. + +Notifications leave your Tailnet on this route. iGotify encrypts each message and sends it over HTTPS to the SecNtfy relay of its author, which hands it to Apple's push service. Skip this section when you do not want that. + +The stack uses the "local instance" mode of iGotify, so Gotify stays reachable only through your Tailnet. In this mode the app talks to Gotify directly, and the images of apps and contacts do not show in the iGotify app. + +1. Start the stack as usual and install the [iGotify app](https://apps.apple.com/app/igotify/id6473452512) on a device that is connected to your Tailnet. +2. In the app, enter `https://gotify..ts.net`, turn on the Local Instance toggle, and log in with your Gotify account. The app then shows three values: the Gotify URL, the Gotify client token, and the SecNtfy token. +3. In `.env`, set `COMPOSE_PROFILES=igotify`, and fill in `GOTIFY_CLIENT_TOKENS` and `SECNTFY_TOKENS` with the values from the app. Set `GOTIFY_URLS=http://127.0.0.1:80` instead of the URL that the app shows: the iGotify container shares the network of the Tailscale sidecar and cannot resolve the MagicDNS name, but it reaches Gotify on the loopback address. The three values go together: if one is missing, the connection fails. +4. Apply the change with `docker compose up -d`. + +The two tokens are secrets, so keep them out of anything you publish. Keep `COMPOSE_PROFILES=igotify` in `.env` as long as you use iGotify: without it, `docker compose down` and `docker compose pull` skip the `igotify` container. + +To stop using iGotify, run `docker compose --profile igotify down`, empty `COMPOSE_PROFILES` in `.env`, and run `docker compose up -d`. A plain `docker compose down` leaves the `igotify` container behind once the profile is no longer active. + ## Links - [Gotify documentation](https://gotify.net/docs/) - [Gotify source code](https://github.com/gotify/server) +- [iGotify documentation](https://github.com/androidseb25/iGotify-Notification-Assistent/wiki) +- [iGotify source code](https://github.com/androidseb25/iGotify-Notification-Assistent) diff --git a/services/gotify/compose.yaml b/services/gotify/compose.yaml index 9f32c2c8..4529e80b 100644 --- a/services/gotify/compose.yaml +++ b/services/gotify/compose.yaml @@ -62,3 +62,28 @@ services: condition: service_healthy # Healthcheck: defined by the image (curl against /health), so this file does not override it. restart: always + + # Optional iGotify container: forwards Gotify messages to the iGotify iOS app. Start it with the igotify profile. + igotify: + profiles: + - igotify + image: ${IGOTIFY_IMAGE_URL} # Image to be used + network_mode: service:tailscale # Sidecar configuration to route the service through Tailscale + container_name: app-${SERVICE}-igotify # Name for local container management + environment: + - GOTIFY_URLS=${GOTIFY_URLS:-} + - GOTIFY_CLIENT_TOKENS=${GOTIFY_CLIENT_TOKENS:-} + - SECNTFY_TOKENS=${SECNTFY_TOKENS:-} + - TZ=${TZ} + volumes: + - ./${SERVICE}-data/igotify:/app/data + depends_on: + application: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-fs", "http://127.0.0.1:8080/Version"] # The image has no HEALTHCHECK, so call the version endpoint of iGotify + 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 From 7572c7883d446eb4160888333ec8cce1e9462d23 Mon Sep 17 00:00:00 2001 From: Jack Spiering <46534141+jackspiering@users.noreply.github.com> Date: Thu, 15 Oct 2026 14:48:28 +0200 Subject: [PATCH 2/2] Gotify: pre-fill GOTIFY_URLS for iGotify --- services/gotify/.env | 5 +++-- services/gotify/README.md | 2 +- services/gotify/compose.yaml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/services/gotify/.env b/services/gotify/.env index 56c7ada5..4938e214 100644 --- a/services/gotify/.env +++ b/services/gotify/.env @@ -28,8 +28,9 @@ COMPOSE_PROFILES= # iGotify Configuration (only used with the igotify profile) IGOTIFY_IMAGE_URL=ghcr.io/androidseb25/igotify-notification-assist:latest -# Set the next three values together, after you set up the iGotify app, see the README. -GOTIFY_URLS= +# Address at which iGotify reaches Gotify. Keep it: iGotify shares the network of the Tailscale sidecar and reaches Gotify on the loopback address. +GOTIFY_URLS=http://127.0.0.1:80 +# Set the next two values after you set up the iGotify app, see the README. GOTIFY_CLIENT_TOKENS= SECNTFY_TOKENS= diff --git a/services/gotify/README.md b/services/gotify/README.md index 3034406d..d902cf08 100644 --- a/services/gotify/README.md +++ b/services/gotify/README.md @@ -46,7 +46,7 @@ The stack uses the "local instance" mode of iGotify, so Gotify stays reachable o 1. Start the stack as usual and install the [iGotify app](https://apps.apple.com/app/igotify/id6473452512) on a device that is connected to your Tailnet. 2. In the app, enter `https://gotify..ts.net`, turn on the Local Instance toggle, and log in with your Gotify account. The app then shows three values: the Gotify URL, the Gotify client token, and the SecNtfy token. -3. In `.env`, set `COMPOSE_PROFILES=igotify`, and fill in `GOTIFY_CLIENT_TOKENS` and `SECNTFY_TOKENS` with the values from the app. Set `GOTIFY_URLS=http://127.0.0.1:80` instead of the URL that the app shows: the iGotify container shares the network of the Tailscale sidecar and cannot resolve the MagicDNS name, but it reaches Gotify on the loopback address. The three values go together: if one is missing, the connection fails. +3. In `.env`, set `COMPOSE_PROFILES=igotify`, and fill in `GOTIFY_CLIENT_TOKENS` and `SECNTFY_TOKENS` with the values from the app. Keep `GOTIFY_URLS=http://127.0.0.1:80` instead of the URL that the app shows: the iGotify container shares the network of the Tailscale sidecar and cannot resolve the MagicDNS name, but it reaches Gotify on the loopback address. The three values go together: if one is missing, the connection fails. 4. Apply the change with `docker compose up -d`. The two tokens are secrets, so keep them out of anything you publish. Keep `COMPOSE_PROFILES=igotify` in `.env` as long as you use iGotify: without it, `docker compose down` and `docker compose pull` skip the `igotify` container. diff --git a/services/gotify/compose.yaml b/services/gotify/compose.yaml index 4529e80b..0f207d9e 100644 --- a/services/gotify/compose.yaml +++ b/services/gotify/compose.yaml @@ -71,7 +71,7 @@ services: network_mode: service:tailscale # Sidecar configuration to route the service through Tailscale container_name: app-${SERVICE}-igotify # Name for local container management environment: - - GOTIFY_URLS=${GOTIFY_URLS:-} + - GOTIFY_URLS=${GOTIFY_URLS:-http://127.0.0.1:80} # Gotify on the loopback address of the shared network - GOTIFY_CLIENT_TOKENS=${GOTIFY_CLIENT_TOKENS:-} - SECNTFY_TOKENS=${SECNTFY_TOKENS:-} - TZ=${TZ}