Nginx static files 404 with django swagger rest api - django

I have Django rest API application and swagger for that is working fine locally. I am trying to configure it using containers and deploy it on ECS.
Now when I build and run the container the application works fine (I mean the swagger UI is appearing). When I attach the application load balancer to it, on the browser it is giving me 404 files not found for js and CSS files.
Here is the console output from the web browser.
Here is my Nginx config file
# nginx.default
add_header X-Content-Type-Options nosniff;
include /etc/nginx/mime.types;
add_header X-XSS-Protection "1; mode=block";
server {
listen 8020;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
proxy_pass http://127.0.0.1:8010;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static {
root /home/app/codebase;
}
}
THe path of static folder inside docker container is /home/app/codebase/static/
Also added the following lines in the Django Settings.py file.
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
Not sure what am I missing. Any leads will be appreciated.
I have looked into these questions. The problem is something similar but not sure what I'm missing.

Posting the solution in case anyone still facing the same kind of issue.
I provisioned all the resources using IaC (Cloud Formation) so while provisioning Load Balancer I created the one target group but at that time the ECS services were not created, so I created a dummy target group that drops the traffic and was not routing the traffic to any service.
And in ALB's path-based routing, the last route (which the traffic uses when the request does not find any route) was directing traffic to a dummy target group.
As soon as I changed the target group everything works like a charm.
Working Fine
Pro Tip:
Always use any of the target groups from your application in the last ALB rule.

Related

nginx working with ip but not domain name

I'm trying to set up a django app with gunicorn and ngix. I followed this tutorial. Everything seems to be working but when I edit the server_name in /etc/nginx/sites-available/project to anything other than the serevr ip address I get the default nginx index page instead of the django app. When this is the server config:
server {
listen 80;
server_name <myserverip>;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/django/project;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
everything works as expected (nginx serves the app) when I put the ip address into my browser, but if the I add a domain name to replace the ip or in addition to the ip all I get is the nginx page in either location. My ALLOWED_HOSTS in settings.py includes the server ip and the domain name. I cannot see any issue in the nginx logs either. Not sure what the issue is at this point.
You should be able to change the server_name to include your domain:
server_name <myserverip> <mydomainname>;
Feel free to drop the ip address if you only want to be able to access the site using your domain name. You'll also want to add any subdomains (i.e. www) you want to serve the same site. For example:
server_name youdomainname.com www.yourdomainname.com;
Don't forget to restart nginx after updating the config file.
In server_name you can write an IP or URL, but at the same time in your settings.py you must give it permission.
[settings.py]
ALLOWED_HOSTS = ['IP', 'URL']
Here, I uploaded something to my github that can help you:
Github/Nginx
I solved the issue. The nginx default configuration /etc/nginx/sites-available/default was shadowing mine. I commented out the server portion of the default configuration and the domain is working as expected.

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

Elasticbeanstalk Nginx Reverse Proxy Conf for Different Server

I am looking to reverse proxy a different server IP from my application when a user goes to /blog on my website. I have set up what I believe to be the correct nginx location block configuration and successfully deployed an ebextension with the configuration, but when I navigate to /blog I receive the 404 page that is rendered from my application's server. On further inspection the request shows that the request was made to the application IP and not the IP address found in the /blog location block in my nginx setup. Can anyone help determine what might be wrong with either my ebextension, nginx or application setup that is preventing the nginx location block to work? I'm not sure how to test beyond requesting the url and checking the network resource tab in my develop tools.
Here is my ebextensions folder setup:
> ebextensions
=> nginx
==> conf.d
==- 01_nginx_blog_rp.config
-00_nginx_https_rw.config
-02_sequelize_db_migration.config
01_nginx_blog_rp.config:
files:
"/etc/nginx/conf.d/01_blog_proxy.conf":
mode: "000644"
owner: root
group: root
content: |
client_max_body_size 10M;
"/etc/nginx/conf.d/02_blog_location_block.conf":
mode: "000644"
owner: root
group: root
content: |
server {
location /blog {
proxy_pass http://xxx.xxx.xxx.xxx:2368;
proxy_set_header Host $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;
}
}
container_commands:
01_reload_nginx:
command: "sudo service nginx reload"
What you trying to achieve is not possible with just adding simple location block in conf.d.
You basically defining a new server block with location inside. This new server block is never used by nginx because you already have default server config generated by ElasticBeanstalk with configured listen and server_name directives. This two directives are used by nginx to decide where to forward request, therefore all incoming requests going to your application server and ignoring your customizations.
What you really need to do is to modify existing server block and add your location into it.
This can be done in a few different ways:
- Create new nginx config and delete default one.
In this aws documentation example they just adding a new .ebextensions/proxy.config and replace default nginx config with the custom one. Using this approach you can have a full control of your nginx configuration.
- Create new config and make it processed before default one.
If you still want to keep default config around you can just keep using your 00_nginx_https_rw.config name of config, this way nginx will process your config first, and if in your config you will have correct server_name and listen it will be used by nginx to process incoming request.
- Add hook to modify default config.
On AWS forum you can find another solution - add bash script hook to
modify existing config.

What does the proxy_pass option in the NGINX config do?

What does the NGINX proxy_pass config do? Let's say for example I have a Django app that is hosted up on Amazon's EC2 services.
On EC2, let's say I have 1 load balancer in front of 2 nginx servers. The nginx servers point to the 4 django app servers that use Gunicorn as there WSGI server:
upstream my-upstream {
server 12.34.45.65:8000;
server 13.43.54.56:8000;
server 13.46.56.52:8000;
server 14.46.58.51:8000;
}
location / {
proxy_pass http://my-upstream;
}
What is the proxy_pass? would it be the URL of the load balancer in this case?
Take a look at nginx's HttpProxyModule, which is where proxy_pass comes from. The proxy_pass docs say:
This directive sets the address of the proxied server and the URI to
which location will be mapped.
So when you tell Nginx to proxy_pass, you're saying "Pass this request on to this proxy URL".
There's also documentation on upstream available:
This directive describes a set of servers, which can be used in
directives proxy_pass and fastcgi_pass as a single entity.
So the reason that you use upstream for proxy_pass is because proxy_pass is expecting one URL, but you want to pass it more than one (so you use an upstream).
If your load balancer is in front of your nginx, your load balancer URL won't be in this config.
It should be:
proxy_pass http://my-upstream;
nginx will load-balance all requests over your 4 djano+gunicorn instances (your my-upstream). The load-balancers will point to the nginx servers.

How to proxy proxy domain name to internal app server URL in Nginx?

I have an internal app server (Django+gunicorn) running behind an Nginx reverse proxy on a private port (listening on port 5000, for example.)
There are several Django apps installed in the app server, mapped to separate base paths. Example:
/app1
/app2
Where /app1 serves up content for domain1.com and /app2 serves content for domain2.com.
I'd like to silently reverse proxy incoming requests for specific hostnames to the related backend app, while preserving the path forwarded to the internal app server:
http://domain1.com/foo --> /app1/foo
http://domain1.com/bar/bletch --> /app1/bar/bletch
http://domain2.com/alpha/bravo --> /app2/alpha/bravo
I suppose you could say I'm trying to set up a simple 'virtual hosting' configuration but I want to use a shared back-end app server instance.
Key point: I don't want the visitor's browser to see the redirected URL structure. So when the client browser hits http://domain1.com/foo, the correct content is served up but the browser doesn't see a redirect.
I've done some basic work with Nginx (still learning) and I'm looking for example Nginx configurations demonstrating secure and efficient ways to accomplish this goal.
Based on this answer here's a configuration that seems to work as desired.
For app1 running on http://localhost:8000/app1_path :
upstream app1 {
server 127.0.0.1:8000 fail_timeout=0;
}
server {
listen 80;
server_name example.com
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
rewrite ^(.*)$ /app1_path$1 break;
proxy_pass http://app1;
}
}
So, one could repeat this pattern as many times as desired for each hostname->app/path pair.