1. 程式人生 > >[樂意黎]Nginx 重寫wordpress路徑於二級子目錄方法

[樂意黎]Nginx 重寫wordpress路徑於二級子目錄方法

把web server 從apache httpd 換成 nginx  後,發現 原 blog 無法訪問了。
原因是原 apache 下的 .htaccess 檔案在nginx 下不生效。


nginx 配置檔案路徑,如: /usr/local/nginx/conf/nginx.conf

在nignx 配置檔案路徑中, server 配置項下加入如下

#blog 為二級目錄,如  www.daza.ren/blog
location /blog/ { 
    index  index.php; 
    try_files $uri $uri/ /blog/index.php?$args; 
} 

wordpress多站點使用子目錄重寫規則:

map $uri $blogname{
 ~^(?P<blogpath>/[^/]+/)files/(.*) $blogpath ;
}
  
map $blogname $blogid{
 default -999;
  
 #Ref: http://wordpress.org/extend/plugins/nginx-helper/
 #include /var/www/wordpress/wp-content/plugins/nginx-helper/map.conf ;
}
  
server {
 server_name daza.ren ;
  
 root /var/www/daza.ren/htdocs;
 index index.php;
  
 #多站點配置
 location ~ ^(/[^/]+/)?files/(.+) {
 try_files /wp-content/blogs.dir/$blogid/files/$2 /wp-includes/ms-files.php?file=$2 ;
 access_log off; log_not_found off; expires max;
 }
  
 #avoid php readfile()
 location ^~ /blogs.dir {
 internal;
 alias /var/www/daza.ren/htdocs/wp-content/blogs.dir ;
 access_log off; log_not_found off; expires max;
 }
  
 if (!-e $request_filename) {
 rewrite /wp-admin$ $scheme://$host$uri/ permanent; 
 rewrite ^(/[^/]+)?(/wp-.*) $2 last; 
 rewrite ^(/[^/]+)?(/.*\.php) $2 last; 
 }
  
 location / {
 try_files $uri $uri/ /index.php?$args ;
 }
  
 location ~ \.php$ {
 try_files $uri =404;
 include fastcgi_params;
 fastcgi_pass php;
 }
  
 #此處可以繼續新增偽靜態規則
}

wordpress多站二級域名重寫規則:

配置中daza.ren修改為自己的站點域名

map $http_host $blogid {
 default  -999;
  
 #Ref: http://wordpress.org/extend/plugins/nginx-helper/
 #include /var/www/wordpress/wp-content/plugins/nginx-helper/map.conf ;
  
}
  
server {
 server_name daza.ren *.daza.ren ;
  
 root /var/www/daza.ren/htdocs;
 index index.php;
  
 location / {
 try_files $uri $uri/ /index.php?$args ;
 }
  
 location ~ \.php$ {
 try_files $uri =404;
 include fastcgi_params;
 fastcgi_pass php;
 }
  
 #WPMU Files
  location ~ ^/files/(.*)$ {
    try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ;
    access_log off; log_not_found off;  expires max;
  }
  
 #WPMU x-sendfile to avoid php readfile()
 location ^~ /blogs.dir {
 internal;
 alias /var/www/daza.ren/htdocs/wp-content/blogs.dir;
 access_log off; log_not_found off; expires max;
 }
  
 #此處可以繼續新增偽靜態規則
}

其它參考:

Main (generic) startup file

This is equivalent to /etc/nginx/nginx.conf (or /etc/nginx/conf/nginx.conf if you're using Arch Linux).

# Generic startup file.
user {user} {group};

#usually equal to number of CPUs you have. run command "grep processor /proc/cpuinfo | wc -l" to find it
worker_processes  auto;
worker_cpu_affinity auto;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

# Keeps the logs free of messages about not being able to bind().
#daemon     off;

events {
	worker_connections  1024;
}

http {
#	rewrite_log on;

	include mime.types;
	default_type       application/octet-stream;
	access_log         /var/log/nginx/access.log;
	sendfile           on;
#	tcp_nopush         on;
	keepalive_timeout  3;
#	tcp_nodelay        on;
#	gzip               on;
        #php max upload limit cannot be larger than this       
	client_max_body_size 13m;
	index              index.php index.html index.htm;

	# Upstream to abstract backend connection(s) for PHP.
	upstream php {
                #this should match value of "listen" directive in php-fpm pool
		server unix:/tmp/php-fpm.sock;
#		server 127.0.0.1:9000;
	}

	include sites-enabled/*;
}

This is a bit different from standard nginx.conf files. This configuration follows the Ubuntu/Debian method of declaring enabled sites for maximum flexibility - using 'sites-available' to store a config and then symlink to the config file from 'sites-enabled'.

Per Site configuration

# Redirect everything to the main site. We use a separate server statement and NOT an if statement - see http://wiki.nginx.org/IfIsEvil

server {
        server_name  _;
        return 302 $scheme://example.com$request_uri;
}

server {
	server_name example.com;
	root /var/www/example.com;

	index index.php;

	include global/restrictions.conf;

	# Additional rules go here.

	# Only include one of the files below.
	include global/wordpress.conf;
#	include global/wordpress-ms-subdir.conf;
#	include global/wordpress-ms-subdomain.conf;
}

Splitting sections of the configuration into multiple files allows the same logic to be reused over and over. A 'global' subdirectory is used to add extra rules for general purpose use (either /etc/nginx/conf/global/ or /etc/nginx/global/ depending on how your nginx install is set up).

Global restrictions file

# Global restrictions configuration file.
# Designed to be included in any server {} block.
location = /favicon.ico {
	log_not_found off;
	access_log off;
}
# robots.txt fallback to index.php
location = /robots.txt {
# Some WordPress plugin gererate robots.txt file
    allow all;
    try_files $uri $uri/ /index.php?$args @robots;
    access_log off;
    log_not_found off;
}
# additional fallback if robots.txt doesn't exist
location @robots {
   return 200 "User-agent: *\nDisallow: /wp-admin/\nAllow: /wp-admin/admin-ajax.php\n";
}

# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac) excepted .well-known directory.
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\.(?!well-known\/) {
    deny all;
}

# Deny access to any files with a .php extension in the uploads directory for the single site
location /wp-content/uploads {
    location ~ \.php$ {
        deny all;
    }
}


# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
	deny all;
}

General WordPress rules

For single site installations, here is the 'global/wordpress.conf' file:

# WordPress single site rules.
# Designed to be included in any server {} block.
# Upstream to abstract backend connection(s) for php
upstream php {
        server unix:/tmp/php-cgi.socket;
        server 127.0.0.1:9000;
}

server {
        ## Your website name goes here.
        server_name domain.tld;
        ## Your only path reference.
        root /var/www/wordpress;
        ## This should be in your http block and if it is, it's not needed here.
        index index.php;

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location / {
                # This is cool because no php is touched for static content.
                # include the "?$args" part so non-default permalinks doesn't break when using query string
                try_files $uri $uri/ /index.php?$args;
        }

        location ~ \.php$ {
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi.conf;
                fastcgi_intercept_errors on;
                fastcgi_pass php;
                fastcgi_buffers 16 16k;
                fastcgi_buffer_size 32k;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

This is more uptodate example for nginx v .10 and ↑.
Ref: https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/

WordPress Multisite Subdirectory rules

For multisite subdirectory installations, here is the 'global/wordpress.conf' file:

# WordPress multisite subdirectory rules.
# Designed to be included in any server {} block.

map $uri $blogname{
    ~^(?P<blogpath>/[^/]+/)files/(.*)       $blogpath ;
}

map $blogname $blogid{
    default -999;

    #Ref: http://wordpress.org/extend/plugins/nginx-helper/
    #include /var/www/wordpress/wp-content/plugins/nginx-helper/map.conf ;
}

server {
    server_name example.com ;

    root /var/www/example.com/htdocs;
    index index.php;

    location ~ ^(/[^/]+/)?files/(.+) {
        try_files /wp-content/blogs.dir/$blogid/files/$2 /wp-includes/ms-files.php?file=$2 ;
        access_log off;     log_not_found off; expires max;
    }

    #avoid php readfile()
    location ^~ /blogs.dir {
        internal;
        alias /var/www/example.com/htdocs/wp-content/blogs.dir ;
        access_log off;     log_not_found off; expires max;
    }

    if (!-e $request_filename) {
        # Don't use `$uri` here, see https://github.com/yandex/gixy/issues/77
        rewrite /wp-admin$ $scheme://$host$request_uri/ permanent;
        rewrite ^(/[^/]+)?(/wp-.*) $2 last;
        rewrite ^(/[^/]+)?(/.*\.php) $2 last;
    }

    location / {
        try_files $uri $uri/ /index.php?$args ;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_pass php;
    }

    #add some rules for static content expiry-headers here
}

NGINX provides 2 special directive: X-Accel-Redirect <x-accel.redirect_> and map. Using these 2 directives, one can eliminate performance hit for static-file serving on WordPress multisite network.

Note: WordPress Network installs no longer need the `blogs.dir` rules when creating a network, however may still be needed when migrating older installations.

WordPress Multisite subdomains rules

map $http_host $blogid {
    default       -999;

    #Ref: http://wordpress.org/extend/plugins/nginx-helper/
    #include /var/www/wordpress/wp-content/plugins/nginx-helper/map.conf ;

}

server {
    server_name example.com *.example.com ;

    root /var/www/example.com/htdocs;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args ;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_pass php;
    }

    #WPMU Files
        location ~ ^/files/(.*)$ {
                try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ;
                access_log off; log_not_found off;      expires max;
        }

    #WPMU x-sendfile to avoid php readfile()
    location ^~ /blogs.dir {
        internal;
        alias /var/www/example.com/htdocs/wp-content/blogs.dir;
        access_log off;     log_not_found off;      expires max;
    }

    #add some rules for static content expiry-headers here
}

Ref: https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/

Note: WordPress Network installs no longer need the `blogs.dir` rules when creating a network, however may still be needed when migrating older installations.

HTTPS in Nginx

Enabling HTTPS in Nginx is relatively simple.

server {
    # listens both on IPv4 and IPv6 on 443 and enables HTTPS and HTTP/2 support.
    # HTTP/2 is available in nginx 1.9.5 and above.
    listen *:443 ssl http2;
    listen [::]:443 ssl http2;

    # indicate locations of SSL key files.
    ssl_certificate /srv/www/ssl/ssl.crt;
    ssl_certificate_key /srv/www/ssl/ssl.key;
    ssl_dhparam /srv/www/master/ssl/dhparam.pem;
    
    # indicate the server name
    server_name example.com *.example.com;

    # Enable HSTS. This forces SSL on clients that respect it, most modern browsers. The includeSubDomains flag is optional.
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

    # Set caches, protocols, and accepted ciphers. This config will merit an A+ SSL Labs score as of Sept 2015.
    ssl_session_cache shared:SSL:20m;
    ssl_session_timeout 10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:CAMELLIA256-SHA:CAMELLIA128-SHA256;
}

Mozilla offers an excellent SSL config generation tool as well.

WP Super Cache Rules

# WP Super Cache rules.
# Designed to be included from a 'wordpress-ms-...' configuration file.

set $cache_uri $request_uri;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
        set $cache_uri 'null cache';
}
   
if ($query_string != "") {
        set $cache_uri 'null cache';
}   

# Don't cache uris containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
        set $cache_uri 'null cache';
}   

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
        set $cache_uri 'null cache';
}

# START MOBILE
# Mobile browsers section to server them non-cached version. COMMENTED by default as most modern wordpress themes including twenty-eleven are responsive. Uncomment config lines in this section if you want to use a plugin like WP-Touch
# if ($http_x_wap_profile) {
#        set $cache_uri 'null cache';
#}

#if ($http_profile) {
#        set $cache_uri 'null cache';
#}

#if ($http_user_agent ~* (2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800)) {
 #       set $cache_uri 'null cache';
#}

#if ($http_user_agent ~* (w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-)) {
  #      set $cache_uri 'null cache';
#}
#END MOBILE

# Use cached or actual file if they exists, otherwise pass request to WordPress
location / {
        try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php?$args ;
}    

Experimental modifications:

If you are using HTTPS, the latest development version of WP Super Cache may use a different directory structure to differentiate between HTTP and HTTPS. try_files line may look like below:

location / {
        try_files /wp-content/cache/supercache/$http_host/$cache_uri/index-https.html $uri $uri/ /index.php?$args ;
}

W3 Total Cache Rules

W3 Total Cache uses different directory structure for disk-based cache storage depending on WordPress configuration.

Cache validation checks will remain common as shown below:

#W3 TOTAL CACHE CHECK 
set $cache_uri $request_uri;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
        set $cache_uri 'null cache';
}   
if ($query_string != "") {
        set $cache_uri 'null cache';
}   

# Don't cache uris containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
        set $cache_uri 'null cache';
}   

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
        set $cache_uri 'null cache';
}
#ADD mobile rules from WP SUPER CACHE section above

#APPEND A CODE BLOCK FROM BELOW...

After creating a map{..} section, you just need to make one more change in your Nginx config so requests for /files/will be first processed using nginx map{..}:

location ~ ^/files/(.*)$ {
          try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ;
          access_log off; log_not_found off; expires max;
 }