Skip to content

Conversation

@TrungNNg
Copy link
Contributor

This PR fixes an issue where Gotify does not normalize URLs, which can lead to double slashes (e.g., http://localhost//message) causing 404 errors.

Before:
Screenshot 2025-11-18 at 1 38 38 PM
After:
Screenshot 2025-11-18 at 1 39 44 PM

Test Proxies
Apache

<VirtualHost *:8080>
    ServerName localhost
    Keepalive On
    ProxyPreserveHost On

    # WebSocket
    ProxyPass "/stream" ws://127.0.0.1:80/stream retry=0 timeout=60

    # HTTP
    ProxyPass "/" http://127.0.0.1:80/ retry=0 timeout=5
    ProxyPassReverse "/" http://127.0.0.1:80/
</VirtualHost>

Result:
Screenshot 2025-11-18 at 1 35 50 PM

Apache subpath

<VirtualHost *:8080>
    ServerName localhost
    Keepalive On

    # Redirect /gotify to /gotify/ (trailing slash)
    Redirect 301 "/gotify" "/gotify/"

    # Preserve host for Gotify WebSocket verification
    ProxyPreserveHost On

    # Proxy WebSocket requests under /gotify/stream
    ProxyPass "/gotify/stream" ws://127.0.0.1:80/stream retry=0 timeout=60

    # Proxy all other /gotify/ requests to Gotify server
    ProxyPass "/gotify/" http://127.0.0.1:80/ retry=0 timeout=5
    ProxyPassReverse "/gotify/" http://127.0.0.1:80/
</VirtualHost>

Result:
Screenshot 2025-11-18 at 1 35 00 PM

Caddy

http://localhost:8080 {
    reverse_proxy localhost:80
}

Result:
Screenshot 2025-11-18 at 1 28 23 PM

Caddy subpath

http://localhost:8080 {
  route /gotify/* {
    uri strip_prefix /gotify
    reverse_proxy localhost:80
  }
  redir /gotify /gotify/
}

Result:
Screenshot 2025-11-18 at 1 32 30 PM

Haproxy

frontend www
    bind 0.0.0.0:8080
    default_backend backend_gotify
    timeout client 60s
    timeout client-fin 30s

backend backend_gotify
    server backend01 127.0.0.1:80 check
    timeout connect 10s
    timeout server 60s

Result:
Screenshot 2025-11-18 at 1 22 55 PM

NGINX

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream gotify {
        server 127.0.0.1:80;  # Gotify server port
    }

    server {
        listen 8080;  # Proxy port
        location / {
            proxy_pass http://gotify;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto http;
            proxy_redirect http:// $scheme://;
            proxy_set_header Host $http_host;

            proxy_connect_timeout 1m;
            proxy_send_timeout 1m;
            proxy_read_timeout 1m;
        }
    }
    include servers/*;
}

Result:
Screenshot 2025-11-18 at 1 10 28 PM

NGINX subpath

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

upstream gotify {
    server 127.0.0.1:80;  # Gotify server running locally on 80
}

server {
    listen 8080;
    location /gotify/ {
        # Strip the /gotify prefix
        rewrite ^/gotify(/.*)$ $1 break;

        proxy_pass         http://gotify;
        proxy_http_version 1.1;

        # WebSocket support
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";

        # Forward client info
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto http;

        # Preserve host for Gotify verification
        proxy_set_header   Host $http_host;

        proxy_connect_timeout   1m;
        proxy_send_timeout      1m;
        proxy_read_timeout      1m;
    }
}
    include servers/*;
}
Screenshot 2025-11-18 at 1 17 13 PM

Traefik

# traefik.yml
entryPoints:
  web:
    address: ":8080"

providers:
  file:
    directory: "./conf.d"

# ./conf.d/gotify.yml
http:
  routers:
    gotify:
      rule: "Host(`localhost`)"
      entryPoints:
        - web
      service: gotify-service

  services:
    gotify-service:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:80"

Result:
Screenshot 2025-11-18 at 1 06 21 PM

@TrungNNg TrungNNg requested a review from a team as a code owner November 18, 2025 22:18
@codecov
Copy link

codecov bot commented Nov 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.15%. Comparing base (9216661) to head (da7b69d).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #875   +/-   ##
=======================================
  Coverage   79.14%   79.15%           
=======================================
  Files          56       56           
  Lines        2225     2226    +1     
=======================================
+ Hits         1761     1762    +1     
  Misses        360      360           
  Partials      104      104           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@eternal-flame-AD eternal-flame-AD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Nice work also making it work on proxies.

I will let Jannis take a look if he has time today otherwise I will merge it tomorrow

@eternal-flame-AD eternal-flame-AD merged commit de7a4e9 into gotify:master Nov 19, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants