Notifications via a proxy (squid) #1763

Closed
opened 2026-02-28 02:31:43 -05:00 by deekerman · 16 comments
Owner

Originally created by @canis54 on GitHub (Jan 11, 2023).

⚠️ Please verify that this feature request has NOT been suggested before.

  • I checked and didn't find similar feature request

🏷️ Feature Request Type

Other

🔖 Feature description

Telegram (axios.get) and teams (axios.post) use neither the system-wide proxy (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) nor a separately defined one such as in the .npmrc (proxy, https-proxy). The extension of the respective axios calls in teams.js or telegram.js with the proxy address (https://www.npmjs.com/package/axios > axios#post(url[, data[, config]])) also fails because the request doesn't arrive at the Squid with request_method=CONNECT.
The webhooks for Telegram and teams via the squid work as desired via curl.

✔️ Solution

The general use of the system variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) for the installation (download-dist.js), the actual monitoring (already works via the http-proxy-agent module) and the notifications (notification-providers) would make sense.

Alternatives

No response

📝 Additional Context

I was able to get the download to run as part of the installation using the 'https-proxy-agent' module in download-dist.js. I couldn't get Axios to work with the Squid.

Originally created by @canis54 on GitHub (Jan 11, 2023). ### ⚠️ Please verify that this feature request has NOT been suggested before. - [X] I checked and didn't find similar feature request ### 🏷️ Feature Request Type Other ### 🔖 Feature description Telegram (axios.get) and teams (axios.post) use neither the system-wide proxy (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) nor a separately defined one such as in the .npmrc (proxy, https-proxy). The extension of the respective axios calls in teams.js or telegram.js with the proxy address (https://www.npmjs.com/package/axios > `axios#post(url[, data[, config]])`) also fails because the request doesn't arrive at the Squid with `request_method=CONNECT`. The webhooks for Telegram and teams via the squid work as desired via curl. ### ✔️ Solution The general use of the system variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) for the installation (`download-dist.js`), the actual monitoring (already works via the `http-proxy-agent` module) and the notifications (notification-providers) would make sense. ### ❓ Alternatives _No response_ ### 📝 Additional Context I was able to get the download to run as part of the installation using the 'https-proxy-agent' module in download-dist.js. I couldn't get Axios to work with the Squid.
Author
Owner

@tperrindell commented on GitHub (Mar 8, 2023):

Agreed, the Teams channel we have is not getting any notifications because the request ignores the proxy settings.

03/08/2023 10:51:16 AM
Error: Error: Error: read ECONNRESET 
03/08/2023 10:51:16 AM at Teams.throwGeneralAxiosError (/app/server/notification-providers/notification-provider.js:38:15)
03/08/2023 10:51:16 AM at Teams.send (/app/server/notification-providers/teams.js:153:18)
03/08/2023 10:51:16 AM at runMicrotasks (<anonymous>)
03/08/2023 10:51:16 AM at processTicksAndRejections (node:internal/process/task_queues:96:5)
03/08/2023 10:51:16 AM at async Socket.<anonymous> (/app/server/server.js:1202:27)
@tperrindell commented on GitHub (Mar 8, 2023): Agreed, the Teams channel we have is not getting any notifications because the request ignores the proxy settings. ``` 03/08/2023 10:51:16 AM Error: Error: Error: read ECONNRESET 03/08/2023 10:51:16 AM at Teams.throwGeneralAxiosError (/app/server/notification-providers/notification-provider.js:38:15) 03/08/2023 10:51:16 AM at Teams.send (/app/server/notification-providers/teams.js:153:18) 03/08/2023 10:51:16 AM at runMicrotasks (<anonymous>) 03/08/2023 10:51:16 AM at processTicksAndRejections (node:internal/process/task_queues:96:5) 03/08/2023 10:51:16 AM at async Socket.<anonymous> (/app/server/server.js:1202:27) ```
Author
Owner

@koehdaniel commented on GitHub (Mar 8, 2023):

I fixed it by using a different library to do the POST-Request.
My first public Pull-Request on Github so not sure how to proceed.

@koehdaniel commented on GitHub (Mar 8, 2023): I fixed it by using a different library to do the POST-Request. My first public Pull-Request on Github so not sure how to proceed.
Author
Owner

@tperrindell commented on GitHub (Mar 8, 2023):

How do you setup the proxy value to use in the notification?

@tperrindell commented on GitHub (Mar 8, 2023): How do you setup the proxy value to use in the notification?
Author
Owner

@koehdaniel commented on GitHub (Mar 8, 2023):

I set them as Environment-Variables:

HTTP_PROXY
HTTPS_PROXY
NO_PROXY
@koehdaniel commented on GitHub (Mar 8, 2023): I set them as Environment-Variables: ``` HTTP_PROXY HTTPS_PROXY NO_PROXY ```
Author
Owner

@vanhoutenbos commented on GitHub (Jun 22, 2023):

👀 im interested in this feature!

@vanhoutenbos commented on GitHub (Jun 22, 2023): 👀 im interested in this feature!
Author
Owner

@CommanderStorm commented on GitHub (Jun 22, 2023):

@vanhoutenbos
Please refrain from posting +1 / requests for updates things on issues, as this makes issue-management harder.
Issues are for discussing what needs to be done how by whom.
We use 👍🏻 on issues to prioritise work.

If you want, you can propose a PR fixing this issue.

@CommanderStorm commented on GitHub (Jun 22, 2023): @vanhoutenbos Please refrain from posting `+1` / requests for updates things on issues, as this makes issue-management harder. Issues are for discussing what needs to be done how by whom. [We use 👍🏻 on issues to prioritise work](https://github.com/louislam/uptime-kuma/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc). If you want, you can propose a PR fixing this issue.
Author
Owner

@garelp commented on GitHub (Aug 16, 2023):

Hello,
That would be good to support either a specific proxy configuration to send notification or having the full support of the proxy variable including the no_proxy too.

@garelp commented on GitHub (Aug 16, 2023): Hello, That would be good to support either a specific proxy configuration to send notification or having the full support of the proxy variable including the no_proxy too.
Author
Owner

@miberecz commented on GitHub (Feb 21, 2024):

Turns out its a big blocker for us. Our servers cannot reach the internet directly, we have to use a proxy (as most enterprise servers)
Since MS Teams webhook addresses are not local, we cannot reach them with the Kuma.
As a workaround I tried to install an Apprise-api container setup our MS Teams endpoint in it, since that one can have proxy set up.
(No, the built-in apprise also does not work since it cannot use proxies)
But now I do not know how to call my Apprise endpoint from Kuma.

http://apprise-address:8000/notify/someID
If I call this as a webhook I get

Error: Error: AxiosError: Request failed with status code 400 {"error":"Payload lacks minimum requirements."}
    at Webhook.throwGeneralAxiosError (/app/server/notification-providers/notification-provider.js:38:15)
    at Webhook.send (/app/server/notification-providers/webhook.js:57:18)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Socket.<anonymous> (/app/server/server.js:1298:27)

Any ideas about this?

@miberecz commented on GitHub (Feb 21, 2024): Turns out its a big blocker for us. Our servers cannot reach the internet directly, we have to use a proxy (as most enterprise servers) Since MS Teams webhook addresses are not local, we cannot reach them with the Kuma. As a workaround I tried to install an Apprise-api container setup our MS Teams endpoint in it, since that one can have proxy set up. (No, the built-in apprise also does not work since it cannot use proxies) But now I do not know how to call my Apprise endpoint from Kuma. http://apprise-address:8000/notify/someID If I call this as a webhook I get ``` Error: Error: AxiosError: Request failed with status code 400 {"error":"Payload lacks minimum requirements."} at Webhook.throwGeneralAxiosError (/app/server/notification-providers/notification-provider.js:38:15) at Webhook.send (/app/server/notification-providers/webhook.js:57:18) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Socket.<anonymous> (/app/server/server.js:1298:27) ``` Any ideas about this?
Author
Owner

@CommanderStorm commented on GitHub (Apr 14, 2024):

@canis54 Is this issue a duplciate of #616?

@CommanderStorm commented on GitHub (Apr 14, 2024): @canis54 Is this issue a duplciate of #616?
Author
Owner

@canis54 commented on GitHub (Apr 19, 2024):

@CommanderStorm Thank you for your inquiry. It appears that I've been rather foolish in my approach prior to submitting the request, as I neglected to thoroughly search through existing inquiries. Essentially, my request aligns closely with those already made. However, my concern extends beyond mere notification via a proxy; rather, I am interested in the general usage of existing proxies, such as during a program update. In my instance, I've simply adjusted the download-dist.js file (which certainly isn't suitable for a pull request, as I'm not a programmer).

@canis54 commented on GitHub (Apr 19, 2024): @CommanderStorm Thank you for your inquiry. It appears that I've been rather foolish in my approach prior to submitting the request, as I neglected to thoroughly search through existing inquiries. Essentially, my request aligns closely with those already made. However, my concern extends beyond mere notification via a proxy; rather, I am interested in the general usage of existing proxies, such as during a program update. In my instance, I've simply adjusted the download-dist.js file (which certainly isn't suitable for a pull request, as I'm not a programmer).
Author
Owner

@CommanderStorm commented on GitHub (Apr 19, 2024):

Closing as s duplicate then

@CommanderStorm commented on GitHub (Apr 19, 2024): Closing as s duplicate then
Author
Owner

@CommanderStorm commented on GitHub (Apr 19, 2024):

which certainly isn't suitable for a pull request, as I'm not a programmer

Provide a PR and we will see about it. Think you are underselling yourself here

@CommanderStorm commented on GitHub (Apr 19, 2024): > which certainly isn't suitable for a pull request, as I'm not a programmer Provide a PR and we will see about it. Think you are underselling yourself here
Author
Owner

@mertcancam commented on GitHub (Jun 27, 2024):

I needed to implement proxy support for the webhook notification provider, and the following changes worked for me.

Server-side (server/notification-providers/webhook.js):

Import:

const HttpsProxyAgent = require("https-proxy-agent");

Then add the following code:

// Add proxy support
if (notification.proxyURL) {
    const httpsAgent = new HttpsProxyAgent(notification.proxyURL);
    config.httpsAgent = httpsAgent;
}

Frontend (src/components/notifications/Webhook.vue):

<div class="mb-3">
    <label for="webhook-url" class="form-label">Proxy URL</label>
    <input
        id="webhook-url"
        v-model="$parent.notification.proxyURL"
        type="url"
        pattern="https?://.+"
        class="form-control"
        required
    />
</div>

It seems feasible to add this feature in a more general way rather than individually for each notification provider. I apologize if this comment is not entirely appropriate. As a DevOps engineer, I needed to get this working quickly. I hope someone can take over and integrate this feature into a future release, so I don't have to rely on a custom build. Thank you!

@mertcancam commented on GitHub (Jun 27, 2024): I needed to implement proxy support for the webhook notification provider, and the following changes worked for me. **Server-side (server/notification-providers/webhook.js):** Import: ```javascript const HttpsProxyAgent = require("https-proxy-agent"); ``` Then add the following code: ```javascript // Add proxy support if (notification.proxyURL) { const httpsAgent = new HttpsProxyAgent(notification.proxyURL); config.httpsAgent = httpsAgent; } ``` **Frontend (src/components/notifications/Webhook.vue):** ```html <div class="mb-3"> <label for="webhook-url" class="form-label">Proxy URL</label> <input id="webhook-url" v-model="$parent.notification.proxyURL" type="url" pattern="https?://.+" class="form-control" required /> </div> ``` It seems feasible to add this feature in a more general way rather than individually for each notification provider. I apologize if this comment is not entirely appropriate. As a DevOps engineer, I needed to get this working quickly. I hope someone can take over and integrate this feature into a future release, so I don't have to rely on a custom build. Thank you!
Author
Owner

@gbetsis commented on GitHub (Nov 26, 2024):

In case you want to implement proxy support for telegram notifications, here is a quick and dirty solution, with hardcoded the proxy settings into the code:

const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const HttpsProxyAgent = require("https-proxy-agent");

class Telegram extends NotificationProvider {

    name = "telegram";

    async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
        let okMsg = "Sent Successfully.";
        const httpsAgent = new HttpsProxyAgent('http://10.10.10.10:3128');

        try {
            let params = {
                chat_id: notification.telegramChatID,
                text: msg,
                disable_notification: notification.telegramSendSilently ?? false,
                protect_content: notification.telegramProtectContent ?? false,
            };
            if (notification.telegramMessageThreadID) {
                params.message_thread_id = notification.telegramMessageThreadID;
            }

            await axios.post(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`,
                params,
                { httpsAgent: httpsAgent });

            return okMsg;

        } catch (error) {
            if (error.response && error.response.data && error.response.data.description) {
                throw new Error(error.response.data.description);
            } else {
                throw new Error(error.message);
            }
        }
    }
}

module.exports = Telegram;

This is the full code of the file /app/server/notification-providers/telegram.js

@gbetsis commented on GitHub (Nov 26, 2024): In case you want to implement proxy support for telegram notifications, here is a quick and dirty solution, with hardcoded the proxy settings into the code: ```js const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const HttpsProxyAgent = require("https-proxy-agent"); class Telegram extends NotificationProvider { name = "telegram"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { let okMsg = "Sent Successfully."; const httpsAgent = new HttpsProxyAgent('http://10.10.10.10:3128'); try { let params = { chat_id: notification.telegramChatID, text: msg, disable_notification: notification.telegramSendSilently ?? false, protect_content: notification.telegramProtectContent ?? false, }; if (notification.telegramMessageThreadID) { params.message_thread_id = notification.telegramMessageThreadID; } await axios.post(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, params, { httpsAgent: httpsAgent }); return okMsg; } catch (error) { if (error.response && error.response.data && error.response.data.description) { throw new Error(error.response.data.description); } else { throw new Error(error.message); } } } } module.exports = Telegram; ``` This is the full code of the file **/app/server/notification-providers/telegram.js**
Author
Owner

@gbetsis commented on GitHub (Nov 26, 2024):

In case you want to use rocket.chat notifications with proxy, here is the full code for the file /app/server/notification-providers/rocket-chat.js:

const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const Slack = require("./slack");
const { setting } = require("../util-server");
const { getMonitorRelativeURL, DOWN } = require("../../src/util");
const HttpsProxyAgent = require("https-proxy-agent");

class RocketChat extends NotificationProvider {

    name = "rocket.chat";

    async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
        let okMsg = "Sent Successfully.";
        try {
            const httpsAgent = new HttpsProxyAgent("http://10.10.10.10:3128");

            if (heartbeatJSON == null) {
                let data = {
                    "text": msg,
                    "channel": notification.rocketchannel,
                    "username": notification.rocketusername,
                    "icon_emoji": notification.rocketiconemo,
                };
                await axios.post(notification.rocketwebhookURL, data, { httpsAgent: httpsAgent });
                return okMsg;
            }

            let data = {
                "text": "Uptime Kuma Alert",
                "channel": notification.rocketchannel,
                "username": notification.rocketusername,
                "icon_emoji": notification.rocketiconemo,
                "attachments": [
                    {
                        "title": `Uptime Kuma Alert *Time (${heartbeatJSON["timezone"]})*\n${heartbeatJSON["localDateTime"]}`,
                        "text": "*Message*\n" + msg,
                    }
                ]
            };

            // Color
            if (heartbeatJSON.status === DOWN) {
                data.attachments[0].color = "#ff0000";
            } else {
                data.attachments[0].color = "#32cd32";
            }

            if (notification.rocketbutton) {
                await Slack.deprecateURL(notification.rocketbutton);
            }

            const baseURL = await setting("primaryBaseURL");

            if (baseURL) {
                data.attachments[0].title_link = baseURL + getMonitorRelativeURL(monitorJSON.id);
            }

            await axios.post(notification.rocketwebhookURL, data, { httpsAgent: httpsAgent });
            return okMsg;
        } catch (error) {
            this.throwGeneralAxiosError(data + " " + error);
        }

    }
}

module.exports = RocketChat;
@gbetsis commented on GitHub (Nov 26, 2024): In case you want to use rocket.chat notifications with proxy, here is the full code for the file **/app/server/notification-providers/rocket-chat.js**: ```js const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const Slack = require("./slack"); const { setting } = require("../util-server"); const { getMonitorRelativeURL, DOWN } = require("../../src/util"); const HttpsProxyAgent = require("https-proxy-agent"); class RocketChat extends NotificationProvider { name = "rocket.chat"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { let okMsg = "Sent Successfully."; try { const httpsAgent = new HttpsProxyAgent("http://10.10.10.10:3128"); if (heartbeatJSON == null) { let data = { "text": msg, "channel": notification.rocketchannel, "username": notification.rocketusername, "icon_emoji": notification.rocketiconemo, }; await axios.post(notification.rocketwebhookURL, data, { httpsAgent: httpsAgent }); return okMsg; } let data = { "text": "Uptime Kuma Alert", "channel": notification.rocketchannel, "username": notification.rocketusername, "icon_emoji": notification.rocketiconemo, "attachments": [ { "title": `Uptime Kuma Alert *Time (${heartbeatJSON["timezone"]})*\n${heartbeatJSON["localDateTime"]}`, "text": "*Message*\n" + msg, } ] }; // Color if (heartbeatJSON.status === DOWN) { data.attachments[0].color = "#ff0000"; } else { data.attachments[0].color = "#32cd32"; } if (notification.rocketbutton) { await Slack.deprecateURL(notification.rocketbutton); } const baseURL = await setting("primaryBaseURL"); if (baseURL) { data.attachments[0].title_link = baseURL + getMonitorRelativeURL(monitorJSON.id); } await axios.post(notification.rocketwebhookURL, data, { httpsAgent: httpsAgent }); return okMsg; } catch (error) { this.throwGeneralAxiosError(data + " " + error); } } } module.exports = RocketChat; ```
Author
Owner

@jakestec commented on GitHub (Jul 4, 2025):

If anyone else stumbles on this and wants a working/not pretty solution for teams.js here you go:

For what its worth I am doing this in uptime-kuma:2.0.0-beta.3, https-proxy-agent is already installed in the default image.

Its only a couple lines of code:

const { HttpsProxyAgent } = require("https-proxy-agent"); // added for axios proxy fix, should be installed 
...
    /**
     * Send the notification
     * @param {string} webhookUrl URL to send the request to
     * @param {object} payload Payload generated by _notificationPayloadFactory
     * @returns {Promise<void>}
     */
    _sendNotification = async (webhookUrl, payload) => {

        // hardcoded proxy server
        const proxy = 'http://192.168.1.1:8080';
        const agent = new HttpsProxyAgent(proxy);

        // post with agent config and proxy: false
        await axios.post(webhookUrl,
            payload,
            { httpsAgent: agent, proxy: false });
    };

full file here /app/server/notification-providers/teams.js:

const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { setting } = require("../util-server");
const { DOWN, UP, getMonitorRelativeURL } = require("../../src/util");
const { HttpsProxyAgent } = require("https-proxy-agent");

class Teams extends NotificationProvider {
    name = "teams";

    /**
     * Generate the message to send
     * @param {const} status The status constant
     * @param {string} monitorName Name of monitor
     * @param {boolean} withStatusSymbol If the status should be prepended as symbol
     * @returns {string} Status message
     */
    _statusMessageFactory = (status, monitorName, withStatusSymbol) => {
        if (status === DOWN) {
            return (withStatusSymbol ? "🔴 " : "") + `[${monitorName}] went down`;
        } else if (status === UP) {
            return (withStatusSymbol ? "✅ " : "") + `[${monitorName}] is back online`;
        }
        return "Notification";
    };

    /**
     * Select the style to use based on status
     * @param {const} status The status constant
     * @returns {string} Selected style for adaptive cards
     */
    _getStyle = (status) => {
        if (status === DOWN) {
            return "attention";
        }
        if (status === UP) {
            return "good";
        }
        return "emphasis";
    };

    /**
     * Generate payload for notification
     * @param {object} args Method arguments
     * @param {object} args.heartbeatJSON Heartbeat details
     * @param {string} args.monitorName Name of the monitor affected
     * @param {string} args.monitorUrl URL of the monitor affected
     * @param {string} args.dashboardUrl URL of the dashboard affected
     * @returns {object} Notification payload
     */
    _notificationPayloadFactory = ({
        heartbeatJSON,
        monitorName,
        monitorUrl,
        dashboardUrl,
    }) => {
        const status = heartbeatJSON?.status;
        const facts = [];
        const actions = [];

        if (dashboardUrl) {
            actions.push({
                "type": "Action.OpenUrl",
                "title": "Visit Uptime Kuma",
                "url": dashboardUrl
            });
        }

        if (heartbeatJSON?.msg) {
            facts.push({
                title: "Description",
                value: heartbeatJSON.msg,
            });
        }

        if (monitorName) {
            facts.push({
                title: "Monitor",
                value: monitorName,
            });
        }

        if (monitorUrl && monitorUrl !== "https://") {
            facts.push({
                title: "URL",
                // format URL as markdown syntax, to be clickable
                value: `[${monitorUrl}](${monitorUrl})`,
            });
            actions.push({
                "type": "Action.OpenUrl",
                "title": "Visit Monitor URL",
                "url": monitorUrl
            });
        }

        if (heartbeatJSON?.localDateTime) {
            facts.push({
                title: "Time",
                value: heartbeatJSON.localDateTime + (heartbeatJSON.timezone ? ` (${heartbeatJSON.timezone})` : ""),
            });
        }

        const payload = {
            "type": "message",
            // message with status prefix as notification text
            "summary": this._statusMessageFactory(status, monitorName, true),
            "attachments": [
                {
                    "contentType": "application/vnd.microsoft.card.adaptive",
                    "contentUrl": "",
                    "content": {
                        "type": "AdaptiveCard",
                        "body": [
                            {
                                "type": "Container",
                                "verticalContentAlignment": "Center",
                                "items": [
                                    {
                                        "type": "ColumnSet",
                                        "style": this._getStyle(status),
                                        "columns": [
                                            {
                                                "type": "Column",
                                                "width": "auto",
                                                "verticalContentAlignment": "Center",
                                                "items": [
                                                    {
                                                        "type": "Image",
                                                        "width": "32px",
                                                        "style": "Person",
                                                        "url": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png",
                                                        "altText": "Uptime Kuma Logo"
                                                    }
                                                ]
                                            },
                                            {
                                                "type": "Column",
                                                "width": "stretch",
                                                "items": [
                                                    {
                                                        "type": "TextBlock",
                                                        "size": "Medium",
                                                        "weight": "Bolder",
                                                        "text": `**${this._statusMessageFactory(status, monitorName, false)}**`,
                                                    },
                                                    {
                                                        "type": "TextBlock",
                                                        "size": "Small",
                                                        "weight": "Default",
                                                        "text": "Uptime Kuma Alert",
                                                        "isSubtle": true,
                                                        "spacing": "None"
                                                    }
                                                ]
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "type": "FactSet",
                                "separator": false,
                                "facts": facts
                            }
                        ],
                        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                        "version": "1.5"
                    }
                }
            ]
        };

        if (actions) {
            payload.attachments[0].content.body.push({
                "type": "ActionSet",
                "actions": actions,
            });
        }

        return payload;
    };

    /**
     * Send the notification
     * @param {string} webhookUrl URL to send the request to
     * @param {object} payload Payload generated by _notificationPayloadFactory
     * @returns {Promise<void>}
     */
    _sendNotification = async (webhookUrl, payload) => {

        const proxy = 'http://192.168.1.1:8080';
        const agent = new HttpsProxyAgent(proxy);

        await axios.post(webhookUrl,
            payload,
            { httpsAgent: agent, proxy: false });
    };

    /**
     * Send a general notification
     * @param {string} webhookUrl URL to send request to
     * @param {string} msg Message to send
     * @returns {Promise<void>}
     */
    _handleGeneralNotification = (webhookUrl, msg) => {
        const payload = this._notificationPayloadFactory({
            heartbeatJSON: {
                msg: msg
            }
        });

        return this._sendNotification(webhookUrl, payload);
    };

    /**
     * @inheritdoc
     */
    async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
        const okMsg = "Sent Successfully.";

        try {
            if (heartbeatJSON == null) {
                await this._handleGeneralNotification(notification.webhookUrl, msg);
                return okMsg;
            }

            const baseURL = await setting("primaryBaseURL");
            let dashboardUrl;
            if (baseURL) {
                dashboardUrl = baseURL + getMonitorRelativeURL(monitorJSON.id);
            }

            const payload = this._notificationPayloadFactory({
                heartbeatJSON: heartbeatJSON,
                monitorName: monitorJSON.name,
                monitorUrl: this.extractAddress(monitorJSON),
                dashboardUrl: dashboardUrl,
            });

            await this._sendNotification(notification.webhookUrl, payload);
            return okMsg;
        } catch (error) {
            this.throwGeneralAxiosError(error);
        }
    }
}

module.exports = Teams;
@jakestec commented on GitHub (Jul 4, 2025): If anyone else stumbles on this and wants a working/not pretty solution for teams.js here you go: For what its worth I am doing this in uptime-kuma:2.0.0-beta.3, https-proxy-agent is already installed in the default image. Its only a couple lines of code: ```js const { HttpsProxyAgent } = require("https-proxy-agent"); // added for axios proxy fix, should be installed ... /** * Send the notification * @param {string} webhookUrl URL to send the request to * @param {object} payload Payload generated by _notificationPayloadFactory * @returns {Promise<void>} */ _sendNotification = async (webhookUrl, payload) => { // hardcoded proxy server const proxy = 'http://192.168.1.1:8080'; const agent = new HttpsProxyAgent(proxy); // post with agent config and proxy: false await axios.post(webhookUrl, payload, { httpsAgent: agent, proxy: false }); }; ``` full file here **/app/server/notification-providers/teams.js:** ```js const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const { setting } = require("../util-server"); const { DOWN, UP, getMonitorRelativeURL } = require("../../src/util"); const { HttpsProxyAgent } = require("https-proxy-agent"); class Teams extends NotificationProvider { name = "teams"; /** * Generate the message to send * @param {const} status The status constant * @param {string} monitorName Name of monitor * @param {boolean} withStatusSymbol If the status should be prepended as symbol * @returns {string} Status message */ _statusMessageFactory = (status, monitorName, withStatusSymbol) => { if (status === DOWN) { return (withStatusSymbol ? "🔴 " : "") + `[${monitorName}] went down`; } else if (status === UP) { return (withStatusSymbol ? "✅ " : "") + `[${monitorName}] is back online`; } return "Notification"; }; /** * Select the style to use based on status * @param {const} status The status constant * @returns {string} Selected style for adaptive cards */ _getStyle = (status) => { if (status === DOWN) { return "attention"; } if (status === UP) { return "good"; } return "emphasis"; }; /** * Generate payload for notification * @param {object} args Method arguments * @param {object} args.heartbeatJSON Heartbeat details * @param {string} args.monitorName Name of the monitor affected * @param {string} args.monitorUrl URL of the monitor affected * @param {string} args.dashboardUrl URL of the dashboard affected * @returns {object} Notification payload */ _notificationPayloadFactory = ({ heartbeatJSON, monitorName, monitorUrl, dashboardUrl, }) => { const status = heartbeatJSON?.status; const facts = []; const actions = []; if (dashboardUrl) { actions.push({ "type": "Action.OpenUrl", "title": "Visit Uptime Kuma", "url": dashboardUrl }); } if (heartbeatJSON?.msg) { facts.push({ title: "Description", value: heartbeatJSON.msg, }); } if (monitorName) { facts.push({ title: "Monitor", value: monitorName, }); } if (monitorUrl && monitorUrl !== "https://") { facts.push({ title: "URL", // format URL as markdown syntax, to be clickable value: `[${monitorUrl}](${monitorUrl})`, }); actions.push({ "type": "Action.OpenUrl", "title": "Visit Monitor URL", "url": monitorUrl }); } if (heartbeatJSON?.localDateTime) { facts.push({ title: "Time", value: heartbeatJSON.localDateTime + (heartbeatJSON.timezone ? ` (${heartbeatJSON.timezone})` : ""), }); } const payload = { "type": "message", // message with status prefix as notification text "summary": this._statusMessageFactory(status, monitorName, true), "attachments": [ { "contentType": "application/vnd.microsoft.card.adaptive", "contentUrl": "", "content": { "type": "AdaptiveCard", "body": [ { "type": "Container", "verticalContentAlignment": "Center", "items": [ { "type": "ColumnSet", "style": this._getStyle(status), "columns": [ { "type": "Column", "width": "auto", "verticalContentAlignment": "Center", "items": [ { "type": "Image", "width": "32px", "style": "Person", "url": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", "altText": "Uptime Kuma Logo" } ] }, { "type": "Column", "width": "stretch", "items": [ { "type": "TextBlock", "size": "Medium", "weight": "Bolder", "text": `**${this._statusMessageFactory(status, monitorName, false)}**`, }, { "type": "TextBlock", "size": "Small", "weight": "Default", "text": "Uptime Kuma Alert", "isSubtle": true, "spacing": "None" } ] } ] } ] }, { "type": "FactSet", "separator": false, "facts": facts } ], "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.5" } } ] }; if (actions) { payload.attachments[0].content.body.push({ "type": "ActionSet", "actions": actions, }); } return payload; }; /** * Send the notification * @param {string} webhookUrl URL to send the request to * @param {object} payload Payload generated by _notificationPayloadFactory * @returns {Promise<void>} */ _sendNotification = async (webhookUrl, payload) => { const proxy = 'http://192.168.1.1:8080'; const agent = new HttpsProxyAgent(proxy); await axios.post(webhookUrl, payload, { httpsAgent: agent, proxy: false }); }; /** * Send a general notification * @param {string} webhookUrl URL to send request to * @param {string} msg Message to send * @returns {Promise<void>} */ _handleGeneralNotification = (webhookUrl, msg) => { const payload = this._notificationPayloadFactory({ heartbeatJSON: { msg: msg } }); return this._sendNotification(webhookUrl, payload); }; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { const okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { await this._handleGeneralNotification(notification.webhookUrl, msg); return okMsg; } const baseURL = await setting("primaryBaseURL"); let dashboardUrl; if (baseURL) { dashboardUrl = baseURL + getMonitorRelativeURL(monitorJSON.id); } const payload = this._notificationPayloadFactory({ heartbeatJSON: heartbeatJSON, monitorName: monitorJSON.name, monitorUrl: this.extractAddress(monitorJSON), dashboardUrl: dashboardUrl, }); await this._sendNotification(notification.webhookUrl, payload); return okMsg; } catch (error) { this.throwGeneralAxiosError(error); } } } module.exports = Teams; ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/uptime-kuma#1763
No description provided.