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 install
inside the project directory. - Rename the
wrangler-sample.toml
file towrangler.toml
. - Read these instructions to customize the proxy.
- Run
npm run authorize
to authorize your Cloudflare connection. - Finally, run
npm run deploy
to 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 = "2024-02-22"
############
## 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 = true
To 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 file
Note: 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-url
setting. - The
behind-proxy
setting is set totrue
. - The
attachment-cache-dir
setting.- 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-limit
to 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
mode
to"send-once"
. - To send a single message to all matched servers, set
mode
to"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_https
setting totrue
. - To display response output, set the
show_response_output
totrue
. - To reveal visitor information, set the
show_visitor_info
totrue
.
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
routes
section, 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
routes
section, 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_domain
is set tofalse
).- This is because the proxy matches the first part of the hostname with the subdomain value (e.g.
abcde.ntfy.example.com
will matchabcde
) defined in the servers list in yourwrangler.toml
file.
- 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.