How to setup push notification with Synapse and Element (or Element X) Android

Context

With the Arrival of Element X the new version of element for Android, users will need to have push notification configured correctly. For user which use Element X from Google play most of time it will work by default by using the google service for this. But for degooglised Android phone the question is generally be more complex. It’s why I wrote this tutorial to explain the context of this and the different possibility to setup a correct notification system.

Notification provider

There are several notification provider that we can use on Android. On this tutorial we will focus on ntfy which is one of the provider. This require to have the ntfy application installed on your phone and also a ntfy server. You can use the official ntfy server or self host the ntfy Yunohost application. Self hosting ntfy is the most complex setup and I’ll focus on this option.

Setup

Synapse configuration

You will need to configure synapse to allow to send request locally to ntfy. For this you can do it from the config panel in: “Advanced Settings” > “Security”. And then enable the parameter: “Allow synapse to send request to localhost”.

Ntfy setup

Firstly you will need to install the ntfy application if it’s not already done.

Then you will need to create an account for each users. You can do this by this command:

sudo -u ntfy /var/www/ntfy/ntfy.sh user add <username>

Then you will need to configure the Android app to use your ntfy server and use the user that you created previously. You can do this from the ntfy app settings in the “General” section.

You will also need to create a dedicated subject into your Android app for the Element notifications. For this the most simple solution would be to launch notification diagnosis into Element X settings. It will create a new notification subject if it’s not already created. You can do this from Element X, in the settings in > Notifications > troubleshooting notifications > run the tests.

After that you should have a last one topic into ntfy (in the Android app). For each topic linked to your self hosted server you will need to configure the rights with theses 2 commands:

# Allow the user to read/write notification
sudo -u ntfy /var/www/ntfy/ntfy.sh access <user> <topic> rw
# Allow everybody to write (needed by synapse to push notifications
sudo -u ntfy /var/www/ntfy/ntfy.sh access everyone <topic> write

# Optional, check all rights
sudo -u ntfy /var/www/ntfy/ntfy.sh access

After that you can run again the test notification from element X and everything should work.

Side note

It could happen that some others app add some new additional topic later. It was by example the case on my side with Tusky. In this case you might have some notification issue because ntfy will have some issue with the new registered topic which has not the right configured. In this case you will just need to configure for the new topic the right as described above. Just keep in mind that this could happen.

Side not for /e/ OS users

By default /e/ OS already integrate the ntfy application so you won’t need to install any additional apps. But the apps is hidden so it need some trick to configure it.

Firstly you will need to enable UnifiedPush (if not already done). For this, open the system settings > System > UnifiedPush. And then enable the button “Enable the distributor”.

At some point you will also need to open the ntfy app. Currently there are no way to open this directly from the UI so there are 2 solution that I found for this.

Use the activity manager application to create a new button

The most recommended solution would be to install the activity manager application. With this application you can create any new shortcut to open a lot of activity. With this application you can find the ntfy application (foundation.e.ntfy) and create a new shortcut to open the main activity from the main screen.

Open with ADB

An other solution would be to use ADB as described into this blog post. So just you just need to run this:

adb shell am start -n foundation.e.ntfy/io.heckel.ntfy.ui.MainActivity

And this will open the ntfy app provided by /e/ OS

10 Likes

Thanks a lot for this tutorial.
I have switched to a degoogled rom about a year ago. I installed FluffyChat, Element X, Schildichat and may be another app to choose from them. I settled with FluffyChat. I’ve also installed ntfy android app using the default server.
It worked fine a couple of months till I had to install fb messenger because at work and in our university all of the colleagues and collaborators use it, intensively :roll_eyes:. It’s like FluffyChat can’t run background.
New messages count gets updated only after opening the app.

1 Like

thanks for the /e/os tips

Thank you for this tutorial. Are there any security issues using the ntfy default server? Also can I use nfty for other apps like e.g Molly.IM or others?

Just adding some notes:
If your ntfy user is also the admin of the ntfy service there is no need to give rw rights to topics.

I had notification issues with some rooms, which were muted, and couldn’t unmute them from element x/schildichat next. Doing a little research I found out that push rules in synapse are set at server level, so if you mute or unmute a room it will be on every client used to access it.
For some reasons element x can’t revert the push rule if it has been set from element desktop (and I guess from element v1).
Aftet unmuting the rooms from my desktop client the setting propagated also to my element x client

Well, it depends what you mean by security issues. If you mean about the data privacy, yes it could. At last the notification is send to the default ntfy server.

Yes, you can. On my side I saw that tusky also use the push notification.

1 Like

Thks.

Is there a simpler globally way to make ntfy works without to enter inside this command line configurations ?
Its like complicated to ask for the topic name to my users to enable it on the command line.

To simplificate i put only

sudo -u ntfy /var/www/ntfy/ntfy.sh access everyone “up*” rw

as synapse need to write globally and every one need to read. Security keep on the fact that topics are randomly created and normal user will normally not share it.

For people who have set up a Nextcloud server alongside Synapse in Yunohost, the NextPush app requires minimal setup and works the same way.

Do they need to be on the same server? And is there a guide for using this with Synapse? Thanks

I personally have both on the same server, but I don’t think it’s required. I have followed this guide to set it up: NextPush - Android | UnifiedPush (The website also has a guide for ntfy, the tool suggested by the original post).

EDIT: I realize I just shared the same link but no synapse-specific setup is required, it’s just a service pulling the updates for you.

Sorry if I’m being stupid but I can’t figure out how to actually tell my matrix server to use the NextPush gateway?

I’m quite positive you don’t. The push server acts as a proxy for the client and use client-fed information to the server. There is however a setting in synapse to control how much information is transmitted to the push server: it is in the web YunoHost interface under the label “Disable content sharing inside push notification”.

That’s what I hoped - and that’s how it works with Molly (Signal FOSS with UnifiedPush)

When I run troubleshoot notifications on Element X it shows the test push gateway as matrix.gateway.unifiedpush.org

It only errors on the final ‘Test push loop back’ which it says ‘pusher has rejected the request’

I whitelisted the IP of the NextPush server too

Edit: Not sure what happened but this suddently started working on its own

Considering a main use-case in which an /e/OS smartphone is already synced with a nextcloud_ynh instance. Which would be the pros and cons of the possible setups :

  • ntfy_ynh on YunoHost Server and foundation.e.ntfy on smartphone
  • UnifiedPush App for nextcloud_ynh on YunoHost Server and nextpush on smartphone
  • keep /e/OS setup with ntfy.sh server and foundation.e.ntfy on smartphone. Configure communication between synapse, mollysocket and ntfy.sh

See How to provide UnifiedPush notifications to a smartphone with /e/OS · Issue #2686 · YunoHost/issues · GitHub

Thanks for this tutorial! I followed it and after browsing the other topics on ntfy + Element on the forum, decided to add an extra security layer via nginx that others might find useful.


What’s different from the original tutorial:

The main addition is an nginx restriction that ensures only localhost (Synapse) can POST to UnifiedPush topics. Without this, anyone on the internet who discovers a UP topic name could send you spam notifications. With this setup, the random topic name is still secret, but even if discovered, external POST requests are blocked.


Steps:

1. Create user accounts as above. Configure this account in the ntfy Android app settings.

Note: YunoHost LDAP users don’t work with ntfy, this is an upstream ntfy limitation (no LDAP support). For multiple users, create separate ntfy accounts as the original tutorial suggests: sudo -u ntfy /var/www/ntfy/ntfy.sh user add <username>

2. Fix authentication through YunoHost’s proxy (required for the Android app to log in):

yunohost app setting ntfy protect_against_basic_auth_spoofing -v false
yunohost app ssowatconf

3. Allow UnifiedPush topic writes:

sudo -u ntfy /var/www/ntfy/ntfy.sh access everyone 'up*' write

4. nginx restriction (the main security addition).

Create /etc/nginx/conf.d/ntfy.yourdomain.tld.d/unifiedpush.conf:

# UnifiedPush topics - POST from localhost only
location ~ ^/(up[a-zA-Z0-9_-]+)$ {
    limit_except GET HEAD OPTIONS {
        allow 127.0.0.1;
        allow ::1;
        deny all;
    }

    proxy_pass http://127.0.0.1:8081;
    include proxy_params_no_auth;

    more_set_input_headers 'Authorization: $http_authorization';
    proxy_set_header Authorization $http_authorization;

    proxy_buffering off;
    proxy_request_buffering off;
    proxy_redirect off;

    proxy_connect_timeout 3m;
    proxy_send_timeout 3m;
    proxy_read_timeout 3m;

    client_max_body_size 0;
}

# Matrix gateway - POST from localhost only
location = /_matrix/push/v1/notify {
    limit_except GET HEAD OPTIONS {
        allow 127.0.0.1;
        allow ::1;
        deny all;
    }

    proxy_pass http://127.0.0.1:8081;
    include proxy_params_no_auth;

    proxy_buffering off;
    proxy_request_buffering off;
    proxy_redirect off;

    proxy_connect_timeout 3m;
    proxy_send_timeout 3m;
    proxy_read_timeout 3m;

    client_max_body_size 0;
}

Then reload nginx:

nginx -t && systemctl reload nginx

5. Synapse setting: In YunoHost admin panel, go to Synapse > Config panel > Advanced Settings > Security, and enable “Allow synapse to send request to localhost”.


Notes:

The “Test push loop back” in Element X’s troubleshooter will fail with this setup. My guess is that the test tries to POST directly from your phone, which nginx blocks. Real notifications work because they go through Synapse on localhost.


Important: iOS limitations for self-hosters

This setup only applies to Android. iOS users don’t use ntfy at all, and unfortunately there’s no easy way to fully self-host push notifications for iOS.

Apple requires all push notifications to go through their APNs (Apple Push Notification service), and only registered Apple developers can send to APNs. From what I could observe in my local synapse postgres’ DB, Element maintains a push gateway at matrix.org with their Apple developer credentials, so all Element X iOS notifications route through matrix.org regardless of which homeserver you use.

The notification flow differs by platform:

Android: Synapse → your ntfy server → ntfy app → Element X ✓ fully self-hosted
iOS:     Synapse → matrix.org → Apple APNs → Element X     ✗ routes through third party

You can see for yourself by running SELECT user_name, app_display_name, pushkey, data FROM pushers; against the synapse DB (sudo -u postgres psql synapse)

Privacy implications: Your iOS notifications pass through matrix.org servers :scream:. Element X uses format: event_id_only by default, which means matrix.org only learns “user X on homeserver Y has a notification”, not the message content. Element X then fetches the actual message directly from your homeserver. This is a reasonable privacy compromise, but it’s important to understand that full sovereignty isn’t possible on iOS without building your own app with your own Apple developer account.

This is an Apple platform restriction, not a Matrix or Element design choice. For users who prioritise complete self-hosting, Android with ntfy is currently the only option.

1 Like