Reputation: 1116
My setup is the following: Nginx(443 https) -> Varnish(port 6081) -> Nginx(port 83 - the app itself)
#nginx https conf:
location / {
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1800;
proxy_request_buffering off;
proxy_buffering off;
proxy_pass http://127.0.0.1:6081;
}
#part of default.vlc conf:
backend default {
.host = "127.0.0.1";
.port = "83";
}
Of course, there's another nginx config for port 83, which is the application itself. I've configured it this way, so I can run varnish behind HTTPS.
Trying to setup purge to invalidate cache for specific endpoints, I've configured the following in the default.vcl:
acl purge {
"127.0.0.1";
"some_public_ip"
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "This IP is not allowed to send PURGE requests."));
}
return (purge);
}
}
Everything ok, I can execute:
curl -X PURGE -I "https://web_server/index.php".
The issue is that, if I remove "127.0.0.1" from the acl list, and only let "some_public_ip", it won't work anymore. It will return "This IP is not allowed to send PURGE requests". I only want the purge to work for that "some_public_ip" only. Is it possible?
Upvotes: 0
Views: 789
Reputation: 4818
Because Nginx sits in front of Varnish the client.ip
variable always refers to it through localhost
. The actual client IP address is stored in the X-Forwarded-For
header.
You can extract it by calling std.ip(req.http.X-Forwarded-For,client.ip)
. This will convert the value of X-Forwarded-For
from a string to an IP address and will still use client.ip
as a fallback in case of errors.
Because Nginx already sets the X-Forwarded-For
header, Varnish will add the IP address of its client to it.
My varnishlog
output shows the following log lines:
- ReqUnset X-Forwarded-For: 178.118.13.77
- ReqHeader X-Forwarded-For: 178.118.13.77, 127.0.0.1
We have to remove the second part in order to get the right IP address. We can do this using the following VCL snippet:
set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For,"^([^,]+),.*$","\1");
In the end, this is the VCL code we need to make this work:
vcl 4.0;
import std;
acl purge {
"127.0.0.1";
"some_public_ip"
}
sub vcl_recv {
if(req.http.X-Forwarded-For ~ ","){
set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For,"^([^,]+),.*$","\1");
}
if (req.method == "PURGE") {
if (!std.ip(req.http.X-Forwarded-For,client.ip) ~ purge) {
return (synth(405, "This IP is not allowed to send PURGE requests."));
}
return (purge);
}
}
Upvotes: 1