[GH-ISSUE #822] Hosting under a subpath does not work well #577

Closed
opened 2026-02-25 23:42:55 +03:00 by kerem · 5 comments
Owner

Originally created by @spantaleev on GitHub (Apr 11, 2023).
Original GitHub issue: https://github.com/healthchecks/healthchecks/issues/822

I'm trying to host Healthchecks under a subpath like /healthchecks and I'm using the following configuration:

Environment variables:

SITE_ROOT=https://DOMAIN/healthchecks
SCRIPT_NAME=/healthchecks

local_settings.py mounted to /opt/healthchecks/hc/local_settings.py in the container image:

FORCE_SCRIPT_NAME = "/healthchecks/"

STATIC_URL = "/healthchecks/static/"

I think that adding /healthchecks to SITE_ROOT may be unnecessary. Perhaps defining the SCRIPT_NAME environment variable does nothing as well.

Nevertheless, FORCE_SCRIPT_NAME and STATIC_URL are obeyed.


With this configuration, I also needed to configure my reverse-proxy to:

  • preserve the /healthchecks/static prefix intact
  • strip the /healthchecks prefix from all other (non-static file) requests

What works:

  • /healthchecks/ redirects to /healthchecks/accounts/login/, as expected
  • /healthchecks/accounts/login/ is rewritten to /accounts/login/ by the reverse-proxy and serves a page, as expected
  • links on the page have the /healthecks prefix, as expected
  • links to static files have the /healthecks prefix, as expected. If I hadn't redefined STATIC_URL with my custom local_settings.py file, this wouldn't have been the case.
  • requests for static files (e.g. /healthchecks/static/CACHE/css/output.c2fb96c40f0a.css) are kept as-is (no stripping of the prefix), and are served, as expected. Note that if we strip the prefix (like we do for other URLs), we'll get 404s

What doesn't work:

  • the CSS file hardcodes font paths as /static/.., not /healthchecks/static/..

Because of this, fonts can't load, which breaks various icons and makes the system unusable.


Is there a way to make the generated CSS file actually use relative URLs, not absolute ones? Or to make it obey STATIC_URL?

Originally created by @spantaleev on GitHub (Apr 11, 2023). Original GitHub issue: https://github.com/healthchecks/healthchecks/issues/822 I'm trying to host Healthchecks under a subpath like `/healthchecks` and I'm using the following configuration: Environment variables: ``` SITE_ROOT=https://DOMAIN/healthchecks SCRIPT_NAME=/healthchecks ``` `local_settings.py` mounted to `/opt/healthchecks/hc/local_settings.py` in the container image: ```python FORCE_SCRIPT_NAME = "/healthchecks/" STATIC_URL = "/healthchecks/static/" ``` ---- I think that adding `/healthchecks` to `SITE_ROOT` may be unnecessary. Perhaps defining the `SCRIPT_NAME` environment variable does nothing as well. Nevertheless, `FORCE_SCRIPT_NAME` and `STATIC_URL` are obeyed. --------- With this configuration, I also needed to configure my reverse-proxy to: - preserve the `/healthchecks/static` prefix intact - strip the `/healthchecks` prefix from all other (non-static file) requests What **works**: - `/healthchecks/` redirects to `/healthchecks/accounts/login/`, as expected - `/healthchecks/accounts/login/` is rewritten to `/accounts/login/` by the reverse-proxy and serves a page, as expected - links on the page have the `/healthecks` prefix, as expected - links to static files have the `/healthecks` prefix, as expected. If I hadn't redefined `STATIC_URL` with my custom `local_settings.py` file, this wouldn't have been the case. - requests for static files (e.g. `/healthchecks/static/CACHE/css/output.c2fb96c40f0a.css`) are kept as-is (no stripping of the prefix), and are served, as expected. Note that if we strip the prefix (like we do for other URLs), we'll get 404s What **doesn't** work: - the CSS file hardcodes font paths as `/static/..`, not `/healthchecks/static/..` Because of this, fonts can't load, which breaks various icons and makes the system unusable. ----- Is there a way to make the generated CSS file actually use relative URLs, not absolute ones? Or to make it obey `STATIC_URL`?
kerem closed this issue 2026-02-25 23:42:55 +03:00
Author
Owner

@cuu508 commented on GitHub (Apr 11, 2023):

As an experiment, I added to my local_settings.py:

STATIC_URL = "/foo/static/"

I ran manage.py collectstatic and manage.py compress.

In HTML pages, I now see CSS includes with the /foo/ prefix:

<link rel="stylesheet" href="/foo/static/CACHE/css/output.880e75aea7f0.css" type="text/css">

In the CSS file, I see fonts referenced with the /foo/ prefix:

@font-face{font-family:'icomoon';src:url('/foo/static/fonts/icomoon.ttf?bncoc2&fc585b7120f2') (...)

One thing to try, if you haven't done it already, is to run manage.py collectstatic and manage.py compress.

<!-- gh-comment-id:1503546613 --> @cuu508 commented on GitHub (Apr 11, 2023): As an experiment, I added to my local_settings.py: ``` STATIC_URL = "/foo/static/" ``` I ran `manage.py collectstatic` and `manage.py compress`. In HTML pages, I now see CSS includes with the /foo/ prefix: ``` <link rel="stylesheet" href="/foo/static/CACHE/css/output.880e75aea7f0.css" type="text/css"> ``` In the CSS file, I see fonts referenced with the `/foo/` prefix: ``` @font-face{font-family:'icomoon';src:url('/foo/static/fonts/icomoon.ttf?bncoc2&fc585b7120f2') (...) ``` One thing to try, if you haven't done it already, is to run `manage.py collectstatic` and `manage.py compress`.
Author
Owner

@spantaleev commented on GitHub (Apr 11, 2023):

I haven't tried these. Thanks for the pointers!

This may work, but it's problematic, because:

  • my container runs with a --read-only filesystem, so these files aren't writable
  • my container runs with a non-root user (--user=...), so it can't write to these files even if they're not readonly

Looks like solving it this way will require both some hacks (--entrypoint=/bin/sh + -c "python /opt/healthchecks/manage.py collectstatic --no-input && python /opt/healthchecks/manage.py compress && uwsgi /opt/healthchecks/docker/uwsgi.ini") and also decreasing security.

I was considering doing a sed-replace instead of running these manage.py commands, but.. these files are not writable due to the read-only filesystem anyway, so that's another no-go. Seems like the /opt/healthchecks/static-collected files are all root:root-owned too.

<!-- gh-comment-id:1503604490 --> @spantaleev commented on GitHub (Apr 11, 2023): I haven't tried these. Thanks for the pointers! This may work, but it's problematic, because: - my container runs with a `--read-only` filesystem, so these files aren't writable - my container runs with a non-root user (`--user=...`), so it can't write to these files even if they're not readonly Looks like solving it this way will require both some hacks (`--entrypoint=/bin/sh` + `-c "python /opt/healthchecks/manage.py collectstatic --no-input && python /opt/healthchecks/manage.py compress && uwsgi /opt/healthchecks/docker/uwsgi.ini"`) and also decreasing security. I was considering doing a `sed`-replace instead of running these `manage.py` commands, but.. these files are not writable due to the read-only filesystem anyway, so that's another no-go. Seems like the `/opt/healthchecks/static-collected` files are all `root:root`-owned too.
Author
Owner

@cuu508 commented on GitHub (Apr 11, 2023):

Looking at django-compressor docs there might be a way to generate relative paths to the font files – use CssRelativeFilter instead of CssAbsoluteFilter. I'll look into that.

Assuming relative paths work, I think the prebuilt CSS would work regardless of the STATIC_URL value at runtime.

<!-- gh-comment-id:1503666312 --> @cuu508 commented on GitHub (Apr 11, 2023): Looking at [django-compressor docs](https://django-compressor.readthedocs.io/en/stable/settings.html) there might be a way to generate relative paths to the font files – use `CssRelativeFilter` instead of `CssAbsoluteFilter`. I'll look into that. Assuming relative paths work, I think the prebuilt CSS would work regardless of the STATIC_URL value at runtime.
Author
Owner

@cuu508 commented on GitHub (Apr 12, 2023):

I pushed a change which switches CSS bundles from using absolute file paths to using relative file paths.

I'm not planning to do a new release soon, but in the meantime you can build an image yourself: clone the repository and from its root directory run

docker build -t healthchecks:v2.9-dev -f docker/Dockerfile .
<!-- gh-comment-id:1504906499 --> @cuu508 commented on GitHub (Apr 12, 2023): I pushed a change which switches CSS bundles from using absolute file paths to using relative file paths. I'm not planning to do a new release soon, but in the meantime you can build an image yourself: clone the repository and from its root directory run ``` docker build -t healthchecks:v2.9-dev -f docker/Dockerfile . ```
Author
Owner

@spantaleev commented on GitHub (Apr 12, 2023):

Glad to hear that it's fixed! Thank you for fixing it up so quickly!


I have built master manually and tested that it's indeed fixed, so I'm closing this issue.


I'm actually hosting Healthchecks without using a subpath, but wanted to have support for this anyway, so that others using the mash-playbok Ansible playbook and its Healthchecks service (powered by the ansible-role-healthchecks Ansible role) can host it at a subpath.

We support hosting at a subpath for various other services, so I thought that supporting it for Healthchecks would be useful to others, as not having to configure DNS for each and every additional service is much more convenient.

Healthchecks support is still a new addition to this Ansible playbook, so if you do give it a try some time and have some feedback about our integration, it'd be great to hear it.

<!-- gh-comment-id:1504944364 --> @spantaleev commented on GitHub (Apr 12, 2023): Glad to hear that it's fixed! Thank you for fixing it up so quickly! ------ I have built `master` manually and tested that it's indeed fixed, so I'm closing this issue. ------ I'm actually hosting Healthchecks without using a subpath, but wanted to have support for this anyway, so that others using the [mash-playbok](https://github.com/mother-of-all-self-hosting/mash-playbook) Ansible playbook and its [Healthchecks](https://github.com/mother-of-all-self-hosting/mash-playbook/blob/main/docs/services/healthchecks.md) service (powered by the [ansible-role-healthchecks](https://github.com/mother-of-all-self-hosting/ansible-role-healthchecks) Ansible role) can host it at a subpath. We support hosting at a subpath for various other services, so I thought that supporting it for Healthchecks would be useful to others, as not having to configure DNS for each and every additional service is much more convenient. Healthchecks support is still a new addition to this Ansible playbook, so if you do give it a try some time and have some feedback about our integration, it'd be great to hear it.
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/healthchecks#577
No description provided.