# Trying to configure an origin pull CDN-like reverse proxy

**URL:** <https://www.ruby-forum.com/t/trying-to-configure-an-origin-pull-cdn-like-reverse-proxy/224208>\
**Category:** NGINX\
**Created:** [November 3, 2012, 5:17am UTC](https://www.ruby-forum.com/t/trying-to-configure-an-origin-pull-cdn-like-reverse-proxy/224208 "2012-11-03T05:17:10Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![aris](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/258eb7/32.png) [@aris](https://www.ruby-forum.com/u/aris)\
**Post date:** [November 3, 2012, 5:17am UTC](https://www.ruby-forum.com/t/trying-to-configure-an-origin-pull-cdn-like-reverse-proxy/224208/1 "2012-11-03T05:17:10Z")

</div>

Hello, I’m hosting a group of Wordpress blogs with about 200k visits and  
millions of hits per day. MySql + PHP live in a server (beefy VPS) and I  
placed a reverse proxy in front of it to cache most of the requests.

Now I want to offload all the static files to a third server, taking  
advantage of a feature of common Wordpress cache plugins, that rewrites  
static file URLs for origin-pull CDN services. This way, an original URL  
[Sooma](http://blog.com/wp-content/uploads/photo.jpg) is rewritten as  
[http://cdn.url.com/wp-content/uploads/photo.jpg](http://cdn.url.com/wp-content/uploads/photo.jpg) and this server requests  
the  
file form the original server, caches it and then serves it directly,  
for  
the duration of the 1st server’s Expires header/directive.

I thought it would be easy to use the proxy\_\* features, but I’m hitting  
a  
wall and I can’t find an applicable tutorial/article anywhere. Would  
somebody have any advice on how to do this? This is the basic behavior  
I’m  
after:

- Client requests static file [cdn.blog.com/dir/photo.jpg](http://cdn.blog.com/dir/photo.jpg)
- [cdn.blog.com](http://cdn.blog.com) looks for the file in its cache
- If the cache has it, check original or revalidate according with  
original  
headers (this is internal, I know).
- If the cache doesn’t have it, request it from  
[www.blog.com/dir/photo.jpg](http://www.blog.com/dir/photo.jpg),  
cache it and serve it.
- Preferably, allow for this to be done for many sites/domains, acting  
as a  
CDN server for many sites.

This is my conf:  
The cache zones in otherwise default nginx.conf and before including  
conf.d/\*.conf (I’m on CentOS 6.3 with nginx 1.0.15 from EPEL)

proxy\_cache\_path /var/www/cache/images levels=1:2  
keys\_zone=images:200m  
max\_size=10g inactive=3d;

proxy\_cache\_path /var/www/cache/scripts levels=1:2  
keys\_zone=scripts:50m  
max\_size=10g inactive=3d;

proxy\_cache\_path /var/www/cache/pages levels=1:2  
keys\_zone=pages:200m  
max\_size=10g inactive=3d;

And this is the individual server config on conf.d/server1.conf

upstream backend\_cdn.blog.com {  
ip\_hash;  
server 333.333.333.333;  
}

server {  
listen 80;  
server\_name [cdn.blog.com](http://cdn.blog.com);  
access\_log off;

# Set proxy headers for the passthrough

proxy\_set\_header Host $host;  
proxy\_set\_header X-Real-IP $remote\_addr;  
proxy\_set\_header X-Forwarded-For $proxy\_add\_x\_forwarded\_for;

# Let the Set-Cookie and Cache-Control headers through.

proxy\_pass\_header Set-Cookie;  
proxy\_pass\_header Cache-Control;  
proxy\_pass\_header Expires;

# Fallback to stale cache on certain errors.

# 503 is deliberately missing, if we’re down for maintenance

# we want the page to display.

proxy\_cache\_use\_stale error  
timeout  
invalid\_header  
updating  
http\_500  
http\_502  
http\_504  
http\_404;

# Set the proxy cache key

set $cache\_key $scheme$host$uri$is\_args$args;

location / {  
proxy\_pass http://backend\_$host;  
proxy\_cache pages;  
proxy\_cache\_key $cache\_key;  
proxy\_cache\_valid 15m; # 200, 301 and 302 will be cached.

# 2 rules to dedicate the no caching rule for logged in users.

# proxy\_cache\_bypass $wordpress\_auth; # Do not cache the response.

# proxy\_no\_cache $wordpress\_auth; # Do not serve response from cache.

add\_header X-Cache $upstream\_cache\_status;  
}

location ~\* .(png|jpg|jpeg|gif|ico|swf|flv|mov|mpg|mp3)$ {  
expires max;  
log\_not\_found off;  
proxy\_pass http://backend\_$host;  
proxy\_cache images;  
proxy\_cache\_key $cache\_key;  
}

location ~\* .(css|js|html|htm)$ {  
expires 7d;  
log\_not\_found off;  
proxy\_pass http://backend\_$host;  
proxy\_cache scripts;  
proxy\_cache\_key $cache\_key;  
}  
}

With this configuration, whenever I call a static file such as  
[http://cdn.blog.com/wp-includes/js/prototype.js](http://cdn.blog.com/wp-includes/js/prototype.js) I end up being  
redirected to  
[Sooma](http://www.blog.com/wp-includes/js/prototype.js). I’ve tried many things,  
like setting the Host header to various values or adding $uri to the end  
of  
the proxy\_pass directives, to no avail. One thing to notice is that the  
333.333.333.333 server only responds to [www.blog.com](http://www.blog.com), not [cdn.blog.com](http://cdn.blog.com).

Do I need a root directive in server1.conf?

I’m running in circles, any help will be much appreciated.

Thanks in advance,  
Cachito Espinoza

Posted at Nginx Forum:

> **[Trying to configure an origin pull CDN-like reverse proxy](https://forum.nginx.org/read.php?2,232468,232468#msg-232468)**
>
> Hello, I'm hosting a group of Wordpress blogs with about 200k visits and millions of hits per day. MySql + PHP live in a server (beefy VPS) and I placed a reverse proxy in front of it to cache most of the requests. Now I want to offload all the...

---

<div class="post-metadata">

**Author:** ![cachito](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/ce7236/32.png) [@cachito](https://www.ruby-forum.com/u/cachito)\
**Post date:** [November 3, 2012, 10:44am UTC](https://www.ruby-forum.com/t/trying-to-configure-an-origin-pull-cdn-like-reverse-proxy/224208/2 "2012-11-03T10:44:50Z")

</div>

On Sat, Nov 03, 2012 at 12:16:46AM -0400, cachito wrote:

Hi there,

All untested by me, but…

> - Preferably, allow for this to be done for many sites/domains, acting as a  
> CDN server for many sites.

So far, it looks like a straightforward caching reverse proxy setup. I’m  
not quite sure what the last point means – but one server{} block per  
site should work.

> proxy\_set\_header Host $host;  
> $host here is probably “[cdn.blog.com](http://cdn.blog.com)”.

What happens if you change this to “proxy\_set\_header Host [www.blog.com](http://www.blog.com);”  
?

> location ~\* .(css|js|html|htm)$ {  
> expires 7d;  
> log\_not\_found off;  
> proxy\_pass http://backend\_$host;  
> proxy\_cache scripts;  
> proxy\_cache\_key $cache\_key;  
> }

> With this configuration, whenever I call a static file such as  
> [http://cdn.blog.com/wp-includes/js/prototype.js](http://cdn.blog.com/wp-includes/js/prototype.js) I end up being redirected to  
> [http://www.blog.com/wp-includes/js/prototype.js](http://www.blog.com/wp-includes/js/prototype.js). I’ve tried many things,  
> like setting the Host header to various values or adding $uri to the end of  
> the proxy\_pass directives, to no avail. One thing to notice is that the  
> 333.333.333.333 server only responds to [www.blog.com](http://www.blog.com), not [cdn.blog.com](http://cdn.blog.com).

What is the output of

curl -i -0 -H ‘Host: [cdn.blog.com](http://cdn.blog.com)’  
[http://333.333.333.333/wp-includes/js/prototype.js](http://333.333.333.333/wp-includes/js/prototype.js)

? That is approximately what nginx will do. (You can add the extra  
proxy\_set\_header headers there, if you think it will make a difference.)

My guess is that the 333.333.333.333 server returns the http redirect,  
and nginx is correct in passing that on to the client.

The nginx log files should show more details.

> Do I need a root directive in server1.conf?

If you read from the filesystem, or otherwise access $document\_root,  
then the root directive is used.

I don’t see that needed for this request.

Good luck with it,

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
