Nginx set proxy_set_header if header is present - ssl

I'm using AWS CloudFront to terminate my SSL before hitting my backend, and need to distinguish this traffic from non-CloudFront traffic to set a proxy_set_header in Nginx.
I believe the best way to do this would be to check for the X-Amz-Cf-Id header (added by CloudFront), and set the proxy_set_header when it's present. However, I'm aware it's not possible to set proxy_set_header in an Nginx if statement, which leads to my question.
How can I set a proxy_set_header value only when that header is present?

if statements aren't a good way of setting custom headers because they may cause statements outside the if block to be ignored.
You can use a map directive instead which is not prone to the same problems.
# outside server blocks
map $http_X_Amz_Cf_Id $is_cloudfront {
default "No";
~. "Yes"; # Regular expression to match any value
}
Then:
# inside location block
proxy_set_header X_Custom_Header $is_cloudfront;

A general answer is that you can set variables in if and then use the variable. Like this:
set $variable "";
if ($http_X_Amz_Cf_Id) {
set $variable "somevalue";
}
proxy_set_header someheader $variable;

Related

I want to delete the prefix "HTTP_" of nginx proxy_set_header

When using nginx's proxy_set_header, HTTP_ is added to the prefix of its own header. Please tell me how to prevent this.
proxy_set_header exmaple_key example_value;
As a result, the header name acquired is HTTP_EXAMPLE_KEY.
I want this to be EXAMPLE_KEY.

NGINX - Using variable in proxy_pass breaks routing

I'm trying to get NGINX's resolver to automatically update the DNS resolution cache, so I'm transitioning to using a variable as the proxy_pass value to achieve that. However, when I do use a variable, it makes all requests go to the root endpoint of the request and cuts off any additional paths of the url. Here's my config:
resolver 10.0.0.2 valid=10s;
server {
listen 80;
server_name localhost;
location /api/test-service/ {
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# If these 2 lines are uncommented, 'http://example.com/api/test-service/test' goes to 'http://example.com/api/test-service/'
set $pass_url http://test-microservice.example.com:80/;
proxy_pass $pass_url;
# If this line is uncommented, things work as expected. 'http://example.com/api/test-service/test' goes to 'http://example.com/api/test-service/test'
# proxy_pass http://test-microservice.example.com:80/;
}
This doesn't make any sense to me because the hardcoded URL and the value of the variable are identical. Is there something I'm missing?
EDIT: Ah, so I've found the issue. But I'm not entirely sure how to handle it. Since this is a reverse proxy, I need the proxy_pass to REMOVE the /api/test-service/ from the URI before it passes it to the proxy. So..
This:
http://example.com/api/test-service/test
Should proxy to this:
http://test-microservice.example.com:80/test
But instead proxies to this:
http://test-microservice.example.com:80/api/test-service/test
When I'm not using a variable, it drops it no problem. But the variable adds it. Is that just inherently what using the variable will do?
There is a small point you missed in documentation
When variables are used in proxy_pass:
location /name/ {
proxy_pass http://127.0.0.1$request_uri;
}
In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.
So you config needs to be changed to
set $pass_url http://test-microservice.example.com:80$request_uri;
proxy_pass $pass_url;

Configuration for Piwik behind nginx reverse proxy with rewrite

I'm using Piwik behind an Nginx reverse proxy and Piwik is running on an Apache Server. I also use a rewrite rule ( /piwik/ to / ).
For Chrome and Safari on Mac the login process for Piwik isn't working (I only got the general error message to configure browser cookies and proxy server).
But my current configuration is working in FirefoxDeveloperEdition for Mac:
nginx.conf:
location /piwik {
rewrite ^/piwik/(.*)$ /$1 break;
proxy_pass http://piwik;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host/piwik;
}
config.ini.php
[General]
proxy_client_headers[] = HTTP_X_FORWARDED_FOR
proxy_host_headers[] = HTTP_X_FORWARDED_HOST
When I remove the /piwik in nginx.conf to:
proxy_set_header X-Forwarded-Host $http_host;
The login is working but I got 2 other problems:
after login I got a wrong redirect to the root / (not Piwik anymore), but after reopening Piwik, I'm logged in
the logo is missing because of the wrong url http://localhost:2020/plugins/Morpheus/images/logo.svg instead of http://localhost:2020/piwik/plugins/Morpheus/images/logo.svg
I also would keep the rewrite rule, because the Apache Server is a universal docker container.
Probably I have to analyse the failing authentification condition, but I didn't find the correct line yet.
I have created a pull request to enable and consider a new header info for proxy environment.
nginx.conf (inform about missing path)
rewrite ^/piwik/(.*)$ /$1 break;
...
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri /piwik;
Enable header in config.ini.php
proxy_uri_header = 1
This option inserts the missing path to the current script name and redirects. See pull request for more details https://github.com/piwik/piwik/pull/12011

Getting real IP with MUP and SSL

We are using MUP for Meteor deployment to AWS. Couple of weeks ago we got excited that we can now switch to a free cert, thanks to Letsencrypt and Kadira. Everything was working very nicely, until I realized in the logs that client IP is no longer being passed through the proxy... No matter what I do, I see 127.0.0.1 as my client IP. I was trying to get it in methods using this.connection.clientIP or headers package.
Well, after doing much research and learning in-depth how stub and nginx work, I came to conclusion that this was never working.
The best solution I came up with is to use proxy_protocol as described by Chris, but I could not get it to work.
I have played with settings of /opt/stud/stud.conf and attempted to turn write-proxy and proxy-proxy settings on.
This is what my nginx config looks like:
server {
listen 80 proxy_protocol;
server_name www.example.com example.com;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto http;
}
}
Here is what my headers look like on production EC2 server:
accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
accept-encoding:"gzip, deflate, sdch"
accept-language:"en-US,en;q=0.8"
cache-control:"no-cache"
connection:"upgrade"
host:"127.0.0.1:3000"
pragma:"no-cache"
upgrade-insecure-requests:"1"
x-forwarded-for:"127.0.0.1"
x-forwarded-proto:"http"
x-ip-chain:"127.0.0.1,127.0.0.1"
x-real-ip:"127.0.0.1"
So, the questions of the day. Using MUP with SSL, is there a way to get a pass-though client IP address?
I know you said you have tried using headers, but you may give it another shot and see if you can get something this way. I was having alot of problems with x-forwarded-for counts not staying consistent, but if I pull from the header chain, [0] is always the client IP.
Put this code in your /server folder:
Meteor.methods({
getIP: function() {
var header = this.connection.httpHeaders;
var ipAddress = header['x-forwarded-for'].split(',')[0];
return ipAddress;
}
});
In your browser console:
Meteor.call('getIP', function(err, result){
if(!err){
console.log(result);
} else {
console.log(err);
}
};
See what you get from that response. If that works, you can just call the method on Template.rendered or whenever you need the IP.
Otherwise, I'm pretty sure you should be able to set the IP to an arbitrary header in your nginx conf and then access it directly in the req object.
By the way, in the nginx config you included, I think you need to use real_ip_header X-Forwarded-For; so that real_ip will use that header to locate the client IP, and you should also set real_ip_recursive on; so that it will ignore your trusted set_real_ip_from
Alright, so after a sleepless night and learning everything I could about the way STUD and HAProxy protocol works, I came to a simple conclusion it's simply not supported.
I knew I could easily go back to have SSL termination at Nginx, but I wanted to make sure that my deployment has automation as MUP.
Solution? MUPX. The next version of MUP, but still in development. It uses Docker and has SSL termination directly at Nginx.
So there you have it. Lesson? Stable is not always a solution. :)

Proxy pass to multiple upstreams

Is there a directive in apache or nginx (preferably) that allows to replicate an incoming stream to multiple upstreams simultaneously?
The reason I need this: I want to stream live video content from one client to a number of Flash RMTP servers that will make that content available to a number of clients.
This setup is working on one streaming server, but I want to add more.
Any help is greatly appreciated.
I am assuming you are using, something similar to this:
proxy_pass
location / {
proxy_pass http://192.168.1.11:8000;
proxy_set_header X-Real-IP $remote_addr;
}
--
Use this instead:
http:// wiki.nginx.org/NginxHttpUpstreamModule
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
}
server {
location / {
proxy_pass http://backend;
}
}