mediacms-io / mediacms

MediaCMS is a modern, fully featured open source video and media CMS, written in Python/Django and React, featuring a REST API.
https://mediacms.io
GNU Affero General Public License v3.0
2.71k stars 500 forks source link

Trouble With Reverse Proxy #63

Closed MikeyYeahYeah closed 3 years ago

MikeyYeahYeah commented 3 years ago

I run my own Nginx reverse proxy with SSL termination. I am experiencing an interesting issue.

When I set the FRONTEND_HOST variable in the deploy/docker/local_settings.py to https://mydomain.example.com and start the app, all of the links and login logic work well and point to the correct domain.

However, any assets IE videos and images do not point to the correct link. They will point to my IP Address and port for some reason. Not sure what I am doing wrong. Posting snippets below:

I am using the standard docker-compose.yml file. The only modification I have made was setting the web ports from 80:80 to 10100:80

nginx config

server {
    server_name mydomain.example.com;
    client_max_body_size 0;
    location / {
      proxy_set_header X-Forwarded-Host $host:$server_port;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass         http://192.168.X.X:10100;
    }

    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/mydomain.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mydomain.example.com/privkey.pem;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

server {
    if ($host = mydomain.example.com) {
        return 301 https://$host$request_uri;
    }

    listen   80;
    server_name mydomain.example.com;
    return 404;
}
swiftugandan commented 3 years ago

Not sure whats going on there, but you can have a look at what nginx-proxy does in this example: https://github.com/mediacms-io/mediacms/blob/main/docs/Docker_deployment.md#advanced-deployment-with-reverse-proxy-accessed-as-httpslocalhost

mgogoulos commented 3 years ago

Hi, not sure if it is related, checkout the Site variable at /admin/sites/site/ and make sure it's the same as the FRONTEND_HOST. The site is an important variable for Django applications. It takes the value you set as FRONTEND_HOST on deploy/docker/local_settings.py upon first time run (when the image is created), so if you set a new one at some point later you will have to change this to reflect the new one. If this makes any difference let us know!

MikeyYeahYeah commented 3 years ago

Very strange... I went to admin/sites/site and all I saw in there was example.com.

For some reason, the links are all over the place. For science, I tried setting the FRONTEND_LOCAL value to http://localhost, rebuilt, and restarted.

All links on the side navbar point use localhost as the base URL EXCEPT the following links that actually point to my subdomain correctly:

My Media
My Playlist
About
Terms
Contact

What is different about these? Is this value not being fed to React correctly? This is very odd. I do appreciate your patience with my questions. Django is a magical mystery box to me. Every other app I deploy using docker-compose respects my nginx reverse proxy without issue.

swiftugandan commented 3 years ago

This is the config that nginx-proxy container uses for mediacms.example.com tested it, and works for me.

# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
# scheme used to connect to this server
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
  default $http_x_forwarded_proto;
  ''      $scheme;
}
# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
# server port the client connected to
map $http_x_forwarded_port $proxy_x_forwarded_port {
  default $http_x_forwarded_port;
  ''      $server_port;
}
# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any
# Connection header that may have been passed to this server
map $http_upgrade $proxy_connection {
  default upgrade;
  '' close;
}
# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Default dhparam
ssl_dhparam /etc/nginx/dhparam/dhparam.pem;
# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
  default off;
  https on;
}
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
log_format vhost '$host $remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent"';
access_log off;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
        ssl_prefer_server_ciphers off;
resolver 127.0.0.11;
# HTTP 1.1 support
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
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 $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";
server {
    server_name _; # This is just an invalid value which will never trigger on a real hostname.
    listen 80;
    access_log /var/log/nginx/access.log vhost;
    return 503;
}
# mediacms.example.com
upstream mediacms.example.com {
                ## Can be connected with "mediacms_default" network
            # mediacms_web_1
            server 192.168.128.8:80;
}
server {
    server_name mediacms.example.com;
    listen 80 ;
    access_log /var/log/nginx/access.log vhost;
    # Do not HTTPS redirect Let'sEncrypt ACME challenge
    location /.well-known/acme-challenge/ {
        auth_basic off;
        allow all;
        root /usr/share/nginx/html;
        try_files $uri =404;
        break;
    }
    location / {
        return 301 https://$host$request_uri;
    }
}
server {
    server_name mediacms.example.com;
    listen 443 ssl http2 ;
    access_log /var/log/nginx/access.log vhost;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /etc/nginx/certs/mediacms.example.com.crt;
    ssl_certificate_key /etc/nginx/certs/mediacms.example.com.key;
    add_header Strict-Transport-Security "max-age=31536000" always;
    location / {
        proxy_pass http://mediacms.example.com;
    }
}

I suspect these two:

upstream mediacms.example.com {
                ## Can be connected with "mediacms_default" network
            # mediacms_web_1
            server 192.168.128.8:80;
}

and

    location / {
        proxy_pass http://mediacms.example.com;
    }

might make it work in your case

mgogoulos commented 3 years ago

Very strange... I went to admin/sites/site and all I saw in there was example.com.

For some reason, the links are all over the place. For science, I tried setting the FRONTEND_LOCAL value to http://localhost, rebuilt, and restarted.

All links on the side navbar point use localhost as the base URL EXCEPT the following links that actually point to my subdomain correctly:

My Media
My Playlist
About
Terms
Contact

What is different about these? Is this value not being fed to React correctly? This is very odd. I do appreciate your patience with my questions. Django is a magical mystery box to me. Every other app I deploy using docker-compose respects my nginx reverse proxy without issue.

Hi, /admin/sites/site is getting used in several places but you are right, it isn't the domain that the media urls are served from. This should be the FRONTEND_HOST variable on deploy/docker/local_settings.py

Some urls are hardcoded indeed as relative urls, in files as templates/config/core/user.html

swiftugandan commented 3 years ago

@MikeyYeahYeah did any of the suggestions work for you? Please update for the benefit of anyone who reads this in future

MikeyYeahYeah commented 3 years ago

Sadly they did not. I am sure there is a solution to the problem but I just ran out of time to troubleshoot this one. It's probably something I am doing so closing the issue.

scyto commented 2 years ago

try setting this in the server location and dropping your other headers

        proxy_set_header Host              $server_name; 
        proxy_set_header X-Forwarded-Proto https; 

AKA do NOT use these

      proxy_set_header X-Forwarded-Host $host:$server_port;
      proxy_set_header X-Forwarded-Server $host;

i just used this on a quick CMS docker local install:

    location /  {
        proxy_set_header Host              $server_name; 
        proxy_set_header X-Forwarded-Proto https; 
        proxy_pass                         http://ipofcmshost:8066;
                }

(i do note, as documented, the docker-compose.yaml doesn't work and the built in ngix instance keeps redirecting browsers to SSL even though the default using docker-compose..yaml shouldn't do that, i would offer to correct the docs but was just helping someone out who couldn't figure out how to get any of this working, not surprising as the docker stuff doesn't work as documented)

mgogoulos commented 2 years ago

Hi @scyto , please open a PR with any changes you believe are needed on the docs and/or the docker-compose files and we can discuss there!