-
-
Notifications
You must be signed in to change notification settings - Fork 20
Home
Here you will find introductions and guides to get start contributing the iGotify Notification Assistent
It's a small notification assistent that encrypt the message and trigger a push notifications to iOS devices via Apple's APNs with my developed service SecNtfy.
SecNtfy will be available for public later this year.
The app to receiving the gotify notification you can download here or via the download badge.
<<<<<<< HEAD
┌─────────────┐ WebSocket ┌──────────────────────┐ HTTPS ┌─────────────┐ APNs ┌─────────────┐
│ Gotify │ ──────────────▶ │ iGotify Assistant │ ───────────▶ │ SecNtfy │ ─────────▶ │ iOS Device │
│ Server │ │ (Notification Relay) │ │ Service │ │ (iGotify) │
└─────────────┘ └──────────────────────┘ └─────────────┘ └─────────────┘
- Gotify receives a notification (e.g., from your server, automation, or app)
- iGotify Assistant connects to Gotify via WebSocket and listens for new messages
- When a message arrives, it encrypts and forwards it to SecNtfy
- SecNtfy sends a push notification through Apple's APNs to your iOS device
- The iGotify app receives and displays the notification
Note
Privacy at SecNtfy: SecNtfy only stores anonymized data (such as device tokens). The payload (your actual notification content) is never stored - it is forwarded 1:1 to Apple's APNs and immediately discarded.
iGotify uses multiple tokens to identify devices and connections:
| Token | Purpose |
|---|---|
| NTFY-Device Token | Unique identifier for your physical device (iPhone/iPad). Generated when you first register a device. |
| Client Token | Gotify client token. Generated for each Gotify instance you connect to. |
These tokens are stored in the iGotify Assistant database along with the Gotify URL for the WebSocket connection.
Adding a second Gotify account on the same device:
- You receive a new Client Token from Gotify
- Your NTFY-Device Token stays the same (same physical device)
- In the database, your NTFY-Device Token appears twice - once for each Gotify client
- You'll receive notifications from both Gotify instances on the same device
Multiple users (different devices):
- Each device gets its own unique NTFY-Device Token
- Each user has their own Client Token(s) for their Gotify connection(s)
- Notifications are routed to the correct device based on the NTFY-Device Token
You can run iGotify in two modes:
| Mode | Description | Pros | Cons |
|---|---|---|---|
| Local Instance | The iOS app communicates directly with Gotify through your local network | Lower latency, no need to expose iGotify port (8681) externally | App/contact images don't work (app can't access internal Gotify URLs for icons) |
| External Instance | The iOS app communicates through the iGotify Assistant | App/contact images work, accessible from anywhere | Requires exposing port 8681, slightly higher latency |
Tip
Use local instance if you primarily use iGotify within your home network and don't need app icons in notifications. Use external instance if you want full functionality including images, or need access from outside your network.
- Docker and Docker Compose (latest version recommended)
- A
docker-compose.yamlfile
| Variable | Description | Default |
|---|---|---|
GOTIFY_DEFAULTUSER_PASS |
Password for the default user | - |
GOTIFY_URLS |
Gotify server URLs (e.g., http://gotify or https://mygotify.domain.tld) |
- |
GOTIFY_CLIENT_TOKENS |
Client tokens from Gotify (e.g., cXXXXXXXX) |
- |
SECNTFY_TOKENS |
SecNtfy tokens from the app (e.g., NTFY-DEVICE-XXXXXX) |
- |
ENABLE_CONSOLE_LOG |
Enable/disable console logging | true |
ENABLE_SCALAR_UI |
Enable/disable the API endpoint page | true |
Note
GOTIFY_URLS, GOTIFY_CLIENT_TOKENS, and SECNTFY_TOKENS are only required when Gotify and iGotify are not accessible via a public domain. If both services are available over a domain, these can be left empty.
Warning
If you set any of the three variables (GOTIFY_URLS, GOTIFY_CLIENT_TOKENS, SECNTFY_TOKENS), you must set all three. If any value is missing, the connection will fail.
You can configure multiple Gotify instances by separating values with a semicolon ;:
GOTIFY_URLS='http://gotify;http://gotify2;http://gotify3'
GOTIFY_CLIENT_TOKENS='cXXXXXXXX1;cXXXXXXXX2;cXXXXXXXX3'
SECNTFY_TOKENS='NTFY-DEVICE-XXXXXX1;NTFY-DEVICE-XXXXXX2;NTFY-DEVICE-XXXXXX3'Tip
All configuration values are displayed in the iOS app after setup.
Create a .env file in the same directory as your docker-compose.yaml:
# .env
# Required
GOTIFY_DEFAULTUSER_PASS=my-very-strong-password
# Connection settings (only required if NOT using a public domain)
# Examples for GOTIFY_URLS:
# Internal: http://gotify (container name / local DNS)
# External: https://mygotify.domain.tld
# For multiple instances, separate with semicolons
GOTIFY_URLS=
GOTIFY_CLIENT_TOKENS=
SECNTFY_TOKENS=
# Optional (write boolean values in single quotes)
ENABLE_CONSOLE_LOG='true'
ENABLE_SCALAR_UI='true'Important
- Change the password to a secure one before starting the stack!
- Make sure to set proper permissions:
chmod 600 .env
Note
The iGotify port (8681) only needs to be exposed if you are not using a local instance in the iOS app setup. When using a local instance, the app communicates directly with Gotify and does not need external access to iGotify.
Standard
services:
gotify:
container_name: gotify
hostname: gotify
image: gotify/server # Uncomment correct server image
# image: gotify/server-arm7
# image: gotify/server-arm64
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- net
ports:
- "8680:80"
volumes:
- data:/app/data
environment:
GOTIFY_DEFAULTUSER_PASS: ${GOTIFY_DEFAULTUSER_PASS}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
igotify:
container_name: igotify
hostname: igotify
image: ghcr.io/androidseb25/igotify-notification-assist
restart: unless-stopped
security_opt:
- no-new-privileges:true
depends_on:
gotify:
condition: service_healthy
networks:
- net
ports:
- "8681:8080"
volumes:
- api-data:/app/data
environment:
GOTIFY_URLS: ${GOTIFY_URLS}
GOTIFY_CLIENT_TOKENS: ${GOTIFY_CLIENT_TOKENS}
SECNTFY_TOKENS: ${SECNTFY_TOKENS}
ENABLE_CONSOLE_LOG: ${ENABLE_CONSOLE_LOG}
ENABLE_SCALAR_UI: ${ENABLE_SCALAR_UI}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/Version"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
networks:
net:
volumes:
data:
api-data:Thanks to The_Think3r and @herrpandora
With Traefik
services:
gotify:
container_name: gotify
hostname: gotify
image: gotify/server
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- net
- proxy
ports:
- "8680:80"
volumes:
- data:/app/data
environment:
GOTIFY_DEFAULTUSER_PASS: ${GOTIFY_DEFAULTUSER_PASS}
GOTIFY_REGISTRATION: 'false'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
labels:
traefik.docker.network: proxy
traefik.enable: "true"
traefik.http.routers.gotify-secure.entrypoints: websecure
traefik.http.routers.gotify-secure.middlewares: default@file
traefik.http.routers.gotify-secure.rule: Host(`gotify.domain-name.de`)
traefik.http.routers.gotify-secure.service: gotify
traefik.http.routers.gotify-secure.tls: "true"
traefik.http.routers.gotify-secure.tls.certresolver: http_resolver
traefik.http.routers.gotify.entrypoints: web
traefik.http.routers.gotify.rule: Host(`gotify.domain-name.de`)
traefik.http.services.gotify.loadbalancer.server.port: "80"
igotify:
container_name: igotify
hostname: igotify
image: ghcr.io/androidseb25/igotify-notification-assist
restart: unless-stopped
security_opt:
- no-new-privileges:true
depends_on:
gotify:
condition: service_healthy
networks:
- net
- proxy
ports:
- "8681:8080"
volumes:
- api-data:/app/data
environment:
GOTIFY_URLS: ${GOTIFY_URLS}
GOTIFY_CLIENT_TOKENS: ${GOTIFY_CLIENT_TOKENS}
SECNTFY_TOKENS: ${SECNTFY_TOKENS}
ENABLE_CONSOLE_LOG: ${ENABLE_CONSOLE_LOG}
ENABLE_SCALAR_UI: ${ENABLE_SCALAR_UI}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/Version"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
labels:
traefik.docker.network: proxy
traefik.enable: "true"
traefik.http.routers.igotify-secure.entrypoints: websecure
traefik.http.routers.igotify-secure.middlewares: default@file
traefik.http.routers.igotify-secure.rule: Host(`igotify.domain-name.de`)
traefik.http.routers.igotify-secure.service: igotify
traefik.http.routers.igotify-secure.tls: "true"
traefik.http.routers.igotify-secure.tls.certresolver: http_resolver
traefik.http.routers.igotify.entrypoints: web
traefik.http.routers.igotify.rule: Host(`igotify.domain-name.de`)
traefik.http.services.igotify.loadbalancer.server.port: "8080"
networks:
net:
proxy:
external: true
volumes:
data:
api-data:Thanks to @majo1989
docker compose up -dYou can run the assistant as a service on any Linux distribution using the install script.
Note
Thanks to @nicedevil007 for writing the original installation guide.
Warning
After updating your distribution, check if the iGotify service is running.
| Distribution | Package Manager | Init System |
|---|---|---|
| Debian / Ubuntu | apt | systemd |
| RHEL / CentOS / Fedora | dnf / yum | systemd |
| Alpine | apk | OpenRC |
Run the following command as root:
curl -sSL https://github.com/androidseb25/iGotify-Notification-Assistent/raw/branch/main/install.sh | bashOr download and review the script first:
curl -sSL https://github.com/androidseb25/iGotify-Notification-Assistent/raw/branch/main/install.sh -o install.sh
chmod +x install.sh
./install.shView install script
#!/bin/bash
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}=== iGotify Notification Assistent Installer ===${NC}"
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Please run as root${NC}"
exit 1
fi
# Detect distribution
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
DISTRO=$ID
elif [ -f /etc/alpine-release ]; then
DISTRO="alpine"
else
echo -e "${RED}Unsupported distribution${NC}"
exit 1
fi
echo -e "${GREEN}Detected distribution: ${DISTRO}${NC}"
}
# Detect init system
detect_init() {
if command -v systemctl &> /dev/null && systemctl --version &> /dev/null; then
INIT_SYSTEM="systemd"
elif command -v rc-service &> /dev/null; then
INIT_SYSTEM="openrc"
else
echo -e "${RED}Unsupported init system${NC}"
exit 1
fi
echo -e "${GREEN}Detected init system: ${INIT_SYSTEM}${NC}"
}
# Install dependencies
install_deps() {
echo -e "${YELLOW}Installing dependencies...${NC}"
case $DISTRO in
alpine)
apk update
apk add libstdc++ icu-libs curl bash unzip
;;
debian|ubuntu)
apt-get update
apt-get install -y curl unzip libicu-dev
;;
rhel|centos|fedora|rocky|almalinux)
if command -v dnf &> /dev/null; then
dnf install -y curl unzip libicu
else
yum install -y curl unzip libicu
fi
;;
*)
echo -e "${RED}Unsupported distribution: ${DISTRO}${NC}"
exit 1
;;
esac
echo -e "${GREEN}Dependencies installed${NC}"
}
# Install .NET
install_dotnet() {
echo -e "${YELLOW}Installing .NET 10.0...${NC}"
export DOTNET_ROOT=/opt/dotnet
mkdir -p $DOTNET_ROOT
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin -c 10.0 --install-dir $DOTNET_ROOT
# Create symlink for system-wide access
ln -sf $DOTNET_ROOT/dotnet /usr/local/bin/dotnet
echo -e "${GREEN}.NET installed: $(dotnet --version)${NC}"
}
# Download and install iGotify
install_igotify() {
echo -e "${YELLOW}Downloading iGotify...${NC}"
RELEASE=$(curl -s https://api.github.com/repos/androidseb25/iGotify-Notification-Assistent/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
echo -e "${GREEN}Latest version: v${RELEASE}${NC}"
cd /tmp
rm -f igotify.zip
curl -sSL -o igotify.zip "https://github.com/androidseb25/iGotify-Notification-Assistent/releases/download/v${RELEASE}/iGotify-Notification-Service-amd64-v${RELEASE}.zip"
# Remove old installation if exists
[ -d /opt/iGotify ] && rm -rf /opt/iGotify
mkdir -p /opt/iGotify
unzip -q igotify.zip -d /opt/iGotify
rm -f igotify.zip
echo -e "${GREEN}iGotify installed to /opt/iGotify${NC}"
}
# Setup systemd service
setup_systemd() {
echo -e "${YELLOW}Setting up systemd service...${NC}"
DOTNET_PATH=$(command -v dotnet || echo "/opt/dotnet/dotnet")
cat <<EOF >/etc/systemd/system/iGotify.service
[Unit]
Description=iGotify Notification Assistent
After=network.target
[Service]
WorkingDirectory=/opt/iGotify
ExecStart=${DOTNET_PATH} '/opt/iGotify/iGotify Notification Assist.dll'
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=igotify
Environment="ASPNETCORE_ENVIRONMENT=Production"
Environment="ASPNETCORE_URLS=http://0.0.0.0:8681"
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable iGotify.service
systemctl start iGotify.service
echo -e "${GREEN}Systemd service created and started${NC}"
}
# Uninstall iGotify
uninstall() {
echo -e "${YELLOW}Uninstalling iGotify...${NC}"
detect_init
# Stop and disable service
if [ "$INIT_SYSTEM" = "systemd" ]; then
systemctl stop iGotify.service 2>/dev/null || true
systemctl disable iGotify.service 2>/dev/null || true
rm -f /etc/systemd/system/iGotify.service
systemctl daemon-reload
else
service iGotify stop 2>/dev/null || true
rc-update del iGotify default 2>/dev/null || true
rm -f /etc/init.d/iGotify
fi
# Remove iGotify
[ -d /opt/iGotify ] && rm -rf /opt/iGotify
echo -e "${GREEN}iGotify removed${NC}"
# Ask about .NET
echo ""
read -p "Remove .NET runtime from /opt/dotnet? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf /opt/dotnet
rm -f /usr/local/bin/dotnet
echo -e "${GREEN}.NET removed${NC}"
fi
echo ""
echo -e "${GREEN}=== Uninstallation complete ===${NC}"
}
# Setup OpenRC service
setup_openrc() {
echo -e "${YELLOW}Setting up OpenRC service...${NC}"
DOTNET_PATH=$(command -v dotnet || echo "/opt/dotnet/dotnet")
cat <<EOF >/etc/init.d/iGotify
#!/sbin/openrc-run
export ASPNETCORE_URLS="http://0.0.0.0:8681"
export ASPNETCORE_ENVIRONMENT=Production
export DOTNET_ROOT=/opt/dotnet
name="iGotify Notification Assistent"
description="iGotify Notification Service"
supervisor="supervise-daemon"
pidfile="/var/run/iGotify.pid"
command="${DOTNET_PATH}"
command_args="'/opt/iGotify/iGotify Notification Assist.dll'"
command_user="root:root"
depend() {
need net
}
EOF
chmod +x /etc/init.d/iGotify
rc-update add iGotify default
service iGotify start
echo -e "${GREEN}OpenRC service created and started${NC}"
}
# Main installation
install() {
detect_distro
detect_init
install_deps
install_dotnet
install_igotify
if [ "$INIT_SYSTEM" = "systemd" ]; then
setup_systemd
else
setup_openrc
fi
echo ""
echo -e "${GREEN}=== Installation complete ===${NC}"
echo -e "iGotify is now running on port 8681"
echo ""
echo -e "Check status:"
if [ "$INIT_SYSTEM" = "systemd" ]; then
echo -e " systemctl status iGotify"
else
echo -e " service iGotify status"
fi
}
# Parse arguments
case "${1:-}" in
--uninstall|-u)
uninstall
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --uninstall, -u Uninstall iGotify"
echo " --help, -h Show this help"
echo ""
echo "Without options, the script will install iGotify."
;;
*)
install
;;
esacTo remove iGotify, run:
curl -sSL https://github.com/androidseb25/iGotify-Notification-Assistent/raw/branch/main/install.sh | bash -s -- --uninstallOr if you have the script locally:
./install.sh --uninstall# Systemd
systemctl status iGotify
# OpenRC
service iGotify status# Check dotnet version (must be 10.x)
dotnet --version
# Run in foreground for more debug info
export ASPNETCORE_URLS="http://0.0.0.0:8681"
export ASPNETCORE_ENVIRONMENT=Production
dotnet '/opt/iGotify/iGotify Notification Assist.dll'If you're running iGotify behind a reverse proxy, you may need additional configuration.
If you have problems with incoming notifications, add these options under "Advanced Settings":
proxy_set_header Host $http_host;
proxy_connect_timeout 1m;
proxy_send_timeout 1m;
proxy_read_timeout 1m;Important
Do not check the boxes "HTTP/2 Support" and "HSTS enabled".
Thanks to @TBT-TBT
| Status | Feature | Issue |
|---|---|---|
| 🏁 Progress finished | Custom Notifications | #45 |
| 🏁 Progress finished | Local Docker Network Option | #59 |
| 🏁 Progress finished | App and Contact Images for Notifications | #64 |
| 🏁 Progress finished | FaceID Implementation | #62 |
| 📝 Planned | macOS Native Application | #47 |
Want to help or found a bug?
Read the Contributing Guide.
- RPICloud (German): iGotify Installation
- Gotify on Proxmox 8.1 with iGotify setup: homelab.casaursus.net (Thanks to @nallej)
Created a tutorial or review? Open an issue with the title [REFERENCE] <TITLE> and the URL.
79f8ce5 (Updated Home (markdown))