Skip to content

Create a self-hosted instance of NTFY

Moved Guides
  • First, devise a naming convention for your NTFY installation. This ideally should be a subdomain as it means you can logically and physically separate your main instance of NodeBB (for example) and make it work independently. This is highly recommended, as we will be using a reverse proxy to setup NTFY and some of those settings differ to what NodeBB already uses.

    First, choose a subdomain you’d like to use – in my case, this will be notify.sudonix.org, and will point to the same IP address as the server hosting my NodeBB installation. You’ll obviously need to make changes to your DNS so that this works as intended. If you are using Cloudflare, you must disable the proxy.

    0358aa66-573d-408b-adfc-dd33b58f1166-image.png

    Allow sufficient time for the DNS to replicate fully. I typically set a low TTL (Time To Live) where possible, and CF allows you to set as low as 60 seconds. You can check on DNS population progress using one of the many checkers available - this one is my go-to

    https://www.whatsmydns.net/

    Now that your DNS record has populated, you can start working on the NTFY build.

    Depending on the version of Linux (or even Windows) you are using, there are a multitude of different packages you can use, including those maintained by Ubuntu / Debian themselves. For the purposes of this guide, I’m assuming Ubuntu / Debian, and this means you should use the below (as root)

    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
    

    At this point, we could run ntfy serve although this will start the communication on port 80 which isn’t what we want because it will conflict with NGINX, so we will need to change the port

    sudo nano /etc/ntfy/server.yml
    

    Make the below changes, obviously substituting my any details with your own

    # All the things: Behind a proxy, Firebase, cache, attachments, 
    # SMTP publishing & receiving
    
    base-url: "https://<your domain fqdn>"
    listen-http: "127.0.0.1:2586"
    cache-file: "/var/cache/ntfy/cache.db"
    behind-proxy: true
    attachment-cache-dir: "/var/cache/ntfy/attachments"
    keepalive-interval: "45s"
    

    Note that if you need to support iOS based devices, you must add the below directly under the base-url: line

    upstream-base-url: "https://ntfy.sh"
    

    Now issue ntfy serve and ensure that the instance starts with the correct port

    04cdabe2-0aba-4b73-a1b9-bece9edf2f36-image.png

    A sample of the NGINX configuration will look like this

    server {
        listen <your ip address>;
        server_name <your server name>;
        root <path to your home directory>
        location / {
            # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want 
            # it to work with curl without the annoying https:// prefix
            set $redirect_https "";
            if ($request_method = GET) {
                set $redirect_https "yes";
            }
            if ($request_uri ~* "^/([-_a-z0-9]{0,64}$|docs/|static/)" ) {
                set $redirect_https "${redirect_https}yes";
            }
            if ($redirect_https = "yesyes" ) {
                return 302 https://$http_host$request_uri$is_args$query_string;
            }
    
            proxy_pass http://127.0.0.1:2586;
            proxy_http_version 1.1;
    
            proxy_buffering off;
            proxy_request_buffering off;
            proxy_redirect off;
    
            proxy_set_header Host $http_host;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
            proxy_connect_timeout 3m;
            proxy_send_timeout 3m;
            proxy_read_timeout 3m;
    
            client_max_body_size 0; # Stream request body to backend
        }
        ssl_certificate /home/sudonix.org/ssl.cert;
        ssl_certificate_key /home/sudonix.org/ssl.key;
    }
    
    server {
        listen <your ip address>:443 ssl http2;
        server_name notify.sudonix.org;
        root <path to your home directory>
        # See https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6see https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6
        ssl_session_timeout 1d;
        ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
        ssl_session_tickets off;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
    
        ssl_certificate <path yo your certificate file>
        ssl_certificate_key <path yo your certificate key>
    
        location / {
            proxy_pass http://127.0.0.1:2586;
            proxy_http_version 1.1;
    
            proxy_buffering off;
            proxy_request_buffering off;
            proxy_redirect off;
    
            proxy_set_header Host $http_host;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
            proxy_connect_timeout 3m;
            proxy_send_timeout 3m;
            proxy_read_timeout 3m;
    
            client_max_body_size 0; # Stream request body to backend
        }
    }
    

    Obviously, you need to supply the information requested in <your information> as this pertains to your installation. Now save your config, ensure there are no errors, and in the console, issue ntfy serve. Now browse to the URL you want to use, and you should see something like the below

    caaebe69-0017-42ed-9828-4b78971319cd-image.png

    In the ACP, go to Plugins -> NTFY, and set your NTFY URL

    6ea26962-b6f9-4021-893b-0324fc044d99-image.png

    Note, that the Access Token isn’t mandatory, but is a good idea to secure the stream. You can generate your own (64bit) here. Use the format in NodeBB as tk_<token>

    https://it-tools.tech/token-generator

    Click Save Changes, and restart NodeBB

    Now go your profile settings in NodeBB and select “Push Notifications”

    aea5d7be-b4e2-4cd0-a5e7-2aade84c0fc9-image.png

    Copy “Private Push Link” and then go to your NTFY self-hosted instance - note, you’ll also see that there is a “Subscribe” button which you can use if you prefer, but you’ll need the latest version of nodebb-plugin-ntfy installed.

    Click “Subscribe to a topic”

    104f493d-c616-40a8-b2ed-54b7cf359a44-image.png

    Paste the value you copied previously

    9baf0d3b-632c-4b56-b71f-4801e42c0246-image.png

    Click Subscribe

    Now go back to your user settings, and click “Send test notification”

    82d8f381-028d-43cd-9ceb-b2206ec4b6ec-image.png

    Ensure you see the message appear in your new instance

    2cb45232-251a-4292-830f-2d727cf947bc-image.png

    The message should have arrived! If it has, then you’re done.

    Well - almost. There is a raft of settings you can apply, such as tokens, ACL’s etc - the guide is very verbose and goes into specific detail, which you can review here

    IMPORTANT: if you are using a mobile device, you should install the dedicated apps for Android and iOS rather than use the web versions.

    https://docs.ntfy.sh/

  • phenomlabundefined phenomlab referenced this topic on
  • @phenomlab said in Create a self-hosted instance of NTFY:

    base-url: "https://ntfy.sh"

    Again, thank you very much for the guide!

    I’m asking myself if the base-url should be set to our new subdomain (“ntfy.my-domain.com”)?

  • @dave1904 yes, sorry. I’ll amend the original post.

  • @phenomlab Any idea why I get this message in any browser trying to access ntfy.mynodebb.com?:

    ntfy.mynodebb.com uses a security technology called “HTTP Strict Transport Security (HSTS)”, by which Firefox is allowed to connect to the website only through secured connections. Therefore, no exception can be added for the website.

    That’s my server.conf (part of):

    server {
        server_name ntfy.mynodebb.com;
    
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Host $http_host;
            proxy_set_header X-NginX-Proxy true;
            proxy_pass http://127.0.0.1:2586;
            proxy_redirect off;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    
        listen 443 ssl;
        ssl_certificate /etc/letsencrypt/live/mynodebb-0001/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mynodebb-0001/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    }
    
  • @dave1904 do you get the same if you prefix the site with https:// ?

  • @phenomlab yes, it will be forwarded in any case

  • @dave1904 are you using Cloudflare?

  • @phenomlab No, I don’t. What I’m not sure of is the root <path to your home directory>. I didn’t set this because I’m not sure where to point.

  • @dave1904 you should use the full path to the subdomain, so for example /home/domain/subdomains/my.subdomain.com

    Also, have you started ntfy ? (I may have missed that step…)

  • I don’t have a folder for my subdomain. What I did was create a new A-Record on DigitalOcean. ntfy is installed on/etc/ntfy. Then I edited the config as in your example and configured nginx.

    Yes, ntfy is serving.

  • @dave1904 it looks like the cert being offered is self signed. How did you apply the LetsEncrypt certificate?

  • Ohh yes it could be that I have to configure Certbot

  • It’s working now! 🎊 Really missed that point 😄

  • @dave1904 good news. Easily missed!

  • Is it possible to directly open the link associated with a notification? It feels like a detour to me to first open ntfy and then to click on the link. So basically click notification -> go to website

  • @dave1904 that’s exactly how it works for me? If I click the notification itself, it opens the link to the post directly - admittedly, in a new browser window, but if does work.

  • Ok, I have to check this again.
    Chat message notifications aren’t working for me at the Moment, can you confirm this?

  • @dave1904 they work fine for me?

  • @phenomlab Sorry, I was too tired this night. 😄 I upgraded to @1.7.3 and it seems to work now. Only thing I’m still struggling with is to set my own icon in the ACP. It doesn’t seem to be changed here