I have a Symfony 2.5.X app running on an nginx server. I will call it domain.com.
The /news URI within that server is configured as a reverse proxy to a remote machine, where I run WordPress blog on nginx server again. I will call it blog.domain.com.
domain.com‘s configuration looks like that:
server {
listen 80;
server_name domain.com;
set $project_path /home/webserver/prod.domain.com;
root $project_path/web;
error_log /home/webserver/prod.domain.com/app/logs/nginx_error.log;
access_log /home/webserver/prod.domain.com/app/logs/nginx_access.log;
charset utf-8;
client_max_body_size 65m;
# Some extra speed
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Reverse-proxy all /news calls to remote machine
location ~ /news?(.*) {
access_log off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_set_header Host blog.domain.com; # without it it doesn't work
#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 http;
proxy_set_header X-Custom-Secret 6ffe3dba7213c678324a101827aa3cf22c;
proxy_redirect off;
proxy_buffering off;
#proxy_intercept_errors on;
proxy_pass http://blog.domain.com:80;
break;
}
# Default URLs
location / {
try_files $uri /app.php$is_args$args;
}
# Error pages (static)
#error_page 403 /errorpages/403.html;
error_page 404 /errorpages/404.html;
#error_page 405 /errorpages/405.html;
error_page 500 501 502 503 504 /errorpages/5xx.html;
# Don't log garbage, add some browser caching
location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
try_files $uri /app.php?$query_string;
}
location ~* ^.+.(css|js)$ {
expires modified +1m;
add_header Pragma "private";
add_header Cache-Control "private";
etag on;
try_files $uri /app.php?$query_string;
}
location = /robots.txt {
allow all;
access_log off;
log_not_found off;
}
# Disallow .htaccess, .htpasswd and .git
location ~ /.(ht|git) {
deny all;
}
# Parse PHP
location ~ ^/(app|app_dev|config).php(/|$) {
include fastcgi_params;
fastcgi_split_path_info ^(.+.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass php;
}
}
blog.domain.com‘s configuration looks like that:
server {
listen 80;
server_name blog.domain.com;
root /home/webserver-blog/news;
access_log /home/webserver-blog/logs/http_access.log;
error_log /home/webserver-blog/logs/http_error.log;
charset utf-8;
client_max_body_size 65m;
# Some extra speed
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Default URLs
location / {
# This never gets parsed as / is reserved for our main server
}
location ~* ^/news/(wp-content|wp-admin) { # without this directive I didn't have any static files
root /home/webserver-topblog/;
}
location ~* ^/news {
try_files $uri $uri/ /index.php?args;
}
# Don't log garbage
location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
location = /robots.txt {
allow all;
access_log off;
log_not_found off;
}
# Disallow .htaccess or .htpasswd
location ~ /.ht {
deny all;
}
# Disallow logs
location ~ ^/logs/.*.(log|txt)$ {
deny all;
}
# Parse PHP
location ~ .php$ {
#if (!-e $request_filename) { rewrite / /index.php last; }
try_files $uri =404;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
}
}
As you can figure out, my WordPress resides in /home/webserver-blog/news/
. I have a slightly modified index.php file in WordPress that checks for X-Custom-Secret
header, and if it’s not present (or invalid), it forces a 301 redirection to domain.com/news/
Now I have tried several different approaches to get it running properly.
- First (and most obvious) was pointing the
root
of blog.domain.com‘s to/home/webserver-blog/
and allowing nginx to naturally pass the request URI to the subdirectory,/news
. This worked quite well, yet it didn’t allow me to utilize WordPress’ permalinks and just worked with query strings. Other strange behaviour it produced was actually exposing blog.domain.com in HTTP redirect if you called/news
without trailing slash. Those redirects were quickly handled by my custom index.php, but still I want to avoid exposing blog.domain.com completely. - Second (and pretty-much current) approach was again pointing the
root
of blog.domain.com‘s directly to WordPress’ directory,/home/webserver-blog/news/
and cheating all the requests for static files withlocation ~* ^/news/(wp-content|wp-admin)
directive pointing it’s root directory one levelel up. This worked for both permalinks and static files, but again –/news/wp-login.php
gives me infinite redirects to itself, and/news/wp-admin/
actually downloads the index.php file instead of parsing it (sends it asapplication/octet-stream
)
I am completely out of ideas… Any help would be much appreciated.
I think I managed to come with a so-so solution. Far from being perfect or clean, but… well, it works.
blog.domain.com‘s config:
So the trick is I’m still operating on filesystem directories and not fancy all-the-way-around rewrites and redirects.
news/
still remains a physical directory in the filesystem that gets read with thelocation /
directive from nginx. Previous issues with exposing the blog.domain.com domain on trying to access without slashes seem to be native nginx’s behaviour – it sees a directory, it adds a slash at the end; and since it’sserver_name
is set to blog.domain.com, here we go. Hardcoding production URL and putting that rule on top pretty much fixed the problem.@redir
location again enabled the WordPress’ permalinks nicely.One more thing I have added to entire setup to prevent people form going directly on http://blog.domain.com/ is another
index.php
file stored directly in/home/webserver-blog/
:…and, as mentioned before, few lines on top of WordPress’ original
index.php
:Ugly… but works.
I’d still be happy to hear nicer solutons. 🙂