403 Forbidden, Nginx config - django

I just started using Django and I try to deploy my project on the digital ocean server using Nginx. I am trying to set up SSL and domain (and they look good through the SSL checker and Google Dig DNS), however I get the 403 error in the browser once I try to access the webpage:
403 Forbidden
nginx/1.14.0 (Ubuntu)
I have been trying different things with Nginx config but it does not seem to help, here is what I have now:
http {
...
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/server_merged_key.crt;
ssl_certificate_key /etc/ssl/other_key.key;
root /var/www/html;
server_name domain.net www.domain.net ;
location / {
root /var/www/html;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_redirect off;
}
...
}
The Django project is located on the home of the server with no directory (just two folders /mysite1/mysite/). The server starts fine.
I do not see any GET request on the server side once I see the 403 error on the page. I do see the 400 error You're accessing the development server over HTTPS, but it only supports HTTP., if I try to access through http://IP-IN-NUMBER:8000.
Also, the settings.py looks like this, if this relevant to the issue:
DEBUG = False
ALLOWED_HOSTS = ['IP-IN-NUMBERS','localhost', '127.0.0.1','HTTP_X_FORWARDED_PROTO', 'https','domain.net'
,'www.domain.net']
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
How do I correctly set up Nginx for Django? Thank you so much for help!

Okay, so I figured it out with additional help, I will put answer in case it will be helpful for others. Basically I just needed to put my Django files in the root of /var/www/html, so they could be together with the index file. This way Nginx allows to access this directory and not throw 403 error.

Related

Django-Allauth OAuth2 problems with Gunicorn behind Nginx reverse proxy

I would ask for help on my specific configuration:
I have a Django application executed by gunicorn with an Nginx reverse proxy. Everything runs on the same Docker instance, run by Supervisord. Gunicorn runs on port 8000, Nginx runs on port 80.
Note: If I run only the Django application (no Nginx proxy) everything works properly and OAuth from Google works.
The Nginx config is
server {
listen 80;
location /static/ {
alias /home/app/static/static_assets/;
}
location /media-files/ {
internal; # only the django instance can access this url directly
alias /home/app/media/media_assets/;
}
location / {
proxy_pass http://localhost:8000;
}
}
I am trying to use the above solution to make OAuth2 work with Google. With the original configuration the error is as follows:
Error 400: redirect_uri_mismatch
The redirect URI in the request, http://localhost:8000/accounts/google/login/callback/, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs, visit: https://console.developers.google.com/apis/credentials/oauthclient/${your_client_id}?project=${your_project_number}
If I add the configuration snippet I get the error below:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
Code: unknown, Error: HTTPSConnectionPool(host='accounts.google.com', port=443): Max retries exceeded with url: /o/oauth2/token (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f79207eb640>: Failed to establish a new connection: [Errno -2] Name or service not known')))

Redirecting correctly HTTP to HTTPS using Django and Nginx

I'm trying to redirect my website from HTTP to HTTPS and I've succeeded partially doing so. The thing is, when I type mywebsite.fr, I get the name of the service of the container that contains the website's code in my address bar (e.g. Django app/) with a DNS_PROBE_FINISHED_NXDOMAIN error.
Now, I tried the same thing with another Chrome browser of another computer and this time when I type www.mywebsite.fr I get the same result whereas the non-www is correctly redirected to the secure address.
Finally, I tried the exact same process using my smartphone (Brave) with the www and non-www, I get https://djangoapp with an error ERR_NAME_NOT_RESOLVED whereas when I explicitly type https:\\mywebsite, I get no issues.
So here is the NGINX portion that redirects to the HTTPS server:
server {
...
location / {
return 301 https://djangoapp$request_uri;
}
}
This is the location in the HTTPS server that refers to the upstream:
server {
...
location / {
...
proxy_pass http://djangoapp;
}
}
And, this is the service that runs the code:
djangoapp:
build: .
ports:
- "8000:80"
links:
- db
depends_on:
- db
I do not master yet all the intricacies of NGINX and I do not really understand what I'm doing wrong here. Any solution or pieces of advice on this issue I'm having?
You are returning your django app url instead of redirecting it to your http nginx block.
In your http part of config:
server {
return 301 https://$host$request_uri;
listen 80;
}
And in https, when proxy passing if you dont want the url to change to the url of your django app, you should add proxy_set_header Host $http_host;. It's also useful to add some additional headers like ip address. So the overal server block will look like:
server {
location / {
proxy_set_header Host $http_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_pass http://djangoapp;
}
}
My problem was resolved because my proxy_set_header X-Forwarded-Proto was set to $https instead of https. Using $scheme as suggested also works fine.
By reading #mehrad's comment and searching a little bit on the web again, I found the bug on why the redirection was not working properly. This also includes using $host as opposed to djangoapp.

Django won't get https header

Intro
I am building a web app using the latest Django version along with python3.7. The app is dockerized and I plan to deploy with docker-compose. Inside the container, I use nginx to proxy traffic to the application and not expose it directly. Also, I use apache in server level to proxy traffic to various other containers hosted on the same machine.
In the Django application, I use oauth2 to authenticate to Fitbit Web API and the issue I am facing is that the django-social-auth is passing the hostname automatically as a redirect_uri which now, after a lot of configuration with all those proxies, works perfectly in HTTP but when I use HTTPS although the app responds normally the redirect_uri is still http which obviously is not allowed by fitbit and very risky.
Although it is very hard for me to locate in which level the problem occurs I have tried various things but nothing seems to work out.
What I have tried
First
I tried to make my container listen to https request which seemed the most appropriate solution to me but ended getting 502 errors from the Apache.
I tried to find a solution on this by adding some configuration to the virtual host file like
#Solution 1
SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyPass / https://localhost:83/ Keepalive=On #Solution 2 (keep alive)
ProxyPassReverse / https://localhost:83
But at last, I found out that it was not an apache issue but that the nginx inside the container was not responding although the traffic was routed to 443 port using HTTPS
Second
I tried to route traffic from the apache https to containerd nginx HTTP ( which does not make so much sense to me ) which makes the application respond normally but and results the redirect_uri error I mentioned above
As you can see I more or less confused and any kind of hint or help could be very useful
Update 1
The nginx configuration as requested in the comments
server {
listen 80;
listen 443 default_server ssl;
server_name localhost;
charset utf-8;
location /static {
alias /app/static/;
}
location /upload {
alias /app/media/;
}
location / {
proxy_pass http://web:8000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
I was able to fix the issue by adding the following configuration on the settings.py. I also added a control conditional in order to be able to run the container in development.
# Was already present before the issue resolved but is also needed
USE_X_FORWARDED_HOST = True
# The actual solution
if eval(os.environ.get('DEPLOY', default=False)):
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Django, nginx, + gunicorn: connection refused when serving media files

I have a Django app served by gunicorn with nginx handling incoming requests. Static files are served just fine, and media files are served in my local development environment- I have MEDIA_ROOT and MEDIA_URL set.
However, on my web host (running Ubuntu 14.04), media files aren't served. Even if I run the Django dev server instead of letting gunicorn serve the app, media files do not show up and the following errors are output to the console:
Since taking gunicorn out of the equation results in the same behavior, I believe the issue is with my nginx configuration. This is my sites-available for the app:
server {
listen 443 ssl;
server_name <server name here>;
<ssl stuff here>
access_log off;
location /static {
alias /opt/testenv/testenv/proj/static/;
}
location /media {
autoindex on;
alias /opt/testenv/testenv/proj/media/;
}
location ~ /.well-known {
allow all;
}
location / {
proxy_pass http://127.0.0.1:9900;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
}
}
server {
listen 80;
server_name <server name here>;
return 301 https://$host$request_uri;
}
I was initially missing the location /media block, which I thought was the issue. However, even after adding it, restarting nginx, and running collectstatic, I still get CONNECTION REFUSED errors when attepting to retrieve the files.
I turned on autoindex to verify that the files can be navigated to manually, and that does work.
The nginx error log doesn't contain anything related to these connection errors, which is curious to me- could the request be getting rejected elsewhere? I recently setup HTTPS but this issue was occurring even before that.
Looks like you are making requests directly to gunicorn instead of nginx,from you configuration you should visit:
https://127.0.0.1
instead of:
http://127.0.0.1:9900

letsencrypt django webroot

I am trying to setup my nginx and django to be able to renew certificates.
However something goes wrong with my webroot-plugin
in nginx:
location ~ /.well-known {
allow all;
}
But when I run the renewal command:
./letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --webroot-path=/home/sult/huppels -d huppels.nl -d www.huppels.nl
However it seems that the cert renewal wants to retrieve a file from my server cause i get the following error.
The following errors were reported by the server:
Failed authorization procedure. www.huppels.nl (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.huppels.nl/.well-known/acme-challenge/some_long_hash [51.254.101.239]: 400
How do i make this possible with nginx or django?
I have my Django app running with gunicorn. I followed the instructions here.
I made sure to include the proper location blocks:
location /static {
alias /home/user/webapp;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Making sure to include any template location alias as well.
I set the .well-known location block like this;
location /.well-known {
alias /home/user/webapp/.well-known;
}
Pointing it directly do the root of the webapp instead of using the allow all.
I did have to make sure that I only used the non ssl block until the certificate was generated then I used a different nginx config based on h5bps nginx configs.
Note: Make sure you have proper A records for you domain pointing to www if you are going to use h5bp to redirect to www.