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


Skip to content
  • 3 Votes
    11 Posts
    127 Views
    E

    Yes, I know that failed backup notifications are already raised in the dashboard, but that requires me to go and look there. I have a mission-critical app that should update every day and I literally had the case that while I was on vacation, it failed one day. Nothing happened, it backed up the next day, but I simply didn't look into the dashboard that day like usually.

    That's where the feature request is coming from.

  • 1 Votes
    3 Posts
    115 Views
    M

    Out of curiosity I've built what @luckow suggested, only with Cloudron API (notifications endpoint) -> n8n -> some magic -> ntfy.sh-app and it looks like this:

    f036453c-4190-48d2-bae2-33c5e16133b5-image.png

    Action gets triggered (either automatically or manually), n8n checks the cloudron api https://my.example1.com/api/v1/notifications (create a readonly access token in your profile and update the Bearer token with it) with the parameters acknowledged = false, so only unread notifications are collected.

    The code-node does the following (filteredTitles because I don't care about app-updates, only actual issues, can be adjusted of course):

    const notifications = items[0].json.notifications; const types = notifications.map(notification => notification.type); const titles = notifications.map(notification => notification.title); // Filter notifications to remove those with type "appUpdated" const filteredNotifications = notifications.filter(notification => notification.type != "appUpdated"); // Extract titles of the filtered notifications const filteredTitles = filteredNotifications.map(notification => notification.title); //return [{ json: { types, titles } }]; return [{ json: { filteredTitles } }];

    This will result in an array of current notifications, e.g.

    [ { "filteredTitles": [ "Email is not configured properly", "The app at cms.example.com ran out of memory." ] } ] The if-node checks if there's actual content. If it's empty, nothing will happen, if it's not, it will make a http request to your nfty instance and topic of your choice (saved credentials in n8n) and send the notifications:

    2ae64242-ff94-44d3-843d-fb0154436eed-image.png

    Since I was working with readonly tokens, I had no intentions of marking the notifications as read after sending out the message. So there's room for improvement, but I thought I would throw it in here as a PoC ๐Ÿ™‚

    Complete code (My_Cloudron_workflow.json) is here:

    { "name": "My Cloudron workflow", "nodes": [ { "parameters": {}, "id": "0dcf1d60-f8e7-4ffe-be14-64399a5c924d", "name": "When clicking \"Test workflow\"", "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 240, 620 ] }, { "parameters": { "url": "https://my.example1.com/api/v1/notifications", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "acknowledged", "value": "false" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer 123" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "id": "073de174-b658-480e-bb3c-6be103304bd9", "name": "EX1", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 620 ], "alwaysOutputData": false }, { "parameters": { "url": "https://my.example2.com/api/v1/notifications", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "acknowledged", "value": "false" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer 456" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "id": "c29eae02-51b5-417c-a103-d35b4bcb15e8", "name": "EX2", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 780 ], "alwaysOutputData": false }, { "parameters": { "url": "https://my.example3.com/api/v1/notifications", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "acknowledged", "value": "false" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer 789" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "id": "a00d01ae-fca9-41e8-b16f-3456459f414a", "name": "EX3", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 460 ], "alwaysOutputData": false }, { "parameters": { "jsCode": "const notifications = items[0].json.notifications;\nconst types = notifications.map(notification => notification.type);\nconst titles = notifications.map(notification => notification.title);\n\n// Filter notifications to remove those with type \"appUpdated\"\nconst filteredNotifications = notifications.filter(notification => notification.type != \"appUpdated\");\n\n// Extract titles of the filtered notifications\nconst filteredTitles = filteredNotifications.map(notification => notification.title);\n\n//return [{ json: { types, titles } }];\nreturn [{ json: { filteredTitles } }];" }, "id": "fb776916-d0d4-46b6-8a7d-7de5694e650c", "name": "Code", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 620, 460 ] }, { "parameters": { "jsCode": "const notifications = items[0].json.notifications;\nconst types = notifications.map(notification => notification.type);\nconst titles = notifications.map(notification => notification.title);\n\n// Filter notifications to remove those with type \"appUpdated\"\nconst filteredNotifications = notifications.filter(notification => notification.type != \"appUpdated\");\n\n// Extract titles of the filtered notifications\nconst filteredTitles = filteredNotifications.map(notification => notification.title);\n\n//return [{ json: { types, titles } }];\nreturn [{ json: { filteredTitles } }];" }, "id": "968f2566-7983-46ef-b14a-3677a3a6fc88", "name": "Code1", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 620, 620 ] }, { "parameters": { "jsCode": "const notifications = items[0].json.notifications;\nconst types = notifications.map(notification => notification.type);\nconst titles = notifications.map(notification => notification.title);\n\n// Filter notifications to remove those with type \"appUpdated\"\nconst filteredNotifications = notifications.filter(notification => notification.type != \"appUpdated\");\n\n// Extract titles of the filtered notifications\nconst filteredTitles = filteredNotifications.map(notification => notification.title);\n\n//return [{ json: { types, titles } }];\nreturn [{ json: { filteredTitles } }];" }, "id": "5463ace4-ed1f-408a-a13c-a153fbda2ca3", "name": "Code2", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 620, 780 ] }, { "parameters": { "method": "POST", "url": "https://ntfy.nftyserver.com/cloudron-notifications", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Title", "value": "Current example3.com notifications" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "Title", "body": "={{ $json.filteredTitles.join(\"\\n\"); }}", "options": {} }, "id": "83bc0ca8-d7e1-4fb5-8dd9-0b3360f6763e", "name": "HTTP Request", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 940, 460 ], "credentials": { "httpBasicAuth": { "id": "5tUu1DjoNUxl0M5a", "name": "ntfy token" } } }, { "parameters": { "method": "POST", "url": "https://ntfy.nftyserver.com/cloudron-notifications", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Title", "value": "Current example1.com notifications" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "Title", "body": "={{ $json.filteredTitles.join(\"\\n\"); }}", "options": {} }, "id": "92815612-9381-444f-86b5-7c3c3cf8a371", "name": "HTTP Request1", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 940, 620 ], "credentials": { "httpBasicAuth": { "id": "5tUu1DjoNUxl0M5a", "name": "ntfy token" } } }, { "parameters": { "method": "POST", "url": "https://ntfy.nftyserver.com/cloudron-notifications", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Title", "value": "Current example2.com notifications" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "Title", "body": "={{ $json.filteredTitles.join(\"\\n\"); }}", "options": {} }, "id": "bc221e4f-8817-4c19-a74d-9333a4783319", "name": "HTTP Request2", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 940, 780 ], "credentials": { "httpBasicAuth": { "id": "5tUu1DjoNUxl0M5a", "name": "ntfy token" } } }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "43482a2f-b2b0-4f0a-b970-7b11e8f6ee03", "leftValue": "={{ $json.filteredTitles }}", "rightValue": "", "operator": { "type": "array", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "id": "af3ebb14-32db-4afb-8c9d-84eb593eae96", "name": "If1", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 780, 620 ] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "1811bb6f-55ca-4b2d-9f6b-97c489ef4d21", "leftValue": "={{ $json.filteredTitles }}", "rightValue": "", "operator": { "type": "array", "operation": "notEmpty", "singleValue": true } } ], "combinator": "or" }, "options": {} }, "id": "e354d631-5daf-495d-a5e2-e0fb64ef212d", "name": "If2", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 780, 780 ] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "43482a2f-b2b0-4f0a-b970-7b11e8f6ee03", "leftValue": "={{ $json.filteredTitles }}", "rightValue": "", "operator": { "type": "array", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "id": "a3fc1a27-f94d-4651-884f-34c683b0a2da", "name": "If", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 780, 460 ] } ], "pinData": {}, "connections": { "When clicking \"Test workflow\"": { "main": [ [ { "node": "EX1", "type": "main", "index": 0 }, { "node": "EX2", "type": "main", "index": 0 }, { "node": "EX3", "type": "main", "index": 0 } ] ] }, "EX1": { "main": [ [ { "node": "Code1", "type": "main", "index": 0 } ] ] }, "EX2": { "main": [ [ { "node": "Code2", "type": "main", "index": 0 } ] ] }, "EX3": { "main": [ [ { "node": "Code", "type": "main", "index": 0 } ] ] }, "Code1": { "main": [ [ { "node": "If1", "type": "main", "index": 0 } ] ] }, "Code2": { "main": [ [ { "node": "If2", "type": "main", "index": 0 } ] ] }, "Code": { "main": [ [ { "node": "If", "type": "main", "index": 0 } ] ] }, "If1": { "main": [ [ { "node": "HTTP Request1", "type": "main", "index": 0 } ] ] }, "If2": { "main": [ [ { "node": "HTTP Request2", "type": "main", "index": 0 } ] ] }, "If": { "main": [ [ { "node": "HTTP Request", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": { "executionOrder": "v1" }, "versionId": "b1689af0-81c6-453c-a8aa-1d7c84d7a85e", "meta": { "templateCredsSetupCompleted": true, "instanceId": "8903125d64295093a384f52f480a1738308c71ada8db56c53efba4894aefbff2" }, "id": "I2Mq9Y8GOPIDIh8i", "tags": [] }

    I threw out a module last minute, so hopefully no oversights in there. Improvements are welcome! ๐Ÿ˜‰

    TL;DR: Adjust the URLs to your Cloudrons, create and add readonly tokens, add a ntfy token to your n8n credentials and adjust the URL to your ntfy instance.

  • 1 Votes
    3 Posts
    93 Views
    sponchS

    @girish Ah okay... Thanks.

  • 1 Votes
    5 Posts
    155 Views
    andreasduerenA

    @girish said in Add notification for Certificate errors:

    @andreasdueren sorry, I meant if your Cloudron is able to send outbound email. Does sending a test email work - https://docs.cloudron.io/email/#send-test-email

    Yea works no problem

  • 1 Votes
    4 Posts
    112 Views
    nebulonN

    You should see it in the app logs around that timeframe what happened

  • 2 Votes
    12 Posts
    338 Views
    nebulonN

    Well if you look into the web inspector, you could just utilize the rest APIs just like the dashboard itself does. "New Apps" here is just defined as first published within last n days.

    But the initial feature request was about a way to find new apps, which is what the menu item is about if I understood this correctly?

  • 0 Votes
    3 Posts
    117 Views
    robiR

    Yes. They used to come nagging back. Maybe it's different this release.

    You can imagine what happens to mobile notifications.

    On a separate note, we did discuss having a button for "Upgrade all apps" in the UI.

    That button would be really helpful.

  • 4 Votes
    3 Posts
    227 Views
    girishG

    This is fixed in 7.4.1, was a regression.

  • 1 Votes
    5 Posts
    154 Views
    ericdrgnE

    Just came to ask about this, thanks for always being on top of things cloudron team!

  • 6 Votes
    14 Posts
    556 Views
    benborgesB

    @potemkin_ai agreed, that would make it all super simple to setup, without having to add anything special on cloudron side, perhaps different webhooks for different alerts and then leave to N8N/ntfy node the definition of how it has to be processed.

  • 0 Votes
    7 Posts
    415 Views
    L

    @jdaviescoates Thanks incredibly for suggesting this method! The NodeBB plugin works well. A reboot is required and you need to enable the plugin too.

    The calendar application is beautiful: full calendar, with some humane licencing.

    https://fullcalendar.io/docs

  • 4 Votes
    6 Posts
    200 Views
    BrutalBirdieB

    @benborges
    Zabbix is running on a Master Node and each Client has an Agent. (Yes the master is an external System)
    Zabbix can monitor clients active and passive.
    Passive means the Master asks the system for data and the system delivers.

    This does not always work within special networks where the master can not reach the client.
    Then you use active monitoring then the client reports all data in a certain interval to the master.

    There can be a master / slave / proxy setup for big scale monitoring solutions. (Google Zabbix HA Cluster Setup for more details)

    For more in detail please consult the doc: https://www.zabbix.com/documentation/current/en/manual/introduction/about

  • 0 Votes
    10 Posts
    490 Views
    girishG

    @qilin said in New to Cloudron. Having different issues:

    The strange part is that there are no bans which is worrisome to me.

    So, this doesn't work most because fail2ban itself works by scanning log files and as you said, there is nothing in the auth.log.

    Generally, this is outside Cloudron configuration (as in, Cloudron does not configure or update all this on the server). My understanding is sshd logs always to syslog. You can check the Facility with which it logs in /etc/ssh/sshd_config. I think from there it goes to /etc/rsyslog.d/* config files to log based on the facility. Not 100% sure, maybe others can chime in.

  • 2 Votes
    8 Posts
    259 Views
    girishG

    There is a bug in the current release that the code crashes when trying to send a notification if a backup failed. This is fixed . I think in the coming releases we can explore more notification options but atleast now you should get an email.

  • 3 Votes
    4 Posts
    226 Views
    nebulonN

    This should now be fixed with next release. It will show 100+ in such a case.

  • 3 Votes
    2 Posts
    239 Views
    timconsidineT

    @d19dotca I'm excited by the potential for https://ntfy.sh.
    Maybe a cloudron official instance which sets up channels for all customers, so cloudron-generated notifications can be delivered to a customer.
    Or maybe there's a better way. I just think ntfy.sh is so easy to implement into scripts.

  • 2 Votes
    3 Posts
    268 Views
    nebulonN

    This should be fixed with the next release. There were a couple of state issues which needed fixing.

  • 7 Votes
    10 Posts
    624 Views
    X

    @mehdi said in Email notify on SSH login:

    @xarp actually, Cloudron uses the inbound port 25. This does not prevent it from sending stuff.

    I tried the postfix/mailutils method which uses a simple bashrc method in the user/root home, however when Cloudron rebooted, the mail service couldn't start unfortunately.

  • 2 Votes
    2 Posts
    284 Views
    imc67I

    @loudlemur curious too!

  • 1 Votes
    2 Posts
    235 Views
    nebulonN

    @klawitterb thanks, good catch! This will be fixed with the next version:

    b999d516-d53b-4994-b50d-8ec58158a2fd-image.png