nginx reverse proxy: How to implement? - configuration

I'm trying to do a reverse proxy with Nginx based on the URL. I want http://mydomain.example.com/client1/... to be redirected to http://127.0.0.1:8193/.... I have tried many ways, and none of them worked. Please note that the application can make redirections. These are the configuration files of my last solution :
default
server {
listen 80;
server_name mydomain.example.com;
location / {
set $instance none;
if ($request_uri ~ ^/(.*)/$) {
set $instance $1;
}
set $no_cookie true;
if ($http_cookie ~ "instance=([^;] +)(?:;|$)") {
set $instance $1;
set $no_cookie false;
}
if ($no_cookie = true) {
add_header Set-Cookie "instance=$instance;Domain=$host;Path=/";
rewrite ^ / break;
}
include instances.conf;
}
instances.conf
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_connect_timeout 90;
proxy_send_timeout 60;
# Installation of language packs, etc. can take a long time
proxy_read_timeout 10800;
if ($instance = client1) {
proxy_pass http://127.0.0.1:8193;
}
if ($instance = client2) {
proxy_pass http://127.0.0.1:8194
}
...
When the browser requests http://mydomain.example.com/client1/, Nginx should set a cookie named instance with the value client1 then redirect the traffic to the appropriate proxy. For subsequent queries, it should use this cookie to make redirection. The problem I have is it never sets the $instance variable to client1. Don't forget that the application has no idea of the prefix /client1.
Do you have an idea? Do you know of a better solution?

The regex used to get the cookie was wrong. I have changed this to
"instance=([^;][^ ]+)(?:;|$)"
and it works now.
Edit: It's only a part of the solution finally. I'm sorry. There is still a problem. See my comment below.

It is not related to your problem but "proxy_connect_timeout"
"This directive assigns a timeout for the connection to the upstream server. It is necessary to keep in mind that this time out cannot be more than 75 seconds."

See Nginx' map module
map $uri $proxy {
/client1 http://127.0.0.1:8193/client1;
/client2 http://127.0.0.1:8194/client2;
}
server {
server_name my.domain.com;
proxy_pass $proxy;
}
Note that appending /clientX to the end of the proxy_pass URI strips that portion of the URI from the request (which seems rational to me, but may not be what you want).

Related

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

Why I can't put proxy_set_header inside an if clause?

With this configuration:
server {
listen 8080;
location / {
if ($http_cookie ~* "mycookie") {
proxy_set_header X-Request $request;
proxy_pass http://localhost:8081;
}
}
}
I have this error when I reload nginx service:
Reloading nginx configuration: nginx: [emerg] "proxy_set_header" directive is not allowed here in /etc/nginx/conf.d/check_cookie.conf:5
nginx: configuration file /etc/nginx/nginx.conf test failed
This configuration works OK, but it does not do what I want:
server {
listen 8080;
location / {
proxy_set_header X-Request $request;
if ($http_cookie ~* "mycookie") {
proxy_pass http://localhost:8081;
}
}
}
Why I can't put proxy_set_header directive inside an if clause?
Inside location try something like this
# default header value in a new variable
set $esb "$remote_addr, $host";
# if my custom header exists
if ($http_my_header){
set $esb "$http_my_header, $remote_addr, $host";
}
proxy_set_header my-header $esb;
Unlike proxy_pass, you cannot put proxy_set_header inside an if block. You can only put it in http/server/location block. So your 2nd config is good.
Reference: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
context: http, server, location
Don't know what the $request variable is. It doesn't appear in nginx variable list: http://wiki.nginx.org/HttpCoreModule#Variables. What are you trying to achieve here?

Configuring nginx for single page website with HTML5 push state URL's

How can I configure nginx to redirect all URL's (not prepended with /api or some static resource eg. JS/images) to index.html? Reason is I am using HTML5 push state URL's with a single page application. Meaning content is changed whether AJAX or JS depending on the URL
My current nginx config looks like:
server {
listen 2000;
server_name localhost;
location / {
root /labs/Projects/Nodebook/public;
index index.html;
}
location /api/ {
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_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
proxy_redirect off;
}
}
location / {
try_files $uri /index.html;
}
This will check if the requested file exists and return it. If the file doesn't exist, it will return index.html.
http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files
mattes answer is almost a solution, however it won't give 404 for missing files (e.g. favicon.icon) as aschepis pointed out.
Nginx will pick the first location that matches. So we can first match for files (which will give 404 if the file does not exist). And after put a location which defaults to index.html for all urls.
location /.+\..+ { # files (assuming they always have a dot)
# use eg alias to serve some files here
}
location / { # url routed by client, client gives 404 for bad urls
try_files $uri /index.html;
}
You need to add to your nginx config file:
rewrite ^(.+)$ /index.html last;
Then say you're using Backbone.js just make sure you re-route any non-defined route to a 404 page:
routes: {
// Other routes
"*path" : "notFound"
},
notFound: function(path) {
// Load 404 template, probably of a cute animal.
}
Source:
http://readystate4.com/2012/05/17/nginx-and-apache-rewrite-to-support-html5-pushstate/

Multiple authentication together with Nginx proxy

I am trying to authenticate several locations together with proxy_pass in Nginx. The Nginx config is following:
server {
listen 443;
server_name example.com;
location /hg/ {
rewrite ^/hg/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8001;
auth_basic "hg";
auth_basic_user_file hg.htpasswd;
location /hg/repo1/ {
auth_basic "hg-repo1";
auth_basic_user_file repo1.htpasswd;
}
location /hg/repo2/ {
auth_basic "hg-repo2";
auth_basic_user_file repo2.htpasswd;
}
}
}
The authentication works ok, but the proxy gets broken in nested locations (repo1, repo2). It seems that proxy_pass config is not inherited. So, Nginx returns 404 (on /hg/repo1 and /hg/repo2).
Any hints?
You need to repeat proxy_pass for each location block.
Also, there is no function to nesting the location blocks. Usually they are not nested.

Nginx to server node.js content + static content

I have an application with both dynamic and static content. I use nginx as a front end for this app. When dynamic content is requested, the request is forwarded to an unix socket (to a node.js app), this part works well. I have added a "location" directive to serve the static content but this part does not work, I get the 404 error each time despite the fact the folder "/home/test/my_app/static" does exist.
This is the nginx conf I have:
upstream test_sock {
server unix:/tmp/test.sock
fail_timeout=0;
}
server {
listen 15000;
client_max_body_size 4G;
server_name localhost domain.com;
keepalive_timeout 5;
location ~ /static/ {
if (!-f $request_filename) {
return 404;
}
if (-f $request_filename) {
root /home/test/my_app/static;
expires 30d;
}
}
location / {
proxy_pass http://test_sock;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
Any idea ?
hmmm... ok, silly thing, I was missing the root directive before the locations ones...