Receive push notifications on one or more ntfy server instances, ensuring redundancy and synchronized communications, all fortified with the added security layer provided by Cloudflare.
To use this reverse proxy, here are some steps to follow:
- Run
npm installinside the project directory. - Rename the
wrangler-sample.tomlfile towrangler.toml. - Read these instructions to customize the proxy.
- Run
npm run authorizeto authorize your Cloudflare connection. - Finally, run
npm run deployto deploy your changes.
Here is an example of how the wrangler.toml file for this reverse proxy should be configured:
name = "ntfy-reverse-proxy"
main = "src/index.ts"
compatibility_date = "2025-01-21"
############
## Routes ##
############
routes = [
{ pattern = "abcde.ntfy.example.com", custom_domain = true },
{ pattern = "12345.ntfy.example.com", custom_domain = true },
]
###################
## Vars: Servers ##
###################
[vars.servers]
mode = "send-once"
list = [
{ subdomain = "abcde", topic = "topic-1", server = "https://server-1-ntfy.sh", token = "tk_m61tag95tx" },
{ subdomain = "abcde", topic = "topic-1", server = "https://server-2-ntfy.sh", token = "tk_mdo4e750xv" },
{ subdomain = "12345", topic = "topic-2", server = "https://server-1-ntfy.sh", token = "tk_m61tag95tx" },
{ subdomain = "12345", topic = "topic-2", server = "https://server-2-ntfy.sh", token = "tk_mdo4e750xv" },
]
####################
## Vars: Settings ##
####################
[vars.settings]
force_https = true
show_response_output = true
show_visitor_info = trueTo route messages through the proxy back to your local ntfy servers, initiate a POST or PUT request with the specified configuration. Please note that sending via the GET method or using a body with JSON is not supported. Here's an example using the default configuration shown above:
POST https://abcde.ntfy.example.com
User-Agent: custom-user-agent
body - can be plain text or a binary fileNote: Please be mindful of the limits imposed by Cloudflare, which are subject to your account's plan. To learn how to filter out unwanted spam and bad traffic, read the Limiting Bad Traffic section below.
The proxy seamlessly integrates with the following headers. These headers, each serving a specific purpose, will be forwarded to the ntfy servers when making requests.
For in-depth configuration instructions, consult the ntfy documentation using the links provided below:
| Headers (A to C) | Headers (C to D) | Headers (E to F) | Headers (I to P) | Headers (T to U) |
|---|---|---|---|---|
| X-Actions | X-Call | X-Email | X-Icon | X-Tags |
| X-Attach | X-Click | X-Filename | X-Markdown | X-Title |
| X-Cache | X-Delay | X-Firebase | X-Priority | X-UnifiedPush |
Note: If the show_visitor_info setting is set to false and an attempt to send requests that includes both the X-Attach header and binary in the body (e.g. an image file), an error will be returned. Please be aware that this is a user error, not an implementation bug.
For optimal functionality, ensure that each ntfy server is defined with these settings below:
- The
base-urlsetting. - The
behind-proxysetting is set totrue. - The
attachment-cache-dirsetting.- Any message with a size limit of more than 4,096 bytes will be sent as attachments.
- If you would like to enforce text-only requests, customize the
attachment-file-size-limitto a smaller value of your preference. This ensures that any file exceeding this limit will fail to send.
Note: For your convenience, you may also refer to the default server.yml configuration, the ntfy Publishing documentation, and the ntfy Self-hosting Configuration documentation.
To specify a destination ntfy server, use the following settings:
- To send a single message to the first server with a success response, set
modeto"send-once". - To send a single message to all matched servers, set
modeto"send-all".
You have the flexibility to define multiple servers for redundancy or opt for a single ntfy server. For a server to match, the URL should begin with the subdomain listed in the servers list. For example:
A URL with abcde.ntfy.example.com would match servers that have the abcde in the subdomain value:
[vars.servers]
mode = "send-once"
list = [
{ subdomain = "abcde", topic = "topic-1", server = "https://server-1-ntfy.sh", token = "tk_m61tag95tx" },
{ subdomain = "abcde", topic = "topic-1", server = "https://server-2-ntfy.sh", token = "tk_mdo4e750xv" },
]A URL with 12345.ntfy.example.com would match servers that have the 12345 in the subdomain value:
[vars.servers]
mode = "send-once"
list = [
{ subdomain = "12345", topic = "topic-2", server = "https://server-1-ntfy.sh", token = "tk_m61tag95tx" },
{ subdomain = "12345", topic = "topic-2", server = "https://server-2-ntfy.sh", token = "tk_mdo4e750xv" },
]Important: Do not forget to set the routes in the wrangler.toml configuration as well. This will help automate the creation of the subdomain when deploying the proxy to Cloudflare.
Note: Only token authentication is supported. You may create tokens using the ntfy command line.
The proxy offers additional settings that might be of interest to you. Here are the available settings:
- To enforce HTTPS, set the
force_httpssetting totrue. - To display response output, set the
show_response_outputtotrue. - To reveal visitor information, set the
show_visitor_infototrue.
By default, the show_response_output setting is set to true to assist with initial setup, but please exercise caution as this setting is designed primarily for debugging purposes. It is recommended to set this to false to avoid exposing excessive information that could compromise the proxy's protections.
When the show_visitor_info is set to true, a section called « Incoming Request Details » will appear. This section shows the user's IP address, location (region, country, and colo code¹), approximate GPS coordinates, and Internet Service Provider (ISP) details (provider name and ASN).
¹ A colo code is used to mark which Cloudflare data center location served the traffic.
If the show_visitor_info is set to true and you send a binary file, you will receive two messages on every matched server for each request.
For instance, if you send one attachment, set the servers mode to send-all, and have two ntfy servers, you will receive four messages in total. To break it down:
- 1st message shows visitor information (2 copies, one for each matched server).
- 2nd message is reserved solely for the binary file (2 copies, one for each matched server).
Customizations made using headers will not be reflected in the 2nd message to prevent intentional duplication of message content and preferences.
This ensures that, for example, you do not receive repeated calls (if the X-Call header is set) or multiple long vibration bursts (if the X-Priority header is set to 5).
After deploying the proxy, there are a few more things to make sure your deployment is secure:
- Create a configuration rule.
- Set a custom filter expression to "partial match" your hostnames set in the
routessection, toggle off the Browser Integrity Check, and set Security Level to "Essentially Off". - This will help prevent legitimate API traffic from being mistakenly flagged with a 403 response. You will also need to create a WAF rule as well.
- Set a custom filter expression to "partial match" your hostnames set in the
- Create a WAF rule.
- Set the incoming traffic to "partial match" your hostnames set in the
routessection, and another rule to match what you would like to limit ("Country" and "User Agent" is a good starter).
- Set the incoming traffic to "partial match" your hostnames set in the
When deploying, there are a few things you need to be aware of:
- A domain name is required.
- You can conveniently register domains within Cloudflare at cost, without markup fees as seen with other domain registrars.
- Routes are not supported (when
custom_domainis set tofalse).- This is because the proxy matches the first part of the hostname with the subdomain value (e.g.
abcde.ntfy.example.comwill matchabcde) defined in the servers list in yourwrangler.tomlfile.
- This is because the proxy matches the first part of the hostname with the subdomain value (e.g.
If you find value in the ongoing development of this proxy and wish to express your appreciation, you have the option to become our supporter on GitHub Sponsors or make a one-time donation through PayPal.