[GH-ISSUE #239] CSRF Error with email system #172

Closed
opened 2026-02-25 23:41:27 +03:00 by kerem · 8 comments
Owner

Originally created by @eirannejad on GitHub (Apr 2, 2019).
Original GitHub issue: https://github.com/healthchecks/healthchecks/issues/239

Hello healthcheck team,
I'm getting a error when clicking on the "Email me a link" button

Forbidden (403)
CSRF verification failed. Request aborted.

Healthcheck is running in a docker container and is mapped to port "3003" so url is "localhost:3003"

Originally created by @eirannejad on GitHub (Apr 2, 2019). Original GitHub issue: https://github.com/healthchecks/healthchecks/issues/239 Hello healthcheck team, I'm getting a error when clicking on the "Email me a link" button ``` Forbidden (403) CSRF verification failed. Request aborted. ``` Healthcheck is running in a docker container and is mapped to port "3003" so url is "localhost:3003"
kerem closed this issue 2026-02-25 23:41:27 +03:00
Author
Owner

@cuu508 commented on GitHub (Apr 3, 2019):

Hello @eirannejad, what Dockerfile are you using?

<!-- gh-comment-id:479381310 --> @cuu508 commented on GitHub (Apr 3, 2019): Hello @eirannejad, what Dockerfile are you using?
Author
Owner

@eirannejad commented on GitHub (Apr 3, 2019):

@cuu508 This one

<!-- gh-comment-id:479544787 --> @eirannejad commented on GitHub (Apr 3, 2019): @cuu508 [This one](https://github.com/galexrt/docker-healthchecks)
Author
Owner

@eirannejad commented on GitHub (Apr 3, 2019):

And here is my docker-compose file

We have two domain names. Email is @mycompany.com but the mailserver and internal servers are under *.mycomp-pdx.com e.g. mail.mycomp-pdx.com, data.mycomp-pdx.com, apps.mycomp-pdx.com

version: '3'

services:
  hc:
    image: galexrt/healthchecks:latest
    restart: always
    ports:
      - "3003:8000"
      - "2525:2525"
    volumes:
      - HC_Data:/healthchecks
      - HC_SQLite:/data
    environment:
      HC_HOST: "0.0.0.0"
      HC_SECRET_KEY: "blablabla"
      HC_ALLOWED_HOSTS: '["*"]'
      HC_DEBUG: "False"
      HC_DEFAULT_FROM_EMAIL: "healthcheck@mycompany.com"
      HC_USE_PAYMENTS: "False"
      HC_REGISTRATION_OPEN: "False"
      HC_EMAIL_HOST: "mail.mycomp-pdx.com"
      HC_EMAIL_PORT: "587"
      HC_EMAIL_HOST_USER: "healthcheck"
      HC_EMAIL_HOST_PASSWORD: "healthcheck-password"
      HC_EMAIL_USE_TLS: "False"
      HC_SITE_ROOT: "http://apps.mycomp-pdx.com/hc"
      HC_SITE_NAME: "MyCompany HealthChecks"
      HC_MASTER_BADGE_LABEL: "MyCompany HealthChecks"
      HC_PING_ENDPOINT: "http://apps.mycomp-pdx.com/hc/ping"
      HC_PING_EMAIL_DOMAIN: "mycompany.com"
      HC_TWILIO_ACCOUNT: "None"
      HC_TWILIO_AUTH: "None"
      HC_TWILIO_FROM: "None"
      HC_PD_VENDOR_KEY: "None"
      HC_TRELLO_APP_KEY: "None"

volumes:
  HC_SQLite:
  HC_Data:

This is running in a docker container behind nginx that is rerouting traffic to port 3003
But even if I open the localhost:3003 in browser on the docker server itself (directly talking to the container), I get the CSRF error.

I know I'm doing something wrong but don't know what.

<!-- gh-comment-id:479547290 --> @eirannejad commented on GitHub (Apr 3, 2019): And here is my `docker-compose` file We have two domain names. Email is `@mycompany.com` but the mailserver and internal servers are under `*.mycomp-pdx.com` e.g. `mail.mycomp-pdx.com`, `data.mycomp-pdx.com`, `apps.mycomp-pdx.com` ```yaml version: '3' services: hc: image: galexrt/healthchecks:latest restart: always ports: - "3003:8000" - "2525:2525" volumes: - HC_Data:/healthchecks - HC_SQLite:/data environment: HC_HOST: "0.0.0.0" HC_SECRET_KEY: "blablabla" HC_ALLOWED_HOSTS: '["*"]' HC_DEBUG: "False" HC_DEFAULT_FROM_EMAIL: "healthcheck@mycompany.com" HC_USE_PAYMENTS: "False" HC_REGISTRATION_OPEN: "False" HC_EMAIL_HOST: "mail.mycomp-pdx.com" HC_EMAIL_PORT: "587" HC_EMAIL_HOST_USER: "healthcheck" HC_EMAIL_HOST_PASSWORD: "healthcheck-password" HC_EMAIL_USE_TLS: "False" HC_SITE_ROOT: "http://apps.mycomp-pdx.com/hc" HC_SITE_NAME: "MyCompany HealthChecks" HC_MASTER_BADGE_LABEL: "MyCompany HealthChecks" HC_PING_ENDPOINT: "http://apps.mycomp-pdx.com/hc/ping" HC_PING_EMAIL_DOMAIN: "mycompany.com" HC_TWILIO_ACCOUNT: "None" HC_TWILIO_AUTH: "None" HC_TWILIO_FROM: "None" HC_PD_VENDOR_KEY: "None" HC_TRELLO_APP_KEY: "None" volumes: HC_SQLite: HC_Data: ``` This is running in a docker container behind `nginx` that is rerouting traffic to port 3003 But even if I open the `localhost:3003` in browser on the docker server itself (directly talking to the container), I get the CSRF error. I know I'm doing something wrong but don't know what.
Author
Owner

@adampetrovic commented on GitHub (May 23, 2019):

Also seeing this error using the linuxserver docker container. I'm reverse proxying to a subdomain via NGINX.

<!-- gh-comment-id:495071107 --> @adampetrovic commented on GitHub (May 23, 2019): Also seeing this error using the linuxserver docker container. I'm reverse proxying to a subdomain via NGINX.
Author
Owner

@cuu508 commented on GitHub (Jun 5, 2019):

I had a look at galexrt/healthchecks:latest, and I think I understand what's happening, but am not sure what's the best fix.

With the above docker-compose.yml file the CSRF validation fails for me too when I access http://localhost:3003. If I flip HC_DEBUG to True, it gives a slightly more helpful error message:

Referer checking failed - Referer is insecure while host is secure.

So the Referer header has a "http://" URL but Django expects a "https://" URL.

Django expects a "https://" URL because its request.is_secure() returns True.

request.is_secure() returns True because gunicorn sets wsgi.url_scheme to http.

gunicorn does that because, with the default settings, it looks for a X-Forwarded-Ssl header, and find it.

The X-Forwarded-Ssl header is being set in nginx.conf.

In galexrt/docker-healthchecks README they actually have a note about this:

A HTTPS Proxy is required for healthchecks to be reachable. This is caused by the CSRF verification failing if HTTPS is not used. The HTTPS Proxy must pass through/create X-FORWARDED-* headers. An example for a simple HTTPS proxy for Docker can be found here: GitHub - jwilder/nginx-proxy.

So, setting up a HTTPS reverse proxy should fix the problem.

I haven't yet investigated linuxserver's Dockerfile.

<!-- gh-comment-id:499076042 --> @cuu508 commented on GitHub (Jun 5, 2019): I had a look at `galexrt/healthchecks:latest`, and I think I understand what's happening, but am not sure what's the best fix. With the above docker-compose.yml file the CSRF validation fails for me too when I access `http://localhost:3003`. If I flip `HC_DEBUG` to True, it gives a slightly more helpful error message: Referer checking failed - Referer is insecure while host is secure. So the Referer header has a "http://" URL but Django expects a "https://" URL. Django expects a "https://" URL because its `request.is_secure()` returns `True`. `request.is_secure()` returns True because gunicorn sets `wsgi.url_scheme` to `http`. gunicorn does that because, [with the default settings](https://docs.gunicorn.org/en/stable/settings.html?highlight=x-forwarded-ssl), it looks for a X-Forwarded-Ssl header, and find it. The X-Forwarded-Ssl header is being set in [nginx.conf](https://github.com/galexrt/docker-healthchecks/blob/master/includes/nginx/nginx.conf#L38). In `galexrt/docker-healthchecks` README they actually have a note about this: > A HTTPS Proxy is required for healthchecks to be reachable. This is caused by the CSRF verification failing if HTTPS is not used. The HTTPS Proxy must pass through/create X-FORWARDED-* headers. An example for a simple HTTPS proxy for Docker can be found here: GitHub - jwilder/nginx-proxy. So, setting up a HTTPS reverse proxy should fix the problem. I haven't yet investigated linuxserver's Dockerfile.
Author
Owner

@cuu508 commented on GitHub (Jul 20, 2019):

@eirannejad, @adampetrovic did you manage to solve the CSRF verification problem?

<!-- gh-comment-id:513466361 --> @cuu508 commented on GitHub (Jul 20, 2019): @eirannejad, @adampetrovic did you manage to solve the CSRF verification problem?
Author
Owner

@eirannejad commented on GitHub (Jul 20, 2019):

No to be honest. I played with it for a while but couldn't get it to work so I ended up using the cloud healthchecks for now. I learned a few things about CSRF during this time so I'll give it another go.

<!-- gh-comment-id:513486685 --> @eirannejad commented on GitHub (Jul 20, 2019): No to be honest. I played with it for a while but couldn't get it to work so I ended up using the cloud `healthchecks` for now. I learned a few things about CSRF during this time so I'll give it another go.
Author
Owner

@mrceperka commented on GitHub (Oct 23, 2020):

I've manged to hack (DO NOT USE THIS IN PRODUCTION) a way around this error.
I'm using galexrt/healthchecks:latest.
I've had to modify nginx.conf and convert referer's http protocol to https.

Working nginx.conf file (mostly copy of https://github.com/galexrt/docker-healthchecks/blob/master/includes/nginx/nginx.conf)
See # exra line

error_log /dev/stdout info;
worker_processes 1;

user healthchecks healthchecks;
pid /tmp/nginx.pid;

events {
    worker_connections 1024;
    accept_mutex off;
}

http {
    include mime.types;
    default_type application/octet-stream;
    access_log /dev/stdout combined;
    sendfile on;

    upstream app_server {
        server 127.0.0.1:8001 fail_timeout=0;
    }

    # extra lines
    map $http_referer $fake_https_referer  {
        ~http://(?<rest>(.*))   "https://$rest";
        default $http_referer;
    }

    server {
        listen 8000 default;
        client_max_body_size 10M;
        server_name _;

        keepalive_timeout 5;
        
        # extra line
        add_header X-Fake-Https-Referer $fake_https_referer;
        location /static {
            # path for static files
            alias /healthchecks/static-collected/;
        }

        location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            # extra line
            proxy_set_header Referer $fake_https_referer;

            proxy_set_header X-Forwarded-Ssl on;
            proxy_redirect off;
            proxy_pass http://app_server;
        }

    }
}
<!-- gh-comment-id:715383387 --> @mrceperka commented on GitHub (Oct 23, 2020): I've manged to _hack_ (DO NOT USE THIS IN PRODUCTION) a way around this error. I'm using `galexrt/healthchecks:latest`. I've had to modify `nginx.conf` and convert referer's http protocol to https. Working `nginx.conf` file (mostly copy of https://github.com/galexrt/docker-healthchecks/blob/master/includes/nginx/nginx.conf) See `# exra line` ```conf error_log /dev/stdout info; worker_processes 1; user healthchecks healthchecks; pid /tmp/nginx.pid; events { worker_connections 1024; accept_mutex off; } http { include mime.types; default_type application/octet-stream; access_log /dev/stdout combined; sendfile on; upstream app_server { server 127.0.0.1:8001 fail_timeout=0; } # extra lines map $http_referer $fake_https_referer { ~http://(?<rest>(.*)) "https://$rest"; default $http_referer; } server { listen 8000 default; client_max_body_size 10M; server_name _; keepalive_timeout 5; # extra line add_header X-Fake-Https-Referer $fake_https_referer; location /static { # path for static files alias /healthchecks/static-collected/; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; # extra line proxy_set_header Referer $fake_https_referer; proxy_set_header X-Forwarded-Ssl on; proxy_redirect off; proxy_pass http://app_server; } } } ```
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#172
No description provided.