ItzNotABug / ghosler

Send newsletter emails to your Ghost CMS subscribers & members, using your own email credentials!
Apache License 2.0
40 stars 5 forks source link

Hosting via Subdirectory instead of Subdomain #53

Closed fritz-fritz closed 1 month ago

fritz-fritz commented 1 month ago

So it seems to me that Ghosler is designed to be run either at it's own subdomain being reverse proxied or directly via the exposed port. Ideally, I would like to do neither and run it at a subdirectory path being reverse proxied to the ghosler instance. This would:

  1. allow you to access it in a similar way to accessing ghost eg www.example.com/ghosler
  2. not need a new dns record exposing Ghosler's existence
  3. not need another port opened in the firewall on the server hosting it

I have managed to get this semi-functional via my nginx config but it is still broken in many of important ways from logic that is server-side. My attempted nginx config snippet is below:

    location /ghosler/ {
        proxy_pass http://127.0.0.1:2370/;
        proxy_set_header Host $host;
        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 $scheme;

        # Preserve the base path
        rewrite ^/ghosler/(.*)$ /$1 break;
        proxy_redirect          default;
        proxy_redirect          / /ghosler/;

        #Rewrite
        sub_filter_once       off;
        sub_filter_types      *;
        sub_filter            'href="/' 'href="/ghosler/';
        sub_filter            'action="/' 'action="/ghosler/';
        sub_filter            'location.href="/' 'location.href="/ghosler/';
        sub_filter            'url(/' 'url(/ghosler/';
        sub_filter 'window.location = "/' 'window.location = "/ghosler/';
        sub_filter "window.location = '/" "window.location = '/ghosler/";
        sub_filter "window.location='/" "window.location='/ghosler/";
        sub_filter 'window.location.href = "/' 'window.location.href = "/ghosler/';
        sub_filter "window.location.href = '/" "window.location.href = '/ghosler/";
        sub_filter 'window.location.replace("/' 'window.location.replace("/ghosler/';
        sub_filter "window.location.replace('/" "window.location.replace('/ghosler/";
        sub_filter "parent.open('/" "parent.open('/ghosler/";
    }

Not all of it is probably necessary as I got a little carried away trying different approaches.

Ideally, Ghosler should be able to work without the rewrites if it used relative paths such as ./ instead of /. Then we would only need a very simple reverse proxy without the sub_filter rewrites and should work fully for the backend.

I will look at implementing myself as I would love to get Ghosler working. But as I'm not really familiar with node or the codebase, perhaps there's a more appropriate solution?

ItzNotABug commented 1 month ago

Hey @fritz-fritz 👋, I never intended to use a sub-path for managing Ghosler.

But the basic config you showed for NGINX should probably work.

location /ghosler/ {
  proxy_pass http://127.0.0.1:2370/;
  proxy_set_header Host $host;
  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 $scheme;
  proxy_redirect / /ghosler/;
}

Regarding the redirection, I don't think I've used ./ but have used / directly.

Feel free to create a PR as this isn't trivial and only requires changing the view files (*.ejs) which share a similar html like structure.

fritz-fritz commented 1 month ago

I haven't yet attempted to do this properly by fixing the source, but i have seemingly fixed everything with the following nginx record for those that may want it in the future I provide it below. I say seemingly as I have yet to fully test and this approach is prone to failure in a LOT of ways. If I get around to looking into the source, I will certainly send a PR.

    location /ghosler/ {
        proxy_pass http://127.0.0.1:2370/;
        proxy_set_header Host $host;
        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 $scheme;

        # Preserve the base path
        rewrite ^/ghosler/(.*)$ /$1 break;
        proxy_redirect          default;
        proxy_redirect          / /ghosler/;

        #Rewrite
        sub_filter_once       off;
        sub_filter_types      *;
        sub_filter            'href="/' 'href="/ghosler/';
        sub_filter            'action="/' 'action="/ghosler/';
        sub_filter            'location.href="/' 'location.href="/ghosler/';
        sub_filter            'url(/' 'url(/ghosler/';
        sub_filter 'window.location = "/' 'window.location = "/ghosler/';
        sub_filter "window.location = '/" "window.location = '/ghosler/";
        sub_filter "window.location='/" "window.location='/ghosler/";
        sub_filter 'window.location.href = "/' 'window.location.href = "/ghosler/';
        sub_filter "window.location.href = '/" "window.location.href = '/ghosler/";
        sub_filter 'window.location.replace("/' 'window.location.replace("/ghosler/';
        sub_filter "window.location.replace('/" "window.location.replace('/ghosler/";
        sub_filter "parent.open('/" "parent.open('/ghosler/";
        sub_filter "fetch(`/" "fetch(`/ghosler/";
        sub_filter "window.location = `/" "window.location = `/ghosler/";
    }
ItzNotABug commented 1 month ago

Completed via #56.