Skip to main content

nginx/Apache2/caddy

For your convenience, here's a working config that'll help configure things behind a proxy. Be sure to enable WebSockets by forwarding the Connection and Upgrade headers accordingly.

In this example, ntfy runs on :2586 and we proxy traffic to it. We also redirect HTTP to HTTPS for GET requests against a topic or the root domain:

NGinx
# /etc/nginx/sites-*/ntfy
#
# This config allows insecure HTTP POST/PUT requests against topics to allow a short curl syntax (without -L
# and "https://" prefix). It also disables output buffering, which has worked well for the ntfy.sh server.
#
# This is pretty much how ntfy.sh is configured. To see the exact configuration,
# see https://github.com/binwiederhier/ntfy-ansible/

server {
  listen 80;
  server_name ntfy.sh;

  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
  }
}

server {
  listen 443 ssl http2;
  server_name ntfy.sh;

  # 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 /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;

  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
  }
}
NGinx (more secure)
# /etc/nginx/sites-*/ntfy
#
# This config requires the use of the -L flag in curl to redirect to HTTPS, and it keeps nginx output buffering
# enabled. While recommended, I have had issues with that in the past.

server {
  listen 80;
  server_name ntfy.sh;

  location / {
    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_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
  }
}

server {
  listen 443 ssl http2;
  server_name ntfy.sh;

  # 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 /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;

  location / {
    proxy_pass http://127.0.0.1:2586;
    proxy_http_version 1.1;

    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
  }
}
Apache
# /etc/apache2/sites-*/ntfy.conf

<VirtualHost *:80>
    ServerName ntfy.sh

    # Proxy connections to ntfy (requires "a2enmod proxy proxy_http")
    ProxyPass / http://127.0.0.1:2586/ upgrade=websocket
    ProxyPassReverse / http://127.0.0.1:2586/

    SetEnv proxy-nokeepalive 1
    SetEnv proxy-sendchunked 1

    # Higher than the max message size of 4096 bytes
    LimitRequestBody 102400

    # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want 
    # it to work with curl without the annoying https:// prefix (requires "a2enmod alias")
    <If "%{REQUEST_METHOD} == 'GET'">
        RedirectMatch permanent "^/([-_A-Za-z0-9]{0,64})$" "https://%{SERVER_NAME}/$1"
    </If>

</VirtualHost>

<VirtualHost *:443>
    ServerName ntfy.sh

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/ntfy.sh/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ntfy.sh/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # Proxy connections to ntfy (requires "a2enmod proxy proxy_http")
    ProxyPass / http://127.0.0.1:2586/ upgrade=websocket
    ProxyPassReverse / http://127.0.0.1:2586/

    SetEnv proxy-nokeepalive 1
    SetEnv proxy-sendchunked 1

    # Higher than the max message size of 4096 bytes 
    LimitRequestBody 102400

</VirtualHost>
Caddy
ntfy.sh, http://nfty.sh {
    reverse_proxy 127.0.0.1:2586

    # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
    # it to work with curl without the annoying https:// prefix
    @httpget {
        protocol http
        method GET
        path_regexp ^/([-_a-z0-9]{0,64}$|docs/|static/)
    }
    redir @httpget https://{host}{uri}
}