Nginx Proxy Pass Always Returning 404s - docker

So I'm working on a POC for a micro-frontend architecture. I am using nginx as the driver for this. In my local environment, I'm testing the docker configuration for the projects. Each micro-frontend will be in its own docker container, and they will share a network. The container names are:
micro-fe-parent
micro-fe-react-wc
The goal is to get micro-fe-parent to be able to load content from micro-fe-react-wc via an nginx proxy. My webpack dev server proxy setup works perfectly with my existing code, but with nginx all I'm getting is 404s.
I can shell into the container and use curl to hit the micro-fe-react-wc application directly, and I can manually request any file successfully this way. So the containers can see each other, the docker network is working. Something in the proxy pass is not working. Unfortunately, nginx logs are no help, and it's debugging tools are really lacking.
The goal of the proxy is that any URI it sees that starts with /react-wc, it will remove the /react-wc part and resolve the rest of the URI against the target host. So let's say I have a file called "app.js", the request I would be making from micro-fe-parent would be /react-wc/assets/app.js, and nginx would proxy that to http://micro-fe-react-wc/assets/app.js, preserving most of the URI but removing that one path element.
I've tried everything I can think of to configure this properly.
Here is my nginx.conf:
worker_processes auto;
events {
worker_connections 1024;
multi_accept on;
}
http {
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $upstream_addr '
'"$http_referer" "$http_user_agent"';
log_format new_format '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request upstream_response_time $upstream_response_time msec $msec request_time $request_time';
include /etc/nginx/mime.types;
default_type text/plain;
gzip on;
gzip_disable "msie6"
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_proxied any;
gunzip on;
gzip_static always;
gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/xml+rss;
gzip_vary on;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
server {
listen 80;
server_name micro-fe-parent;
access_log /var/log/nginx/access.log new_format;
error_log /var/log/nginx/error.log debug;
rewrite_log on;
root /var/www;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /react-wc {
rewrite '^/react-wc(/.*)$' '$1' break;
proxy_pass http://micro-fe-react-wc;
}
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~* \.(?:css|js)$ {
try_files $uri =404;
expires 1y;
access_log off;
add_header Cache-Control "public";
}
location ~ ^.+\..+$ {
try_files $uri =404;
}
}
}

So the problem was I wasn't using ^~ to treat it like a regex match, so it was looking for a literal /react-wc path instead of as a matcher on the path.
location ^~ /react-wc {
rewrite '^/react-wc(/.*)$' '$1' break;
proxy_pass http://micro-fe-react-wc;
}

Related

Docker ngix/traefik 301 redirecting http to https in localhost

This is a follow up to Turn off https in Docker with some more information. I still haven't figured it out.
I asked in the Docker slack group and they are convinced it's coming from the nginx or traefik config.
In Firefox there is a SSL_ERROR_UNRECOGNIZED_NAME_ALERT error, and in Chrome it's the similar ERR_SSL_UNRECOGNIZED_NAME_ALERT. I'm not finding out much about either of those by searching.
My nginx config:
user nginx;
daemon off;
worker_processes auto;
error_log /proc/self/fd/2 debug;
events {
worker_connections 1024;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
fastcgi_buffers 16 32k;
fastcgi_buffer_size 32k;
fastcgi_intercept_errors on;
fastcgi_read_timeout 900;
include fastcgi_params;
access_log /proc/self/fd/1;
port_in_redirect off;
send_timeout 600;
sendfile on;
client_body_timeout 600;
client_header_timeout 600;
client_max_body_size 256M;
client_body_buffer_size 16K;
client_header_buffer_size 4K;
large_client_header_buffers 8 16K;
keepalive_timeout 60;
keepalive_requests 100;
reset_timedout_connection off;
tcp_nodelay on;
tcp_nopush on;
server_tokens off;
upload_progress uploads 1m;
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 2;
gzip_http_version 1.1;
gzip_min_length 20;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/x-icon application/vnd.ms-fonto
gzip_vary on;
gzip_proxied any;
gzip_disable msie6;
add_header X-XSS-Protection '1; mode=block';
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
map $http_x_forwarded_proto $fastcgi_https {
default $https;
http '';
https on;
}
map $uri $no_slash_uri {
~^/(?<no_slash>.*)$ $no_slash;
}
upstream backend {
server php:9000;
}
include conf.d/*.conf;
}
My nginx.conf.default:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
My docker-compose.yml is unchanged from the previous question.
I've looked for anthing resembling traefik config and can't find anything.
Things I've tried so far:
swapping things round inside the map $http_x_forwarded_proto $fastcgi_https i.e. default $http; http on; https '';
deleting that whole map block
removing the references to https in line 140 of docker-compose.yml
removing line 143 from docker-compose.yml
removing line 147 from docker-compose.yml
creating a self-signed certificate for localhost
sackcloth and ashes
I'm genuinely at a loss, any help appreciated.
After more tests from OP, and other user's comments: it seemed that the redirection (HTTP to HTTPS) was occurring after Nginx handled the request.
OP also tested using a single index.html file and was not redirected to HTTPS: confirming that the redirection came from PHP (or at least not from Nginx).
The next steps were to look into Drupal configuration, and/or htaccess configuration. OP changed some Drupal configuration (about redirections), and successfully got the drupal setup page working with HTTP only.
Best in those case is always to try to pin-point the where the issue come from:
Make your Nginx configuration minimal: simple index.html
Clear browser cache regularly: they sometimes cache the redirection
Check/remove htaccess to see if behavior changes
Finally, if Nginx is "clean" from any issue, and htaccess doesn't seem to be the issue: it's mostly "after", so the issue may come from "to who Nginx is sending the request"
From "large" frameworks/CMS like Drupal, Woocommerce, Laravel... Redirection is usually handled "easily" from configuration files or DB settings.
When you have custom code handling redirections: it'll need debugging

nginx redirect for urls without trailing slash doesn't work in docker when not using default port 80

Here is a website based on gatsby.
When running with -p 80:80, it's accessible to http://localhost/docs/infrastructure/components, which has no trailing slash.
docker run -itd -p 80:80 --env-file env.list --name docs.kubesphere.io kubesphere/docs.kubesphere.io:v2.1
When running with -p 81:80, it's not accessible to http://localhost:81/docs/infrastructure/components. The browser received a redirect to http://localhost/docs/infrastructure/components/, not http://localhost:81/docs/infrastructure/components/.
docker run -itd -p 81:80 --env-file env.list --name docs.kubesphere.io kubesphere/docs.kubesphere.io:v2.1
nginx conf is as follows:
daemon off;
worker_processes 1;
user root;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
keepalive_timeout 15;
autoindex off;
server_tokens off;
port_in_redirect off;
sendfile off;
tcp_nopush on;
tcp_nodelay on;
client_max_body_size 64k;
client_header_buffer_size 16k;
large_client_header_buffers 4 16k;
## Cache open FD
open_file_cache max=10000 inactive=3600s;
open_file_cache_valid 7200s;
open_file_cache_min_uses 2;
## Gzipping is an easy way to reduce page weight
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_types application/javascript application/x-javascript application/rss+xml text/javascript text/css image/svg+xml;
gzip_buffers 16 8k;
gzip_comp_level 6;
access_log /dev/stdout;
error_log /dev/stderr error;
server {
listen 80;
root /pub;
index index.html;
autoindex off;
charset utf-8;
error_page 404 /404.html;
location ~* \.(html)$ {
add_header Cache-Control "no-store";
expires off;
}
location ~* \.(ico|jpg|jpeg|png|gif|svg|js|jsx|css|less|swf|eot|ttf|otf|woff|woff2)$ {
add_header Cache-Control "public";
expires +1y;
}
rewrite ^([^.]*[^/])$ $1/ permanent;
try_files $uri $uri/ $uri/index.html =404;
}
}
Without rewrite ^([^.]*[^/])$ $1/ permanent;, the browser still can reveive 301 Moved Permanently (from disk cache) and then appended a trailing slash when using -p 80:80. Changing to -p 81:81 found some pages can receive 81 port in its response header, but some can't.
I'm wondering why the browser can recevie 301 status code?
Is it sent by nginx?
How can I verify it?

Enable gzip with docker and bitnami/nginx

I deployed a website with docker and bitnami/nginx as image: https://www.10studio.tech/demo. After deployment, I realized that files like analyzejs.js was not gzipped:
Here is docker-compose.yml:
version: "3"
services:
docusaurus:
image: bitnami/nginx:1.16
restart: always
volumes:
- ./build:/app
- ./certs:/certs:ro
- ./my_server_block.conf:/opt/bitnami/nginx/conf/server_blocks/my_server_block.conf:ro
ports:
- "3001:3001"
- "3002:3002"
Here is my_server_block.conf:
server {
listen 3002;
absolute_redirect off;
root /app;
location = / {
rewrite ^(.*)$ https://$http_host/docs/introduction redirect;
}
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 3001 ssl;
ssl_certificate /certs/server.crt;
ssl_certificate_key /certs/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:3002;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Ssl on;
}
}
Here is /opt/bitnami/nginx/conf/nginx.conf, where gzip seems to be enabled:
I have no name!#8317023de7ec:/app$ cat /opt/bitnami/nginx/conf/nginx.conf
# Based on https://www.nginx.com/resources/wiki/start/topics/examples/full/#nginx-conf
# user www www; ## Default: nobody
worker_processes auto;
error_log "/opt/bitnami/nginx/logs/error.log";
pid "/opt/bitnami/nginx/tmp/nginx.pid";
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log "/opt/bitnami/nginx/logs/access.log";
add_header X-Frame-Options SAMEORIGIN;
client_body_temp_path "/opt/bitnami/nginx/tmp/client_body" 1 2;
proxy_temp_path "/opt/bitnami/nginx/tmp/proxy" 1 2;
fastcgi_temp_path "/opt/bitnami/nginx/tmp/fastcgi" 1 2;
scgi_temp_path "/opt/bitnami/nginx/tmp/scgi" 1 2;
uwsgi_temp_path "/opt/bitnami/nginx/tmp/uwsgi" 1 2;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
keepalive_timeout 65;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
include "/opt/bitnami/nginx/conf/server_blocks/*.conf";
# HTTP Server
server {
# port to listen on. Can also be set to an IP:PORT
listen 8080;
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
}
Does anyone know what's wrong here and how I could enable gzip?
I also just stumbled over the same problem. It seems like the docker image already has gzip enabled. I also have an nginx deployed for the whole server which acts as reverse proxy for the different docker container in the server. What worked for me is to also enabled gzip in the global nginx configuration /etc/nginx/nginx.conf.
Don't know if you also have a wrapping nginx. Hope this helps.

After deploy I see standard nginx's "It works!"

I've deployed rails app with Capistrano to VPS, and when I try to access it with "APP_NAME.com", I see standard Nginx's "It works!" page.
I've tried to remove index.html file from /var/www folder, now I see folders in it: apps, log and tmp.
In nginx.conf I have:
user nginx web;
pid /var/run/nginx.pid;
error_log /var/www/log/nginx.error.log;
events {
worker_connections 1024;
accept_mutex off;
use epoll;
}
http {
include mime.types;
types_hash_max_size 2048;
server_names_hash_bucket_size 64;
default_type application/octet-stream;
access_log /var/www/log/nginx.access.log combined;
sendfile on;
tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
tcp_nodelay off; # on may be better for some Comet/long-poll stuff
gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 0;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 9;
gzip_types text/plain text/xml text/css
text/comma-separated-values
text/javascript application/x-javascript
application/atom+xml;
upstream app_server {
server unix:/var/www/apps/APP_NAME/socket/.unicorn.sock fail_timeout=0;
}
server {
pagespeed on;
pagespeed FileCachePath /var/ngx_pagespeed_cache;
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
add_header "" "";
}
location ~ "^/ngx_pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
location /ngx_pagespeed_statistics {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
location /ngx_pagespeed_global_statistics {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
pagespeed MessageBufferSize 100000;
location /ngx_pagespeed_message {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
location /pagespeed_console {
allow 127.0.0.1; allow 5.228.169.73; deny all;
}
charset utf-8;
listen 80 default deferred; # for Linux
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
root /var/www/apps/APP_NAME/current/public;
try_files $uri/index.html $uri.html $uri #app;
location ~ ^/(assets)/ {
root /var/www/apps/APP_NAME/current/public;
expires max;
add_header Cache-Control public;
}
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/apps/APP_NAME/current/public;
}
}
}
Am I missing something in nginx.conf or in other files?
Also, when I stop nginx server, it doesn't make sense, I see the same page.
I'm not good in deploying apps to server, it's my first time without Heroku, so I don't know, what exactly you need to know, to help in my problem. So, if you need any additional info, ask, I'll add it to question.
Thanks!
So, I've found the solution from this answer. The problem was with Apache web server, which was running in background and prevent Nginx to run on 80 port.
I've stopped Apache server and restart Nginx, and everything now works ok:
sudo apachectl stop
sudo restart nginx
Your must use passenger and set in nginx config something like this:
http {
passenger_root /home/deployer/.rvm/gems/ruby-1.9.3-p327/gems/passenger-3.0.18;
passenger_ruby /home/deployer/.rvm/wrappers/ruby-1.9.3-p327/ruby;
...
or use HTTP server for Rack, as example Unicorn, and set in nginx config:
upstream app_server {
server unix:/path/to/.unicorn.sock fail_timeout=0;
...
server {
proxy_pass http://app_server;
...

Compressing rails assets and nginx gzip

Do I have to configure nginx to compress assets (gzip set to on) if I have compressed rails assets with rake assets:precompile? I mean does it make sense or not? Will performance better or worse? Thank you!
Do rake assets:precompile and you have to configure nginx for send gzip version of files, i use this configuration.
user www-data www-data;
worker_processes 4;
pid /var/run/nginx.pid;
events{
worker_connections 2048;
use epoll;
}
http{
include mime.types;
default_type application/octet-stream;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
server_tokens off;
server_name_in_redirect off;
ignore_invalid_headers on;
gzip off;
sendfile on;
upstream reverse-proxy{
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}
server{
listen 80;
server_name _;
root /home/www-data/my_website/public;
client_max_body_size 10M;
client_body_buffer_size 512k;
location ~ ^/assets/ {
gzip_static on;
add_header Cache-Control public;
expires 4w;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";
gzip_comp_level 6;
gzip_types application/x-javascript text/css text/html image/x-icon image/png image/jpeg image/gif;
}
location / {
try_files $uri #ruby;
}
location #ruby {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://reverse-proxy;
}
}
}
No, you do not. They are not the same kind of compression. When you run rake assets:precompile, all you're really doing is joining a bunch of files into one file and dumping it to the disk. Actually, according to the official documentation, it is two files:
When files are precompiled, Sprockets also creates a gzipped (.gz)
version of your assets. Web servers are typically configured to use a
moderate compression ratio as a compromise, but since precompilation
happens once, Sprockets uses the maximum compression ratio, thus
reducing the size of the data transfer to the minimum. On the other
hand, web servers can be configured to serve compressed content
directly from disk, rather than deflating non-compressed files
themselves.
This is important for you, because it allows you to use gzip, if you want, but it does not force you to do so. Gzip compression, which is real compression (not just concatenating files) reduces the amount of data you have to transfer, but at the expense of processor power (compressing and decompressing). It is likely to fairly dramatically improve your site, depending on page sizes and your (and your user's) hardware.
Here is a complete configuration(I am using it for my site):
GENERAL CONFIGURATION
http {
passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-4.0.5;
passenger_ruby /usr/local/bin/ruby;
include mime.types;
default_type application/octet-stream;
server_tokens off;
sendfile on;
keepalive_timeout 70;
gzip on;
gzip_http_version 1.1;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 1100;
gzip_buffers 64 8k;
gzip_comp_level 3;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml;
add_header Strict-Transport-Security "max-age=16070400; includeSubdomains";
add_header X-Frame-Options DENY;
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
include /opt/nginx/conf/nginx_host.conf;
}
Content of /opt/nginx/conf/nginx_host.conf;
HOST CONFIGURATION
server {
listen 80;
server_name *.domain.com;
root APP_PATH/current/public;
passenger_enabled on;
access_log off;
error_log /dev/null;
# Cross domain webfont access
location ~* \.(?:ttf|ttc|otf|eot|woff|font.css)$ {
add_header "Access-Control-Allow-Origin" "*";
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~* \.(ico|css|gif|jpe?g|png)(\?[0-9]+)?$ {
expires max;
}
location ~ ^/(assets|uploaded_assets|system)/ {
root /home/travelobd/rails_apps/travelobd/current/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
}
For serving assets:
server {
listen 80;
server_name static.domain.com;
root APP_PATH/current/public;
location / {
if ($request_filename ~ "\.(jpg|css|gif|png|swf|ico|js)$") {
break;
}
return 404;
}
}
Yes, you should if you want to improve performance.
Simply add the following block to your site configuration:
location ~ ^/(assets)/ {
root /path/to/public; # CHANGE THIS
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
Change the root path in the configuration. That is all there is to it.
RecommendationFromDocumentation™: http://guides.rubyonrails.org/asset_pipeline.html
What worked for me was configuring Nginx:
location ~ ^/(assets)/ {
gzip_static on;
}
Then in application.rb:
config.middleware.insert_before(Rack::Sendfile, Rack::Deflater)
# Compress JavaScripts and CSS.
config.assets.compress = true
config.assets.js_compressor = Uglifier.new(mangle: false)

Resources