I am working on a website available in different countries/regions. For SEO reasons we would like to use subdirectories per country for the url. So we have example.com as main domain. When you navigate to example.com/jp/ you would be shown the Japanese version.
Now for technical reasons (the usage of the Domains module for Drupal to be exact) I would like to use a subdomain to place the website on. Lets say jp.example.com. To the outside world, people would navigate to /jp/ but NGINX returns jp.example.com
Both jp.example.com and example.com are the same website, but because of the domains module it shows different content. This means they share their codebase and theoretically their virtual host configuration. I have been trying many things, but ended up with this:
server {
listen 80;
server_name www.example.com jp.example.com;
root /var/www/example.com;
index index.php index.html index.htm;
location /jp(.+)$ {
proxy_pass http://jp.example.com$1;
}
location #rewrite {
rewrite ^/(.*)$ /index.php?q=$1;
}
location ~ '\.php$|^/update.php' {
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
}
I have left out some of the location entries, I think the above are the only relevant ones, especially the first one. This does result however, in a 404 on the example.com website since the /jp url is not a page.
When I visit jp.example.com directly it does work however. Can it be done and if so, how?
I think I found the solution:
location ~* ^/jp/ {
rewrite ^/jp/(.*)$ /$1 break;
proxy_pass http://jp.example.com:81/$1;
}
I added another vhost in a separate conf file listening to port 81. Though this does seem to work for a page, all files within the page (css, images etc) are still loading from example.com directly. So I think the domains module is still seeing it as the main website. Does nginx forward the original hostname somehow?
Update: I ended up with some nasty nginx tricks by rewriting URL's in the output HTML using the sub_filter module. It looks like this:
location ~ '\.php$|^/update.php' {
sub_filter 'href="/' 'href="http://www.example.com/jp/$1';
sub_filter 'src="/' 'src="http://www.example.com/jp/$1';
sub_filter 'jp.example.com' 'www.example.com/jp';
sub_filter_once off;
sub_filter_types *;
fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
I had to hard code the URL's since $host points to jp.example.com. If you use multiple sub_filter declarations, they are not working on each other. So if you replace src="/test" with src="http://jp.example.com/test" and then replace "jp.example.com" for "www.example.com/jp" it doesn't get replaced. This means for every language I need to do this trick with hardcoded domains, but at least it works. I am not sure if this has any impact on the nginx performance though.
Related
I've run my site on Apache for years, and since I've made the transition over to Nginx for speed preference, my htaccess rewrite rules have broken my site.
My site content is served dynamically based on the URL request - here's how my htaccess file looks for / traffic.
RewriteEngine on
RewriteRule ^([a-zA-Z0-9-z\-\_]+)/$ index.php?first_path=$1 [QSA]
This will pass any directory as a first_path param to index.php.
Reading through the Nginx documentation for url restructuring, I can't seem to figure out how to write my requirements.
Any ideas will help.
You may have some luck with online converters like this one, which specifically to your .htaccess will produce:
server {
server_name example.com;
rewrite ^/([a-zA-Z0-9-z\-\_]+)/$ /index.php?first_path=$1;
}
Naturally, you also have to include a "handler" location for PHP processing so a more complete configuration would be:
server {
server_name example.com;
rewrite ^/([a-zA-Z0-9-z\-\_]+)/$ /index.php?first_path=$1;
location ~ \.php$ {
fastcgi_pass unix:/path/to/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
It's worth noting though, that the creator of NGINX himself, Igor Sysoev, is not in favor of using rewrite directives, dismissing their use to old times when nested locations were not supported.
Nested locations, as per NGINX author allow isolating regular expression thus creating a configuration that is easier to maintain in the future (not necessarily easier to create at first though). So in this case, using nested location, the same config may look like this:
server {
server_name example.com;
location / {
location ~ ^/(?<dir>[a-zA-Z0-9-z\-\_]+)/$ {
fastcgi_pass unix:/path/to/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME /path/to/index.php;
fastcgi_param QUERY_STRING first_path=$dir
include fastcgi_params;
}
}
location ~ \.php$ {
fastcgi_pass unix:/path/to/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
I'm trying to set up a Wordpress in a system that has another php application installed, using nginx as web server.
I've simplified my config file to the maximun. The following confi is serving one post of my blog:
server {
listen 80;
server_name blog.ct.com;
root /home/ff/www/blog/;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$uri&$args =405;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_buffer_size 128k;
fastcgi_buffers 64 32k;
fastcgi_busy_buffers_size 128k;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param APPLICATION_ENV development;
fastcgi_param HTTP_X_FORWARDED_PROTO https;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
}
But, due my system's requirements I need to serve the blog from within a sub path (In my final system http://blog.ct.com/ should be serving my custom php app and http://blog.ct.com/vendor should be serving the wordpress blog).
The local root directory from wordpress must be /home/ff/www/blog/ (this cannot be changed, while my custom app's directory is /home/ff/www/myapp/). So I think I need to reserve location / for my custom app, I have to create a location /vendor
If I add /vendor and I return 403 in / (just to debug easier), the browser says 405 (notice the =405 in /vendor, also to debug easier):
location /vendor {
try_files $uri $uri/ /index.php?$uri&$args =405;
}
location / {
return 403;
}
So I think nginx is going into location /vendor but is not finding my php script in /home/ff/www/blog/index.php so its returning the fallback 405.
Any idea why this could happen?
How can I achieve to load http://blog.ct.com/vendor as the root from wordpress but keeping http://blog.ct.com/ using another php script?
I've found out the following hints that gave me the clue to fix the problem (in case someone has the same problem than me, this may help)
Using location /path is not the same as using location ~(/path) (regex have different priority, so maybe they are not being checked in the order you think)
Adding error_log /your/path/log/error.log debug; to any location block may help you to see how is nginx serving every request (e.g. to location fastcgi, location \vendor, or the server{ block).
alias /var/www/path/vendor works different than root /var/www/path/vendor (check Nginx -- static file serving confusion with root & alias);
In case of the root directive, full path is appended to the root including the location part, whereas in case of the alias directive, only the portion of the path NOT including the location part is appended to the alias.
using rewrite with alias can help you parse the php file you want independent of the path
if (!-f $request_filename) {
rewrite ^ $document_root/index-wp.php last;
}
Take care of the SCRIPT_FILENAME you are using (check it with error_log, see above), maybe you need fastcgi_param SCRIPT_FILENAME $fastcgi_script_name; but you are loading fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; so depending on your previous config you may be attaching the document root twice.
Two different configurations for fastcgi can be used if you change your index.php file names. E.g. location ~ wp\.php$ { will work with wp.php while location ~ \.php$ { will work with all other php files like index.php.
I need to install postfixadmin as a subfolder of a domain hosted in nginx.
In other words, I'm trying to access postfixadmin using http://example.com/postfixadmin
Physically, the contents of the sites are stored this way:
example.com site in /var/www/example
Postfixadmin files in /var/www/postfixadmin
I've tried adding this within the server section of example.com:
location ~ /posfixadmin/ {
root /var/www;
index index.php;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
The above works partially, php scripts are executed correctly, but css and image files found under /var/www/postfixadmin/css and /var/www/postfixadmin/images are not loaded.
I've checked at the generated html code and the links to css and image files in postfixadmin are called using relative paths, like this:
href="css/default.css"
I think nginx tries to get the css files from http://example.com/css instead of http://example.com/postfixadmin/css, that's why it's failing, I've tried something like this:
location /postfixadmin/css/ {
root /var/www/postfixadmin;
}
but the above doesn't work.
Any idea about how to fix this? Thanks in advance!
I know it's an old topic, but still: do not use "root" in a "location" block. Source: https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
This works for me at the moment with the current PostfixAdmin 3.2 (which moved all the public facing stuff into the "public" subdirectory). Mind that I have defined the fastcgi_pass elsewhere, so this bit is not directly applicable.
location /postfixadmin {
alias /usr/local/www/postfixadmin/public;
location ~ ^(.+\.php)(.*)$ {
fastcgi_pass php;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_read_timeout 180;
fastcgi_buffers 4 256k;
fastcgi_buffer_size 128k;
}
location ~ \.php {
include /usr/local/etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass php;
fastcgi_index index.php;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
On many sites can be found this nginx location block :
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000
fastcgi_index index.php
...
}
Given the official documentation of fastcgi_index, it seems like it is used when requests end with /. However, it doesn't match the regular expression of the location block above? Am I missing something about the fastcgi_index directive?
You are right, if your nginx configuration (outside the location directive) has no index directive, then the location directive will never match and the fastcgi_index directive is useless.
If you have a line like this on your configuration
index index.php
then a request to / will create an internal redirect to /index.php, the location will match and fastcgi will be called. php-fpm will need a SCRIPT_FILENAME parameter that points to the file being executed. Normally, the configuration looks something like this:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
$fastcgi_script_name contains the name of the matched script, so fastcgi_index is ignored.
There is at least one instance where fastcgi_index is useful and used: when nginx and php-fpm are on different servers and nginx can't match the index.php file.
On a Zend Framework 2 based website (test environment on nginx and live environment on Apache) there is a category "courses" and its pages have URIs like this:
domain.tld/courses/123-Name of course that can contain ®, €, (, ), and other special chars
The courses names come from the database and are URL-encoded for the internal links:
domain.tld/courses/123-Name%20of%20course%20that%20can%20contain%20%C2%AE%2C%20%E2%82%AC%2C%20%C3%A4%2C%20(%2C%20)%2C%20and%20other%20special%20chars
It's working fine, but when I try to access a page using a special character without encoding a 404-error occures.
An example of website, that uses spacial characters is Wikipedia. You can use
http://en.wikipedia.org/wiki/Signal_(electrical_engineering)
or
http://en.wikipedia.org/wiki/Signal_%28electrical_engineering%29
and are always get the page you want.
Does someone know, how to achieve such behavior ("à la Wikipedia")? (Maybe with HTTP redirecting with a .htaccess rule?)
UPDATE:
/etc/nginx/ax-common-vhost
server {
listen 80;
server_name
foo.loc
bar.loc
baz.loc
;
if ($host ~ ^(?<project>.+)\.(?<area>.+)\.loc$) {
set $folder "$area/$project";
}
access_log /var/log/nginx/$area/$project.access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_min_length 1000;
gzip_types text/plain text/xml application/xml;
client_max_body_size 25m;
root /var/www/$folder/public/;
try_files $uri $uri/ /index.php?$args;
index index.html index.php;
location / {
index index.html index.php;
sendfile off;
}
location ~ (\.inc\.php|\.tpl|\.sql|\.tpl\.php|\.db)$ {
deny all;
}
location ~ \.htaccess {
deny all;
}
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
location ~ \.php$ {
fastcgi_cache off;
#fastcgi_pass 127.0.0.1:9001;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_read_timeout 6000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param APPLICATION_ENV development;
fastcgi_param HTTPS $https;
}
}
You can achieve the intended URL rewrite behavior by having the correct rewrite rules inside of your .htaccess file.
I suggest you have a look at the rewriteflags, particularly the B flag
You should show us your nginx fast_cgi configuration.
They're several way to set the PATH_INFO for PHP, and this is the string containing the path that ZF will have to manage.
One way is:
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
From this post it seems you could also use this way (named captures) to avoid all urlencoding of the PATH_INFO content:
location ~ ^(?<SCRIPT_FILENAME>.+\.php)(?<PATH_INFO>.+)$ {
(...)
fastcgi_param PATH_INFO $PATH_INFO;
So at least you would detect if the problem comes from having too much or not enough urlencoding.
By avoiding urlencoding from the webserver (and by doing the same with apache) you could manage urldecoding of the path in the PHP side. As this time you know it would never be urldecoded, and that you would have to to do it in php -- or maybe you would have to urlencode it -- weel you would have to manage the fact that path may come in both versions.
This would, maybe, be a nice job for a Zend Framework Router. One of the job of the router is to avoid things like .htaccess rewrite rules in apache and manages url in the application, on a stable and webserver-independant way.
First step will be to test the path string and detect if url encoding needs to be done or not.
Of course if you send url with a mix of url-encoded and url-decoded characters in the same string things will get a lot more harder, as you will not be able to decide (but it would be the same for a webserver). And in your example you used parenthesis that were not urlencoded in generated encoded url but encoded in wikipedia example, your application will have to choose a policy for the rfc protected characters.