11

I have a model News with an image and those News can be loaded via an JSON REST API. The server is signed with a certificate from an Authority and all request must be done with https.

My problem is, the ModelSerializer serialize the ImageField with http and not https. How do I change that ?

Here is an abstract of code and output example:

#myProject/models.py
class News(models.Model):
    image = models.ImageField()

#myProject/serializers.py
class NewsSerializer(serializers.ModelSerializer):
    class Meta:
        model = News
        fields = ('image')

#request for a news
https://myDomain/news/the-news-id-here/

#current output
{
    "image": "http://myDomain/media/news/imageName.jpg"
}

#wanted output
{
    "image": "https://myDomain/media/news/imageName.jpg"
}

Thanks David

David Kühner
  • 793
  • 1
  • 7
  • 19
  • 4
    The scheme used in the generated response is determined dynamically, based on the scheme used for the request it self. Are you querying the server over HTTPS? You will also get different behaviour on the development server, which will always use HTTP. Also check if you are using an internal proxy that talks to Django over HTTP, in which case you need to set [SECURE_PROXY_SSL_HEADER](https://docs.djangoproject.com/en/1.8/ref/settings/#secure-proxy-ssl-header). – solarissmoke Oct 02 '15 at 12:54
  • 6
    In nginx use `proxy_set_header X-Forwarded-Proto https;` – dukebody Oct 02 '15 at 14:05

3 Answers3

4

Please consider adding proxy_set_header X-Forwarded-Proto https; inside of your Nginx virtual host file i.e conf file located within /etc/nginx/sites-available/. So, in a nutshell, your conf file may look like this:

server {
    listen   443 ssl;
    server_name example.com www.example.com;
    root /var/www/html/static_files/;

    client_max_body_size 4G;
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    access_log /home/user/API/logs/nginx-access.log;
    error_log /home/user/API/logs/nginx-error.log;

    location /api/ {
        proxy_pass http://127.0.0.1:8000/api/;
    }

    location /media/ {
        proxy_pass http://127.0.0.1:8000/media/;
    }

    # Error pages
    # error_page 500 502 503 504 /home/user/API/500.html;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}

In conclusion, after adding proxy_set_header X-Forwarded-Proto https;. Your REST API will be redirected to https. Credit to dukeboy for his comment.

Brian
  • 406
  • 1
  • 5
  • 8
  • 2
    Still does not work, even with the header. I'm using Django 1.11. Edit: you need to put `SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')` in your Django settings – h345k34cr May 17 '20 at 09:50
  • Thank you for highlighting that – Brian Jun 10 '20 at 14:22
0

You can do this in nginx config, like this

server {
    listen         80;
    return 301 https://$host$request_uri;
}
Ali
  • 2,541
  • 2
  • 17
  • 31
0

I faced the same problem, my work around was to add the full url with https in the MEDIA_URL, inside django's settings.py file:

Before modification:

MEDIA_URL = '/media/'

After modification:

MEDIA_URL = 'https://www.my-app.com/media/'

No need to tweak nginx configs.