From 76667ffcf9937cb4dd0428b5858710c218ee9f71 Mon Sep 17 00:00:00 2001 From: nisbet-hubbard <87453615+nisbet-hubbard@users.noreply.github.com> Date: Wed, 12 Jul 2023 18:18:48 +0800 Subject: [PATCH 1/5] Use mod_proxy_http for websocket upgrade mod_proxy_wstunnel is deprecated as of httpd 2.4.47. It also uses more resources since it relies on mod_rewrite. See https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#protoupgrade. --- docs/config.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/docs/config.md b/docs/config.md index 9af79992..3577bb48 100644 --- a/docs/config.md +++ b/docs/config.md @@ -649,8 +649,8 @@ or the root domain: ServerName ntfy.sh - # Proxy connections to ntfy (requires "a2enmod proxy") - ProxyPass / http://127.0.0.1:2586/ + # Proxy connections to ntfy (requires "a2enmod proxy proxy_http") + ProxyPass / http://127.0.0.1:2586/ upgrade=websocket ProxyPassReverse / http://127.0.0.1:2586/ SetEnv proxy-nokeepalive 1 @@ -661,11 +661,6 @@ or the root domain: # Enable mod_rewrite (requires "a2enmod rewrite") RewriteEngine on - - # WebSockets support (requires "a2enmod rewrite proxy_wstunnel") - RewriteCond %{HTTP:Upgrade} websocket [NC] - RewriteCond %{HTTP:Connection} upgrade [NC] - RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L] # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want # it to work with curl without the annoying https:// prefix @@ -681,8 +676,8 @@ or the root domain: SSLCertificateKeyFile /etc/letsencrypt/live/ntfy.sh/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf - # Proxy connections to ntfy (requires "a2enmod proxy") - ProxyPass / http://127.0.0.1:2586/ + # Proxy connections to ntfy (requires "a2enmod proxy proxy_http") + ProxyPass / http://127.0.0.1:2586/ upgrade=websocket ProxyPassReverse / http://127.0.0.1:2586/ SetEnv proxy-nokeepalive 1 @@ -693,11 +688,7 @@ or the root domain: # Enable mod_rewrite (requires "a2enmod rewrite") RewriteEngine on - - # WebSockets support (requires "a2enmod rewrite proxy_wstunnel") - RewriteCond %{HTTP:Upgrade} websocket [NC] - RewriteCond %{HTTP:Connection} upgrade [NC] - RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L] + ``` From e52132c85b1297a53911f97302546aab227097eb Mon Sep 17 00:00:00 2001 From: nisbet-hubbard <87453615+nisbet-hubbard@users.noreply.github.com> Date: Wed, 12 Jul 2023 19:48:51 +0800 Subject: [PATCH 2/5] Use mod_alias for redirection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s a less resource-intensive alternative to mod_rewrite. --- docs/config.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/docs/config.md b/docs/config.md index 3577bb48..af84dae9 100644 --- a/docs/config.md +++ b/docs/config.md @@ -658,14 +658,13 @@ or the root domain: # Higher than the max message size of 4096 bytes LimitRequestBody 102400 - - # Enable mod_rewrite (requires "a2enmod rewrite") - RewriteEngine on # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want - # it to work with curl without the annoying https:// prefix - RewriteCond %{REQUEST_METHOD} GET - RewriteRule ^/([-_A-Za-z0-9]{0,64})$ https://%{SERVER_NAME}/$1 [R,L] + # it to work with curl without the annoying https:// prefix (requires "a2enmod alias") + + RedirectMatch permanent "^/([-_A-Za-z0-9]{0,64})$" "https://%{SERVER_NAME}/$1" + + @@ -685,9 +684,6 @@ or the root domain: # Higher than the max message size of 4096 bytes LimitRequestBody 102400 - - # Enable mod_rewrite (requires "a2enmod rewrite") - RewriteEngine on ``` From a534cc9ecacb5985c1de4b503ae435fe9973c768 Mon Sep 17 00:00:00 2001 From: nisbet-hubbard <87453615+nisbet-hubbard@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:00:48 +0800 Subject: [PATCH 3/5] Add server.yml ex. when using proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This would help inexperienced sysadmins who may not realise that since TLS terminates at proxy, ntfy is actually listening on a TCP socket that’s using http rather than https. --- docs/config.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/config.md b/docs/config.md index af84dae9..bb7f7e1b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -44,6 +44,14 @@ Here are a few working sample configs: attachment-cache-dir: "/var/cache/ntfy/attachments" ``` +=== "server.yml (behind proxy, with cache + attachments)" + ``` yaml + base-url: "http://ntfy.example.com" + listen-http: ":2586" + cache-file: "/var/cache/ntfy/cache.db" + attachment-cache-dir: "/var/cache/ntfy/attachments" + ``` + === "server.yml (ntfy.sh config)" ``` yaml # All the things: Behind a proxy, Firebase, cache, attachments, From 4e9eeb1fa168e0d27d6df013242aefc6e172fe5a Mon Sep 17 00:00:00 2001 From: nisbet-hubbard <87453615+nisbet-hubbard@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:24:57 +0800 Subject: [PATCH 4/5] Add missing note on log file permissions --- server/server.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/server.yml b/server/server.yml index 6b2fc989..b044a914 100644 --- a/server/server.yml +++ b/server/server.yml @@ -342,6 +342,10 @@ # - "field -> level" to match any value, e.g. "time_taken_ms -> debug" # Warning: Using log-level-overrides has a performance penalty. Only use it for temporary debugging. # +# Check your permissions: +# If you are running ntfy with systemd, make sure this log file is owned by the +# ntfy user and group by running: chown ntfy.ntfy . +# # Example (good for production): # log-level: info # log-format: json From 384cabede52dc61ca57c1033bf6d4d27554d4ee2 Mon Sep 17 00:00:00 2001 From: Nihal Gonsalves Date: Fri, 14 Jul 2023 13:10:24 +0200 Subject: [PATCH 5/5] feat: check extension to display external images --- web/src/app/notificationUtils.js | 2 +- web/src/components/Notifications.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/app/notificationUtils.js b/web/src/app/notificationUtils.js index 35c85ce6..0bd5136d 100644 --- a/web/src/app/notificationUtils.js +++ b/web/src/app/notificationUtils.js @@ -35,7 +35,7 @@ export const formatMessage = (m) => { }; const imageRegex = /\.(png|jpe?g|gif|webp)$/i; -const isImage = (attachment) => { +export const isImage = (attachment) => { if (!attachment) return false; // if there's a type, only take that into account diff --git a/web/src/components/Notifications.jsx b/web/src/components/Notifications.jsx index d1cce0e8..0b8b2e7d 100644 --- a/web/src/components/Notifications.jsx +++ b/web/src/components/Notifications.jsx @@ -27,7 +27,7 @@ import { useOutletContext } from "react-router-dom"; import { useRemark } from "react-remark"; import styled from "@emotion/styled"; import { formatBytes, formatShortDateTime, maybeActionErrors, openUrl, shortUrl, topicShortUrl, unmatchedTags } from "../app/utils"; -import { formatMessage, formatTitle } from "../app/notificationUtils"; +import { formatMessage, formatTitle, isImage } from "../app/notificationUtils"; import { LightboxBackdrop, Paragraph, VerticallyCenteredContainer } from "./styles"; import subscriptionManager from "../app/SubscriptionManager"; import priority1 from "../img/priority-1.svg"; @@ -346,7 +346,7 @@ const Attachment = (props) => { const { attachment } = props; const expired = attachment.expires && attachment.expires < Date.now() / 1000; const expires = attachment.expires && attachment.expires > Date.now() / 1000; - const displayableImage = !expired && attachment.type && attachment.type.startsWith("image/"); + const displayableImage = !expired && isImage(attachment); // Unexpired image if (displayableImage) {