ingress nginx: rewrite rule logic and location lookup - kubernetes-ingress

I deployed in my k8s cluster a nginx ingress controller to reach a backend application.
When testing my ingress resource configuration, I noticed that if I add a rewrite rule, I also need to declare a path for the rewritten URI pointing to the same service.
For example, the following ingress config doesn't work:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: fieldprov-app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /wetty
nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
kubernetes.io/ingress.class: "field-management"
spec:
tls:
- hosts:
- ccfanhe09.sce-lab.com
rules:
- host: ccfanhe09.sce-lab.com
http:
paths:
- path: /provisioning
backend:
serviceName: fieldprov-app
servicePort: 3000
The controller will redirect me to its default backend server associated to "/"
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /provisioning HTTP/2.0" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0" 236 0.003 [default-fieldprov-app-3000] [] [fd10::1:10a]:
3000 0 0.003 304 64895f25fd3fb9937f66ebbcee369c81
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /wetty/socket.io/socket.io.js HTTP/2.0" 404 159 "https://ccfanhe10.sce-lab.com:30000/provisioning" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firef
ox/60.0" 71 0.002 [upstream-default-backend] [] 127.0.0.1:8181 159 0.003 404 8310972dd6b39f294bae7550305bd7c2
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /wetty/wetty.min.js HTTP/2.0" 404 159 "https://ccfanhe10.sce-lab.com:30000/provisioning" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0" 2
4 0.001 [upstream-default-backend] [] 127.0.0.1:8181 159 0.002 404 47875d655cf4bcd02fc6212dc6142848
fd10::2:102 - [fd10::2:102] - - [01/Oct/2019:19:34:07 +0000] "GET /wetty/wetty.min.js HTTP/2.0" 404 159 "https://ccfanhe10.sce-lab.com:30000/provisioning" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0" 2
4 0.001 [upstream-default-backend] [] 127.0.0.1:8181 159 0.000 404 08d1fd4cc72a5475d0fcfb4ca6a4cb2b``
So to me it's like the controller is doing a 2nd lookup after having applied the rewrite rule.
Below is my nginx.conf associated to the ingress config described above:
## start server ccfanhe10.sce-lab.com
server {
server_name ccfanhe10.sce-lab.com ;
listen 80 ;
listen [::]:80 ;
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;
set $proxy_upstream_name "-";
# PEM sha: 692b563bafa154b7d28350ef01e7c4d53ec2afd1
ssl_certificate /etc/ingress-controller/ssl/default-fake-certificate.pem;
ssl_certificate_key /etc/ingress-controller/ssl/default-fake-certificate.pem;
ssl_certificate_by_lua_block {
certificate.call()
}
location ~* "^/provisioning" {
set $namespace "default";
set $ingress_name "fieldprov-app";
set $service_name "fieldprov-app";
set $service_port "{0 3000 }";
set $location_path "/provisioning";
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = true,
use_port_in_redirects = false,
})
balancer.rewrite()
plugins.run()
}
header_filter_by_lua_block {
plugins.run()
}
body_filter_by_lua_block {
}
log_by_lua_block {
balancer.log()
monitor.call()
plugins.run()
}
if ($scheme = https) {
more_set_headers "Strict-Transport-Security: max-age=15724800; includeSubDomains";
}
rewrite_log on;
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "default-fieldprov-app-3000";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $the_real_ip;
proxy_set_header X-Forwarded-For $the_real_ip;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
rewrite "(?i)/provisioning" /wetty break;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
location ~* "^/" {
set $namespace "";
set $ingress_name "";
set $service_name "";
set $service_port "{0 0 }";
set $location_path "/";
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = true,
use_port_in_redirects = false,
})
balancer.rewrite()
plugins.run()
}
header_filter_by_lua_block {
plugins.run()
}
body_filter_by_lua_block {
}
log_by_lua_block {
balancer.log()
monitor.call()
plugins.run()
}
if ($scheme = https) {
more_set_headers "Strict-Transport-Security: max-age=15724800; includeSubDomains";
}
rewrite_log on;
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "upstream-default-backend";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $the_real_ip;
proxy_set_header X-Forwarded-For $the_real_ip;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
rewrite "(?i)/" /wetty break;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
}
## end server ccfanhe10.sce-lab.com
I don't understand the rewrite rule under "^ /" location.
Also I thought that adding the break keyword to the rewrite rule would avoid any extra URI lookup but this is not the behavior I'm seeing. If I don't create a location for "/wetty" which points to the same service as "/provisioning", it doesn't work.
I'm looking for some explanation about the expected behavior in such condition.
Thanks for your support !!

Try to use capture groups as described in here or here section of ingres-nginx documentation.
Starting in Version 0.22.0, ingress definitions using the annotation nginx.ingress.kubernetes.io/rewrite-target are not backwards compatible with previous versions. In Version 0.22.0 and beyond, any substrings within the request URI that need to be passed to the rewritten path must explicitly be defined in a capture group.
Captured groups are saved in numbered placeholders, chronologically, in the form $1, $2 ... $n. These placeholders can be used as parameters in the rewrite-target annotation.
So Your ingress config should looks something like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: fieldprov-app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /wetty/$2
nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
kubernetes.io/ingress.class: "field-management"
spec:
tls:
- hosts:
- ccfanhe09.sce-lab.com
rules:
- host: ccfanhe09.sce-lab.com
http:
paths:
- path: /provisioning/(/|$)(.*)
backend:
serviceName: fieldprov-app
servicePort: 3000
As for the nginx.conf it looks like that because its settings are injected from nginx-controller using lua-nginx-module, You can read about it here.
Update:
If the rewrite rule is working correctly there shouldn't be any extra lookups. I was not able to find anything like that in nginx ingress annotations.
You can check if rewrite rule is working by using curl -I -k <URI> command:
$ curl -I -k http://approot.bar.com/
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.11.10
Date: Mon, 13 Mar 2017 14:57:15 GMT
Content-Type: text/html
Content-Length: 162
Location: http://stickyingress.example.com/app1
Connection: keep-alive

Related

Tons of timeouts from Node.JS Express API hosted on Nginx behind Cloudflare

I have a Node.JS Express API (MySQL) hosted on Nginx behind Cloudflare (2 instances running). I'm getting a lot of 504 timeout on Roblox and upstream timed out on Nginx. I have never seen a request I sent with Postman fail. I think it happens more under load. These instances are processing processing 11M requests a week. This is hosted on a 16 core, 64 GB RAM, dedicated server with 2-3 load average
Nginx error log spams these:
upstream timed out (110: Connection timed out) while reading response header from upstream
no live upstreams while connecting to upstream
upstream prematurely closed connection while reading response header from upstream
The upstream timed out errors are the concern as they are the majority of the errors.
Generally, I don't do too much processing on the API. I have less then a dozen endpoints that are mostly simple DB selects.
Can someone direct me in the right area to resolve this? Is it my Nginx config, do I need more instances, is it my design, is it Roblox, is it Cloudflare? I read Node.js can handle this (under one instance), so I tried to adjust worker connections in Nginx which caused more no live upstream errors. I cannot wrap my head around what the bottle neck is.
Site Config
proxy_cache_path /tmp/NGINX_cache/ keys_zone=backcache:10m;
map $http_upgrade $connection_upgrade {
default upgrade;
' ' close;
}
upstream nodejs {
# Use IP Hash for session persistence
ip_hash;
keepalive 90;
# List of Node.js application servers
server localhost:9000;
server localhost:9001;
}
# HTTP: www and non-www to https
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# HTTPS: non-www to www
server {
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /example/example.com.cert.pem;
ssl_certificate_key /example/example.com.key.pem;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
# HTTPS: www
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /example/example.com.cert.pem;
ssl_certificate_key /example/example.com.key.pem;
server_name www.example.com;
location / {
return 301 $scheme://www.example.example$request_uri;
}
location /api {
proxy_pass https://nodejs;
proxy_cache backcache;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 90;
proxy_redirect https://nodejs https://www.example.com;
}
location /api_staging {
proxy_pass https://localhost:8000;
proxy_cache backcache;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 90;
proxy_redirect https://localhost:8000 https://www.example.com;
}
location /api_development {
proxy_pass https://localhost:7000;
proxy_cache backcache;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 90;
proxy_redirect https://localhost:7000 https://www.example.com;
}
}
Nginx Config
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1000;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
client_max_body_size 100M;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
Cloudflare Edits
Proxied is on
Full strict SSL
All Roblox IPs are allowed through firewall

Nginx reverse proxy works fine with Safari and Firefox but doesn't work with Chrome

I use Nginx as reverse proxy to forward my Https request to backend server (which runs in Http protocol with port 7654 in the same server). Everything works well in Safari and Firefox, but Chrome throws an error.
Chrome Error: net::ERR_CERT_AUTHORITY_INVALID
Below is my nginx.conf file. BTW, it also works fine when I use IP address instead of domain name in Chrome. How can I fix this problem?
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name mydomain.name.lan;
root /usr/share/nginx/html;
ssl_certificate "/etc/pki/tls/certs/crt.crt";
ssl_certificate_key "/etc/pki/tls/private/key.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
try_files $uri $uri/ /index.html;
}
location /app/v1/ {
proxy_pass http://localhost:7654;
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 https;
}
}
i can give you an example of working config, which works for all browsers (currently latest releases) which we use at company. TLDR story behind, we have docker swarm deployment, but we have entry point Nginx which runs on host, and has another Nginx inside container which then redirects trafic to specific API gateways and so on..
We are gonna focus on that first level Nginx (which is on host), which actually does all SSL checks and so on .. we use http inside docker (between pods & containers)..
Working example for linux:
server_tokens off;
server {
listen 443 http2 ssl;
server_name development.docker.company.si;
add_header Strict-Transport-Security "max-age=31536000" always;
proxy_buffering off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
set $upstream_local_docker_proxy 10.10.0.2; #static location of inner nginx
ssl_certificate /etc/tls/si.company.docker.development-chain.crt;
ssl_certificate_key /etc/tls/si.company.docker.development-unencrypted.key;
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;
ssl_protocols TLSv1.2 TLSv1.3;
#here we just have /url-location-level-routing/ , in case you want to know
location /my-application-demo/ {
proxy_pass http://$upstream_local_docker_proxy;
proxy_set_header Host local.docker.company-my-application-demo;
rewrite ^/my-application-demo/(.*) /$1 break;
}
}
For a specific case you have, i have a windows config, all u need to do is change windows path of certs to linux and it should work:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
upstream local-company1-api {
server localhost:5000;
}
server {
listen 443 http2 ssl;
server_name company1.company.si;
add_header Strict-Transport-Security "max-age=31536000" always;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
ssl_certificate C:\\tls\\si.company.company1-chain.pem;
ssl_certificate_key C:\\tls\\si.company.company1-unencrypted.pem;
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;
ssl_protocols TLSv1.2 TLSv1.3;
# ----------------------------------------------------------------------------------------------------
location / {
proxy_pass http://local-company1-api/;
proxy_redirect off;
}
}
}
I hope any of this helps.

File requests with Query Strings failing in ASP.NET Core behind NGINX

I have an ASP.NET Core site running behind an NGINX reverse-proxy on Linux. I'm running into an issue where if I do a file request through the proxy with a query string attached (i.e. for cache-busting), I'm getting 404 errors, but if I request the exact same URL directly from the application (not through NGINX), it works fine, and if I drop the query string, it also works fine.
Examples below (the NGINX proxy is listening on port 5000 and the application is listening on port 5002)...
If I use a url like:
http://host-name:5000/path/file.json
I get the result back correctly, and this is what appears on the application's console output:
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://host-name:5000/path/file.json
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5000/path/file.json
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 400.9508ms 200 application/json
If I use a url like:
http://host-name:5002/path/file.json
I get the result back correctly, and this is what appears on the application's console output:
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://host-name:5002/path/file.json
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5002/path/file.json
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 28.2031ms 200 application/json
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 28.2031ms 200 application/json
If I use a url like:
http://host-name:5002/path/file.json?_dc=1020
I get the result back correctly, and this is what appears on the application's console output:
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://host-name:5002/path/bootstrap.json?_dc=1020
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5002/path/bootstrap.json?_dc=1020
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware:Information: Sending file. Request path: '/path/file.json'. Physical path: '/home/coreuser/debug/wwwroot/path/file.json'
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 146.8157ms 200 application/json
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 146.8157ms 200 application/json
If I use a url like:
http://host-name:5000/path/file.json?_dc=1020
I get a 404 error, and this is what appears on the application's console output:
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://host-name:5000/path/file.json?_dc=1020
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://host-name:5000/path/file.json?_dc=1020
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 379.4175ms 404
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 379.4175ms 404
Now, I'm not clear on whether this is an issue with NGINX messing with what it is forwarding to the ASP.NET Core application, or it isn't just an issue with the ASP.NET Core application (and/or Kestrel) getting thrown off by the combination of query string and the proxy's port number showing up on the request.
The relevant part of the NGINX configuration looks like this:
server {
server_name host-name;
listen 5000 default_server;
listen [::]:5000 default_server;
location / {
proxy_pass http://localhost:5002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Path $request_uri;
}
}
Any ideas?
EDIT:
I've since modified my server block to look like this:
server {
server_name host-name;
listen 5000 default_server;
listen [::]:5000 default_server;
root /var/www/path-to-debug/wwwroot;
location / {
if ($query_string ~ "^(.*)_dc=(.*)$") {
rewrite ^(.*)$ $uri?;
}
try_files $uri #proxy;
}
location #proxy {
proxy_pass http://localhost:5002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Path $request_uri;
}
}
Now that specific file is being fetched properly (bypassing Kestrel completely), but that seems to be messing with one of my controller calls that also has the _dc=XXXX attached.
I've gotten this part to work by modifying my server proxy block as below...it feels like a hack to me, but I haven't found a better solution yet. I also still have other issues, but will post separate questions for those if/when I can't figure them out.
server {
server_name host-name;
listen 5000 default_server;
listen [::]:5000 default_server;
root /var/www/path-to-debug/wwwroot;
location / {
if ($query_string ~ "^(.*)_dc=(.*)$") {
rewrite ^(.*)$ $uri?;
}
try_files $uri #proxy;
}
location #proxy {
proxy_pass http://localhost:5002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Path $uri;
}
}

how to set upgrade-insecur-requests based on nginx

I have changed my site to https,but I used the cdn of static files in the code. it can't work and the chrome console show the errors like this:
Mixed Content: The page at 'https://a.example.com/static/' was loaded over HTTPS, but requested an insecure stylesheet 'http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css'. This request has been blocked; the content must be served over HTTPS.
I have add the add_header Content-Security-Policy upgrade-insecure-requests; in the nginx configuration file like this:
server {
listen 80;
listen 443;
server_name a.example.com;
add_header Content-Security-Policy upgrade-insecure-requests;
if ($scheme != "https") {
return 301 https://$server_name$request_uri;
#rewrite ^ https://$server_name$request_uri? permanent;
}
ssl on;
ssl_certificate /etc/nginx/ssl/example.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
gzip on;
gzip_proxied any;
gzip_types text/plain application/xml application/json;
client_max_body_size 8M;
access_log /var/log/nginx/example.log;
location / {
proxy_pass http://10.10.10.110:5000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
location ^~ /static/ {
proxy_pass http://10.10.10.110:8888;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
#proxy_set_header Content-Security-Policy upgrade-insecure-requests;
}
}
but it does't work yet! Can someone tell me how to fix this? thx :)
Be aware that upgrade-insecure-requests is not supported in all browsers, e.g. Safari and IE.
I recommend that you just replace the HTTP requests in your code. You can use // to load it relative to the protocol it is called from as per:
//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css
That means that if you are opening the web application from an HTTPS context, it will load it using the HTTPS protocol, otherwise it will use HTTP.

Leverage browser caching for Nginx, no css when reloading the page

I amtrying to follow the google pagespeed advice and Leverage browser caching. For that I place the following code into the server block of my nginx.conf file.
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
location ~* \.(pdf)$ {
expires 30d;
}
It seems to work nicely, page speed increases my score to from 87/100 to 95/100. However, when I click the refresh button for my site it doesn't seem to load the css files anymore?
Did the caching not work?
The error message I get is
Failed to load resource: the server responded with a status of 404 (Not Found)
Here is my entire nginx.conf file
worker_processes 1;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
sendfile on;
gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 500;
gzip_disable "MSIE [1-6]\.";
gzip_types text/plain text/xml text/css
text/comma-separated-values
text/javascript
application/x-javascript
application/atom+xml;
# Configuration containing list of application servers
upstream app_servers {
server 127.0.0.1:8080;
}
# Configuration for Nginx
server {
# Running port
listen 80;
# Settings to serve static files
location /static/ {
# Example:
# root /full/path/to/application/static/file/dir;
root /var/www/benty-fields/app/;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
location ~* \.(pdf)$ {
expires 30d;
}
# Serve a static file (ex. favico)
# outside /static directory
location = /favico.ico {
root /app/favico.ico;
}
# Proxy connections to the application servers
# app_servers
location / {
proxy_pass http://app_servers;
proxy_redirect off;
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-Host $server_name;
}
}
}
Take a look at Fiddler traces or Chrome dev tools.
A 304 would mean that the server responded with "not modified, use your local cache". If you clear your browser cache or do Shift + Refresh, you will get a 200 along with the body of the file. 304 on the contrary have zero body length.
I was getting the same issue.
Resolved it by placing:
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
location ~* \.(pdf)$ {
expires 30d;
}
inside
location /static/
So the final config looks like
location / {
proxy_pass http://app_servers;
proxy_redirect off;
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-Host $server_name;
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
location ~* \.(pdf)$ {
expires 30d;
}
}
Reference: https://developers.google.com/speed/pagespeed/module/filter-cache-extend