install.md 19 KB

Installing ntfy

The ntfy CLI allows you to publish messages, subscribe to topics as well as to self-host your own ntfy server. It's all pretty straight forward. Just install the binary, package or Docker image, configure it and run it. Just like any other software. No fuzz.

!!! info

The following steps are only required if you want to **self-host your own ntfy server or you want to use the ntfy CLI**.
If you just want to [send messages using ntfy.sh](publish.md), you don't need to install anything. You can just use
`curl`.

General steps

The ntfy server comes as a statically linked binary and is shipped as tarball, deb/rpm packages and as a Docker image. We support amd64, armv7 and arm64.

  1. Install ntfy using one of the methods described below
  2. Then (optionally) edit /etc/ntfy/server.yml for the server (Linux only, see configuration or sample server.yml)
  3. Or (optionally) create/edit ~/.config/ntfy/client.yml (or /etc/ntfy/client.yml, see sample client.yml)

To run the ntfy server, then just run ntfy serve (or systemctl start ntfy when using the deb/rpm). To send messages, use ntfy publish. To subscribe to topics, use ntfy subscribe (see [subscribing via CLI][subscribe/cli.md] for details).

Linux binaries

Please check out the releases page for binaries and deb/rpm packages.

=== "x86_64/amd64"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_x86_64.tar.gz
tar zxvf ntfy_1.28.0_linux_x86_64.tar.gz
sudo cp -a ntfy_1.28.0_linux_x86_64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_1.28.0_linux_x86_64/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```

=== "armv6"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_armv6.tar.gz
tar zxvf ntfy_1.28.0_linux_armv6.tar.gz
sudo cp -a ntfy_1.28.0_linux_armv6/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_1.28.0_linux_armv6/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```

=== "armv7/armhf"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_armv7.tar.gz
tar zxvf ntfy_1.28.0_linux_armv7.tar.gz
sudo cp -a ntfy_1.28.0_linux_armv7/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_1.28.0_linux_armv7/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```

=== "arm64"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_arm64.tar.gz
tar zxvf ntfy_1.28.0_linux_arm64.tar.gz
sudo cp -a ntfy_1.28.0_linux_arm64/ntfy /usr/bin/ntfy
sudo mkdir /etc/ntfy && sudo cp ntfy_1.28.0_linux_arm64/{client,server}/*.yml /etc/ntfy
sudo ntfy serve
```

Debian/Ubuntu repository

Installation via Debian repository:

=== "x86_64/amd64"

```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
    > /etc/apt/sources.list.d/archive.heckel.io.list"  
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

=== "armv7/armhf"

```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=armhf signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
    > /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

=== "arm64"

```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=arm64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
    > /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

Manually installing the .deb file:

=== "x86_64/amd64"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_amd64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

=== "armv6"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_armv6.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

=== "armv7/armhf"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_armv7.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

=== "arm64"

```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_arm64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

Fedora/RHEL/CentOS

=== "x86_64/amd64"

```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_amd64.rpm
sudo systemctl enable ntfy 
sudo systemctl start ntfy
```

=== "armv6"

```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_armv6.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```

=== "armv7/armhf"

```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_armv7.rpm
sudo systemctl enable ntfy 
sudo systemctl start ntfy
```

=== "arm64"

```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_linux_arm64.rpm
sudo systemctl enable ntfy 
sudo systemctl start ntfy
```

Arch Linux

ntfy can be installed using an AUR package. You can use an AUR helper like paru, yay or others to download, build and install ntfy and keep it up to date.

paru -S ntfysh-bin

Alternatively, run the following commands to install ntfy manually:

curl https://aur.archlinux.org/cgit/aur.git/snapshot/ntfysh-bin.tar.gz | tar xzv
cd ntfysh-bin
makepkg -si

NixOS / Nix

ntfy is packaged in nixpkgs as ntfy-sh. It can be installed by adding the package name to the configuration file and calling nixos-rebuild. Alternatively, the following command can be used to install ntfy in the current user environment:

nix-env -iA ntfy-sh

macOS

The ntfy CLI (ntfy publish and ntfy subscribe only) is supported on macOS as well. To install, please download the tarball, extract it and place it somewhere in your PATH (e.g. /usr/local/bin/ntfy).

If run as root, ntfy will look for its config at /etc/ntfy/client.yml. For all other users, it'll look for it at ~/Library/Application Support/ntfy/client.yml (sample included in the tarball).

curl -L https://github.com/binwiederhier/ntfy/releases/download/v1.28.0/ntfy_1.28.0_macOS_all.tar.gz > ntfy_1.28.0_macOS_all.tar.gz
tar zxvf ntfy_1.28.0_macOS_all.tar.gz
sudo cp -a ntfy_1.28.0_macOS_all/ntfy /usr/local/bin/ntfy
mkdir ~/Library/Application\ Support/ntfy 
cp ntfy_1.28.0_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
ntfy --help

!!! info

There is a [GitHub issue](https://github.com/binwiederhier/ntfy/issues/286) about making ntfy installable via
[Homebrew](https://brew.sh/). I'll eventually get to that, but I'd also love if somebody else stepped up to do it. 
Also, you can build and run the ntfy server on macOS as well, though I don't officially support that. 
Check out the [build instructions](develop.md) for details.

Windows

The ntfy CLI (ntfy publish and ntfy subscribe only) is supported on Windows as well. To install, please download the latest ZIP, extract it and place the ntfy.exe binary somewhere in your %Path%.

The default path for the client config file is at %AppData%\ntfy\client.yml (not created automatically, sample in the ZIP file).

Also available in Scoop's Main repository:

scoop install ntfy

!!! info

There is currently no installer for Windows, and the binary is not signed. If this is desired, please create a
[GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know.

Docker

The ntfy image is available for amd64, armv6, armv7 and arm64. It should be pretty straight forward to use.

The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent message cache, you also need to map a volume to /var/cache/ntfy. To change other settings, you should map /etc/ntfy, so you can edit /etc/ntfy/server.yml.

!!! info

Note that the Docker image **does not contain a `/etc/ntfy/server.yml` file**. If you'd like to use a config file, 
please manually create one outside the image and map it as a volume, e.g. via `-v /etc/ntfy:/etc/ntfy`. You may
use the [`server.yml` file on GitHub](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml) as a template.

Basic usage (no cache or additional config):

docker run -p 80:80 -it binwiederhier/ntfy serve

With persistent cache (configured as command line arguments):

docker run \
  -v /var/cache/ntfy:/var/cache/ntfy \
  -p 80:80 \
  -it \
  binwiederhier/ntfy \
    serve \
    --cache-file /var/cache/ntfy/cache.db

With other config options, timezone, and non-root user (configured via /etc/ntfy/server.yml, see configuration for details):

docker run \
  -v /etc/ntfy:/etc/ntfy \
  -e TZ=UTC \
  -p 80:80 \
  -u UID:GID \
  -it \
  binwiederhier/ntfy \
  serve

Using docker-compose with non-root user:

version: "2.1"

services:
  ntfy:
    image: binwiederhier/ntfy
    container_name: ntfy
    command:
      - serve
    environment:
      - TZ=UTC    # optional: set desired timezone
    user: UID:GID # optional: replace with your own user/group or uid/gid
    volumes:
      - /var/cache/ntfy:/var/cache/ntfy
      - /etc/ntfy:/etc/ntfy
    ports:
      - 80:80
    restart: unless-stopped

If using a non-root user when running the docker version, be sure to chown the server.yml, user.db, and cache.db files to the same uid/gid.

Alternatively, you may wish to build a customized Docker image that can be run with fewer command-line arguments and without delivering the configuration file separately.

FROM binwiederhier/ntfy
COPY server.yml /etc/ntfy/server.yml
ENTRYPOINT ["ntfy", "serve"]

This image can be pushed to a container registry and shipped independently. All that's needed when running it is mapping ntfy's port to a host port.

Kubernetes

The setup for Kubernetes is very similar to that for Docker, and requires a fairly minimal deployment or pod definition to function. There are a few options to mix and match, including a deployment without a cache file, a stateful set with a persistent cache, and a standalone unmanaged pod.

Deployment

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ntfy
    spec:
      selector:
        matchLabels:
          app: ntfy
      template:
        metadata:
          labels:
            app: ntfy
        spec:
          containers:
          - name: ntfy
            image: binwiederhier/ntfy
            args: ["serve"]
            resources:
              limits:
                memory: "128Mi"
                cpu: "500m"
            ports:
            - containerPort: 80
              name: http
            volumeMounts:
            - name: config
              mountPath: "/etc/ntfy"
              readOnly: true
          volumes:
            - name: config
              configMap:
                name: ntfy
    ---
    # Basic service for port 80
    apiVersion: v1
    kind: Service
    metadata:
      name: ntfy
    spec:
      selector:
        app: ntfy
      ports:
      - port: 80
        targetPort: 80

Stateful set

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: ntfy
    spec:
      selector:
        matchLabels:
          app: ntfy
      serviceName: ntfy
      template:
        metadata:
          labels:
            app: ntfy
        spec:
          containers:
          - name: ntfy
            image: binwiederhier/ntfy
            args: ["serve", "--cache-file /var/cache/ntfy/cache.db"]
            ports:
            - containerPort: 80
              name: http
            volumeMounts:
            - name: config
              mountPath: "/etc/ntfy"
              readOnly: true
          volumes:
            - name: config
              configMap:
                name: ntfy
      volumeClaimTemplates:
      - metadata:
          name: cache
        spec:
          accessModes: [ "ReadWriteOnce" ]
          resources:
            requests:
              storage: 1Gi

Pod

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        app: ntfy
    spec:
      containers:
      - name: ntfy
        image: binwiederhier/ntfy
        args: ["serve"]
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80
          name: http
        volumeMounts:
        - name: config
          mountPath: "/etc/ntfy"
          readOnly: true
      volumes:
        - name: config
          configMap:
            name: ntfy

Configuration is relatively straightforward. As an example, a minimal configuration is provided.

Resource definition

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ntfy
    data:
    server.yml: |
        # Template: https://github.com/binwiederhier/ntfy/blob/main/server/server.yml
        base-url: https://ntfy.sh

from-file

    kubectl create configmap ntfy --from-file=server.yml 

Kustomize-based deployment with persistent storage and Traefik ingress

Kustomize allows for deploying templated configurations in easy way

Kustomization

Create new folder, name it nfty and create kustomization.yaml within along all resources listed below. Ingress is optional - you can skip this one if planning to expose service using different service type (hash it out from kustomization file)


apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ntfy-deployment.yaml # main deployment
  - ntfy-svc.yaml # service connecting two pods together
  - ntfy-pvc.yaml # pvc uset to store cache and attachment
  - ntfy-ingress.yaml # ingress traefik

configMapGenerator: # will parse config from raw config to configmap,it allows for dynamic reload of application if additional app is deployed ie https://github.com/stakater/Reloader
    - name: server-config
      files: 
        - server.yml

namespace: TESTNAMESPACE # select namaespace for whole application 

----

apiVersion: kustomize.config.k8s.io/v1beta1 #local resources
kind: Kustomization
resources:
  - git@github.com:gituser/kustomize.git/kustomize/main/ #WIP when complete config will be stored in repo 

namespace: TESTNAMESPACE # select namaespace for whole application 

ntfy-deployment.yaml


apiVersion: apps/v1
kind: Deployment
metadata:
  name: ntfy-deployment
  labels:
    app: ntfy-deployment
spec:
  revisionHistoryLimit: 1
  replicas: 1
  selector:
    matchLabels:
      app: ntfy-pod
  template:
    metadata:
      labels:
        app: ntfy-pod
    spec:
      containers:
        - name: ntfy 
          image: binwiederhier/ntfy:v1.28.0 # select version here latest is not the greatest idea !
          args: ["serve"]
          env:  #example of adjustments made in environmental variables
            - name: TZ # set timezone
              value: XXXXXXX
            - name: NTFY_DEBUG # enable/disable debug
              value: "false"
            - name: NTFY_LOG_LEVEL # adjust log level
              value: INFO
            - name: NTFY_BASE_URL # add base url
              value: XXXXXXXXXX 
          ports: 
            - containerPort: 80
              name: http-ntfy
          resources:
            limits:
              memory: 300Mi
              cpu:  200m
            requests:
                  cpu: 150m
                  memory: 150Mi
          volumeMounts:
            - mountPath: /etc/ntfy/server.yml
              subPath: server.yml
              name: config-volume # generated vie configMapGenerator from kustomization file
            - mountPath: /var/cache/ntfy
              name: cache-volume #cache volume mounted to persistent volume
      volumes:
        - name: config-volume
          configMap:  # uses configmap generator to parse server.yml to configmap
            name: server-config
        - name: cache-volume
          persistentVolumeClaim: # stores /cache/ntfy in defined pv
            claimName: ntfy-pvc

ntfy-pvc.yaml

Stores all in cache folder for event of the pod re-deployment

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ntfy-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path # adjust storage if needed
  resources:
    requests:
      storage: 1Gi

ntfy-svc.yaml

Exposes pod to internal network of the cluster

apiVersion: v1
kind: Service
metadata:
  name: ntfy-svc  
spec:
  type: ClusterIP
  selector:
    app: ntfy-pod
  ports:
    - name: http-ntfy-out
      protocol: TCP
      port: 80
      targetPort:  http-ntfy

ntfy-ingress.yaml

If cluster uses Ingress controller you have to deploy ingress to access application externally. It will not have TLS/SSL enabled so you have to deploy cert-manager and generate CA cert along certificate for service

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ntfy-ingress
spec:
  rules:
    - host: ntfy.test #select own
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name:  ntfy-svc
                port:
                  number: 80

server.yml

cache-file: "/var/cache/ntfy/cache.db"
attachment-cache-dir: "/var/cache/ntfy/attachments"

Deploying from kustomization

Go one level up from folder where all resources were created and apply configuration

kubectl apply -k /nfty