Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Apps | Demo | Docs | Install
  1. Cloudron Forum
  2. Discuss
  3. Guide: Self Hosted Notifications

Guide: Self Hosted Notifications

Scheduled Pinned Locked Moved Discuss
3 Posts 2 Posters 996 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • T Offline
      T Offline
      thetomester13
      App Dev
      wrote on last edited by
      #1

      Hello fellow Cloudron-users!

      With the year about to close, I was very happy to recently be able to check off an important item for me on my self hosted checklist, 'Self hosted notifications'. I wanted to share my setup with the community for anyone else that is thinking of doing something similar.

      Goals

      • Self hosted (on Cloudron)
      • iOS app
      • Easy webhook trigger
      • Open source

      Why?

      I want to be able to receive push notifications on my phone (iOS, important to distinguish, will touch on this later), automatically or manually with ease.

      Setup

      I use Matrix (server) and Element (client) for the main messages system. n8n is used to setup easy to use webhooks so I can trigger a notification from most places.

      Alternatives And Why I Didn't Like These Solutions

      • Slack: I used to use Slack for notifications. They have a really solid mobile application, and easy to use webhooks, crucial for automating notifications. However, Slack is closed source and proprietary, a real deal breaker for what I'm trying to go for.

      • RocketChat: RocketChat could be used instead of Matrix. I went with Matrix because of its decentralized nature and because I already had it installed and don't have RocketChat on my Cloudron. I believe RocketChat could be used as an alternative solution. The mobile application works very well (have used it previously).

      • Gotify: Gotify has been packaged for Cloudron (unofficially) and I really wanted to use this since it's built for exactly this purpose. However, given Apple's tight grip on their hardware, Gotify doesn't have an iOS application since it requires agreeing to Apple's TOS and paying them to host an app on the App Store. Unfortunately, this was a dealbreaker for me.

        • Gotify can also be used with an unofficial PushOver 'bridge' for iOS. But PushOver is closed source. Again, dealbreaker.

      Guide

      1. Install Matrix and Element to your Cloudron.
      2. Install n8n to your Cloudron.
      3. Log in to Element using your main (LDAP) user, and create a new room that will be the place where all of your notification messages will go to, for example #automated-messages. In the room settings, be sure you set Notifications to 'All Messages'.
        9fd29fa6-ba0a-414a-b92f-b5c6dc757f26-image.png
      4. We'll now need to create our bot user and invite it to the room created above.
        • From your Cloudron dashboard, go to your Matrix application's File Manager and open the file /app/data/configs/homeserver.yaml.
        • Set enable_registration to true. We'll come back and set this to false later, but we need this to create our bot user.
        • Also set enabled and localdb_enabled to true under password_config. This is to ensure that newly registered users will be able to login.
        • Restart your Matrix application.
        • Go to your Element application and register a new user. Give this 'user' (read: bot) a username that you'd want your bot to have. Keep the credentials in a secure place (probably your Cloudron's Bitwarden : ) even though you probably won't need to access this user very frequently at all.
        • After the registration of the bot user, you should set enable_registration back to false and save the config file. This way no external uninvited users can use your Matrix instance to register a new user.
        • Restart your Matrix application again.
      5. As your main user, now go to the room you created and invite your bot user.
      6. As your bot user, accept the invitation to the room.
      7. We can test your notifications proper now. Be sure you have the Element client installed on your phone and logged in as your primary user. Send a message from the bot account in the room. You should get a mobile notification! Now time to enable automation.
      8. As your bot user, go to your All Settings -> Help & About. Make note of your Access Token.
        • If you have this token written down somewhere, you can now log out of the bot's Element account, we won't to be logged into it anymore.
      9. Let's create a workflow in n8n to be able to send messages with ease from our bot user! Go to n8n and create a new workflow.
      10. Copy the text below and paste it into your workflow.
      {
        "name": "Send Matrix Message",
        "nodes": [
          {
            "parameters": {},
            "name": "Start",
            "type": "n8n-nodes-base.start",
            "typeVersion": 1,
            "position": [
              240,
              300
            ]
          },
          {
            "parameters": {
              "roomId": "!roomId:matrix_url.com",
              "text": "={{Object.keys($json[\"body\"]).length > 0 ? $json[\"body\"][\"msg\"] || JSON.stringify($json[\"body\"]) : $json[\"query\"][\"msg\"] || \"Notification triggered\"}}"
            },
            "name": "Matrix",
            "type": "n8n-nodes-base.matrix",
            "typeVersion": 1,
            "position": [
              780,
              120
            ],
            "credentials": {
              "matrixApi": {
                "id": "11",
                "name": "Matrix Bot"
              }
            }
          },
          {
            "parameters": {
              "httpMethod": "POST",
              "path": "matrix",
              "options": {}
            },
            "name": "POST Webhook",
            "type": "n8n-nodes-base.webhook",
            "typeVersion": 1,
            "position": [
              240,
              120
            ],
            "webhookId": "5b81524e-74fb-4da2-9526-51eb20e4ccfb"
          },
          {
            "parameters": {
              "path": "matrix",
              "options": {}
            },
            "name": "GET Webhook",
            "type": "n8n-nodes-base.webhook",
            "typeVersion": 1,
            "position": [
              240,
              -40
            ],
            "webhookId": "379725f7-f3ab-4c5e-a99b-334d70023295"
          },
          {
            "parameters": {
              "conditions": {
                "boolean": [],
                "string": [
                  {
                    "value1": "={{$json[\"query\"][\"x-matrix\"] || $json[\"headers\"][\"x-matrix\"]}}",
                    "value2": "neo"
                  }
                ]
              }
            },
            "name": "IF GET",
            "type": "n8n-nodes-base.if",
            "typeVersion": 1,
            "position": [
              480,
              -40
            ]
          },
          {
            "parameters": {
              "conditions": {
                "boolean": [],
                "string": [
                  {
                    "value1": "={{$json[\"headers\"][\"x-matrix\"]}}",
                    "value2": "neo"
                  }
                ]
              }
            },
            "name": "IF POST",
            "type": "n8n-nodes-base.if",
            "typeVersion": 1,
            "position": [
              480,
              120
            ]
          }
        ],
        "connections": {
          "Start": {
            "main": [
              [
                {
                  "node": "Matrix",
                  "type": "main",
                  "index": 0
                }
              ]
            ]
          },
          "POST Webhook": {
            "main": [
              [
                {
                  "node": "IF POST",
                  "type": "main",
                  "index": 0
                }
              ]
            ]
          },
          "GET Webhook": {
            "main": [
              [
                {
                  "node": "IF GET",
                  "type": "main",
                  "index": 0
                }
              ]
            ]
          },
          "IF GET": {
            "main": [
              [
                {
                  "node": "Matrix",
                  "type": "main",
                  "index": 0
                }
              ]
            ]
          },
          "IF POST": {
            "main": [
              [
                {
                  "node": "Matrix",
                  "type": "main",
                  "index": 0
                }
              ]
            ]
          }
        },
        "active": true,
        "settings": {},
        "id": 10
      }
      
      1. Be sure to create a new Credentials for Matrix using your bot's Access Token we copied from earlier and your Matrix URL, and set your workflow to use those credentials. Also be sure to update the Room ID in the workflow to the shared room created above.
      2. Save and Activate this workflow. This workflow enables both POST and GET requests that will send a message to your room from the bot user!
        • As a precaution, we validate that the request contains a special header/parameter and only then will send the message. In this case, we want x-matrix to be set to neo. If this is not present, the request will return a 200 response, but won't actually send a message/notification.
        • The text to send should be under the name msg. If no msg exists, we fallback to sending the text 'Notification triggered'.

      Example CURL commands to test this out from your Terminal:

      1. GET request with validator header: curl "https://n8n.cloudron.url/webhook/matrix?msg=Test%20message" -H "x-matrix: neo"
      2. GET request with validator parameter: curl "https://n8n.cloudron.url/webhook/matrix?msg=Test%20message&x-matrix=neo"
      3. Invalid GET request with no validator (returns 200 status but does not send notification): curl "https://n8n.cloudron.url/webhook/matrix?msg=Test%20message
      4. POST request curl -X POST https://n8n.cloudron.url/webhook/matrix -H 'x-matrix: neo' -H 'Content-Type: application/json' -d '{"msg": "Test message"}'

      You can also simply visit a URL in your browser to send a test message: https://n8n.<cloudron_url>/webhook/matrix?msg=Test%20message&x-matrix=neo

      afc4875a-bb6a-4dc1-8e6d-893f7f028885-image.png

      You can now use automations to trigger a notification given the URL's and examples above!

      Still Left To Figure Out

      Since I want this URL to be as easy for me as possible to ping in the future, I'd like to be able to set up some sort of forwarding mechanims where push.cloudron_url.com goes to n8n.cloudron_url.com/webhook/matrix. The tricky part is that the plain forwarding URL (push.cloudron_url.com) ideally would not need any path but it would forward to the path /webhook/matrix on the actual URL. This solution would also need to forward query parameters, headers, etc with it to ensure the notification comes through properly. Open to suggestions on how to go about doing this!

      robiR 1 Reply Last reply
      7
      • T thetomester13

        Hello fellow Cloudron-users!

        With the year about to close, I was very happy to recently be able to check off an important item for me on my self hosted checklist, 'Self hosted notifications'. I wanted to share my setup with the community for anyone else that is thinking of doing something similar.

        Goals

        • Self hosted (on Cloudron)
        • iOS app
        • Easy webhook trigger
        • Open source

        Why?

        I want to be able to receive push notifications on my phone (iOS, important to distinguish, will touch on this later), automatically or manually with ease.

        Setup

        I use Matrix (server) and Element (client) for the main messages system. n8n is used to setup easy to use webhooks so I can trigger a notification from most places.

        Alternatives And Why I Didn't Like These Solutions

        • Slack: I used to use Slack for notifications. They have a really solid mobile application, and easy to use webhooks, crucial for automating notifications. However, Slack is closed source and proprietary, a real deal breaker for what I'm trying to go for.

        • RocketChat: RocketChat could be used instead of Matrix. I went with Matrix because of its decentralized nature and because I already had it installed and don't have RocketChat on my Cloudron. I believe RocketChat could be used as an alternative solution. The mobile application works very well (have used it previously).

        • Gotify: Gotify has been packaged for Cloudron (unofficially) and I really wanted to use this since it's built for exactly this purpose. However, given Apple's tight grip on their hardware, Gotify doesn't have an iOS application since it requires agreeing to Apple's TOS and paying them to host an app on the App Store. Unfortunately, this was a dealbreaker for me.

          • Gotify can also be used with an unofficial PushOver 'bridge' for iOS. But PushOver is closed source. Again, dealbreaker.

        Guide

        1. Install Matrix and Element to your Cloudron.
        2. Install n8n to your Cloudron.
        3. Log in to Element using your main (LDAP) user, and create a new room that will be the place where all of your notification messages will go to, for example #automated-messages. In the room settings, be sure you set Notifications to 'All Messages'.
          9fd29fa6-ba0a-414a-b92f-b5c6dc757f26-image.png
        4. We'll now need to create our bot user and invite it to the room created above.
          • From your Cloudron dashboard, go to your Matrix application's File Manager and open the file /app/data/configs/homeserver.yaml.
          • Set enable_registration to true. We'll come back and set this to false later, but we need this to create our bot user.
          • Also set enabled and localdb_enabled to true under password_config. This is to ensure that newly registered users will be able to login.
          • Restart your Matrix application.
          • Go to your Element application and register a new user. Give this 'user' (read: bot) a username that you'd want your bot to have. Keep the credentials in a secure place (probably your Cloudron's Bitwarden : ) even though you probably won't need to access this user very frequently at all.
          • After the registration of the bot user, you should set enable_registration back to false and save the config file. This way no external uninvited users can use your Matrix instance to register a new user.
          • Restart your Matrix application again.
        5. As your main user, now go to the room you created and invite your bot user.
        6. As your bot user, accept the invitation to the room.
        7. We can test your notifications proper now. Be sure you have the Element client installed on your phone and logged in as your primary user. Send a message from the bot account in the room. You should get a mobile notification! Now time to enable automation.
        8. As your bot user, go to your All Settings -> Help & About. Make note of your Access Token.
          • If you have this token written down somewhere, you can now log out of the bot's Element account, we won't to be logged into it anymore.
        9. Let's create a workflow in n8n to be able to send messages with ease from our bot user! Go to n8n and create a new workflow.
        10. Copy the text below and paste it into your workflow.
        {
          "name": "Send Matrix Message",
          "nodes": [
            {
              "parameters": {},
              "name": "Start",
              "type": "n8n-nodes-base.start",
              "typeVersion": 1,
              "position": [
                240,
                300
              ]
            },
            {
              "parameters": {
                "roomId": "!roomId:matrix_url.com",
                "text": "={{Object.keys($json[\"body\"]).length > 0 ? $json[\"body\"][\"msg\"] || JSON.stringify($json[\"body\"]) : $json[\"query\"][\"msg\"] || \"Notification triggered\"}}"
              },
              "name": "Matrix",
              "type": "n8n-nodes-base.matrix",
              "typeVersion": 1,
              "position": [
                780,
                120
              ],
              "credentials": {
                "matrixApi": {
                  "id": "11",
                  "name": "Matrix Bot"
                }
              }
            },
            {
              "parameters": {
                "httpMethod": "POST",
                "path": "matrix",
                "options": {}
              },
              "name": "POST Webhook",
              "type": "n8n-nodes-base.webhook",
              "typeVersion": 1,
              "position": [
                240,
                120
              ],
              "webhookId": "5b81524e-74fb-4da2-9526-51eb20e4ccfb"
            },
            {
              "parameters": {
                "path": "matrix",
                "options": {}
              },
              "name": "GET Webhook",
              "type": "n8n-nodes-base.webhook",
              "typeVersion": 1,
              "position": [
                240,
                -40
              ],
              "webhookId": "379725f7-f3ab-4c5e-a99b-334d70023295"
            },
            {
              "parameters": {
                "conditions": {
                  "boolean": [],
                  "string": [
                    {
                      "value1": "={{$json[\"query\"][\"x-matrix\"] || $json[\"headers\"][\"x-matrix\"]}}",
                      "value2": "neo"
                    }
                  ]
                }
              },
              "name": "IF GET",
              "type": "n8n-nodes-base.if",
              "typeVersion": 1,
              "position": [
                480,
                -40
              ]
            },
            {
              "parameters": {
                "conditions": {
                  "boolean": [],
                  "string": [
                    {
                      "value1": "={{$json[\"headers\"][\"x-matrix\"]}}",
                      "value2": "neo"
                    }
                  ]
                }
              },
              "name": "IF POST",
              "type": "n8n-nodes-base.if",
              "typeVersion": 1,
              "position": [
                480,
                120
              ]
            }
          ],
          "connections": {
            "Start": {
              "main": [
                [
                  {
                    "node": "Matrix",
                    "type": "main",
                    "index": 0
                  }
                ]
              ]
            },
            "POST Webhook": {
              "main": [
                [
                  {
                    "node": "IF POST",
                    "type": "main",
                    "index": 0
                  }
                ]
              ]
            },
            "GET Webhook": {
              "main": [
                [
                  {
                    "node": "IF GET",
                    "type": "main",
                    "index": 0
                  }
                ]
              ]
            },
            "IF GET": {
              "main": [
                [
                  {
                    "node": "Matrix",
                    "type": "main",
                    "index": 0
                  }
                ]
              ]
            },
            "IF POST": {
              "main": [
                [
                  {
                    "node": "Matrix",
                    "type": "main",
                    "index": 0
                  }
                ]
              ]
            }
          },
          "active": true,
          "settings": {},
          "id": 10
        }
        
        1. Be sure to create a new Credentials for Matrix using your bot's Access Token we copied from earlier and your Matrix URL, and set your workflow to use those credentials. Also be sure to update the Room ID in the workflow to the shared room created above.
        2. Save and Activate this workflow. This workflow enables both POST and GET requests that will send a message to your room from the bot user!
          • As a precaution, we validate that the request contains a special header/parameter and only then will send the message. In this case, we want x-matrix to be set to neo. If this is not present, the request will return a 200 response, but won't actually send a message/notification.
          • The text to send should be under the name msg. If no msg exists, we fallback to sending the text 'Notification triggered'.

        Example CURL commands to test this out from your Terminal:

        1. GET request with validator header: curl "https://n8n.cloudron.url/webhook/matrix?msg=Test%20message" -H "x-matrix: neo"
        2. GET request with validator parameter: curl "https://n8n.cloudron.url/webhook/matrix?msg=Test%20message&x-matrix=neo"
        3. Invalid GET request with no validator (returns 200 status but does not send notification): curl "https://n8n.cloudron.url/webhook/matrix?msg=Test%20message
        4. POST request curl -X POST https://n8n.cloudron.url/webhook/matrix -H 'x-matrix: neo' -H 'Content-Type: application/json' -d '{"msg": "Test message"}'

        You can also simply visit a URL in your browser to send a test message: https://n8n.<cloudron_url>/webhook/matrix?msg=Test%20message&x-matrix=neo

        afc4875a-bb6a-4dc1-8e6d-893f7f028885-image.png

        You can now use automations to trigger a notification given the URL's and examples above!

        Still Left To Figure Out

        Since I want this URL to be as easy for me as possible to ping in the future, I'd like to be able to set up some sort of forwarding mechanims where push.cloudron_url.com goes to n8n.cloudron_url.com/webhook/matrix. The tricky part is that the plain forwarding URL (push.cloudron_url.com) ideally would not need any path but it would forward to the path /webhook/matrix on the actual URL. This solution would also need to forward query parameters, headers, etc with it to ensure the notification comes through properly. Open to suggestions on how to go about doing this!

        robiR Offline
        robiR Offline
        robi
        wrote on last edited by robi
        #2

        @thetomester13 said in Guide: Self Hosted Notifications:

        I'd like to be able to set up some sort of forwarding mechanims where push.cloudron_url.com goes to n8n.cloudron_url.com/webhook/matrix.

        That's what smarter reverse proxies do like nginx or traeffic which also help you scale the n8n backend service for the frontend push service..

        If you don't need that level of scale, you can just deploy a surfer app and some JS/HTML to take a number of different GET/POST requests and forward them as you expect. This may be called URL cloaking in some circles and domain forwarding in others.

        Initially I thought you were aiming at setting up a web page where you can type in any message for you/others, but that removes the API aspects which N8N is for.

        Conscious tech

        T 1 Reply Last reply
        1
        • robiR robi

          @thetomester13 said in Guide: Self Hosted Notifications:

          I'd like to be able to set up some sort of forwarding mechanims where push.cloudron_url.com goes to n8n.cloudron_url.com/webhook/matrix.

          That's what smarter reverse proxies do like nginx or traeffic which also help you scale the n8n backend service for the frontend push service..

          If you don't need that level of scale, you can just deploy a surfer app and some JS/HTML to take a number of different GET/POST requests and forward them as you expect. This may be called URL cloaking in some circles and domain forwarding in others.

          Initially I thought you were aiming at setting up a web page where you can type in any message for you/others, but that removes the API aspects which N8N is for.

          T Offline
          T Offline
          thetomester13
          App Dev
          wrote on last edited by
          #3

          deploy a surfer app and some JS/HTML to take a number of different GET/POST requests and forward them

          True, a very reliant and low tech solution that could work! If I don't think of something else anytime soon that's probably what I'll do. I'll update this post when I have that part working as well.

          Initially I thought you were aiming at setting up a web page where you can type in any message for you/others, but that removes the API aspects which N8N is for.

          No, don't want anyone just being able to send me notifications whenever 🙂

          1 Reply Last reply
          2
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Bookmarks
            • Search