I have a Rails app configured with nginx with its root at /var/www/apps/example/current/public. It's accessed at https://www.example.com. That all works great. I decided to add a blog, and I wanted to go with Wordpress. I installed it in a different directory on the server, /var/www/apps/blog, and I want to be able to access it by going to https://www.example.com/blog
Below is my nginx config:
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/certs/example.com.key;
server_name www.example.com;
root /var/www/apps/example/current/public;
passenger_enabled on;
rails_env production;
client_max_body_size 100M;
client_body_buffer_size 256k;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /blog {
root /var/www/apps;
location ~ [^/]\.php(/|$) {
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
I can navigate to example.com/blog and it takes me there without any issues. The problem comes when I enable pretty URLs and try to view a post. It circumvents the /blog directory and hits my Rails app, ending up with a 404. I see the following error in /var/log/nginx/error.log:
2016/06/30 17:24:32 [error] 7035#0: *20 "/var/www/apps/blog/hello-world/index.html" is not found (2: No such file or directory), client: 199.27.128.198, server: www.example.com, request: "GET /blog/hello-world/ HTTP/1.1", host: "www.example.com", referrer: "https://www.example.com/blog/"
Adding an index index.php directive doesn't fix the problem, it merely then states that /var/www/apps/blog/hello-world/index.php is not found instead.
Any ideas? I'm stumped.
try_files $uri=404; is not enough for pretty permalinks.
To enable pretty permalinks, you need to change it to:
location /blog {
root /var/www/apps/blog;
try_files $uri $uri/ /index.php?$args;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Or, try non-root try_files redirect:
location /blog {
try_files $uri $uri/ /blog/index.php?$args;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Here's a quick guide setting up wordpress with rails
Related
I've a web server which has two PHP files, index.php and controller.php, the latter which handles all non-/ requests with a p (for page) parameter, e.g.
/controller.php?p=some_page
The following nginx configuration works nicely:
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /code;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
However, I now want to clean up the URLs, and want / to go to index.php and /some_page to go to /controller.php?p=some_page.
Here's the new configuration I'm trying:
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /code;
# this is new, and makes index.php handle /
location / {
index index.php;
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# this is new, but doesn't work.
location #rewrites {
if ($uri ~* ^/([0-9a-z_]+)$) {
set $page_to_view "/controller.php?p=$1";
rewrite ^/([0-9a-z_]+)$ $scheme://$http_host/controller.php?p=$1 last;
}
}
}
The browser address bar shows this:
- http://localhost:8080/some_page (initial request)
- http://localhost:8080/controller.php?p=some_page (first redirect one second later)
- https://localhost/some_page/ (final redirect another second later)
So, it ends up on a URL which doesn't have the original port, with a trailing slash, and using scheme https.
What can I do to fix it?
PS It would be a bonus if trailing slashes didn't matter (i.e. localhost:8080/some_page and localhost:8080/some_page/ shows the same thing.
PS the port 8080 is just me locally testing via Docker, which maps container 80 to host 8080.
Update:
I've implemented Richard's answers, and tried the suggested curl:
$ curl -I http://localhost:8080/some_page
HTTP/1.1 301 Moved Permanently
Server: nginx/1.21.4
Date: Thu, 09 Dec 2021 15:07:11 GMT
Content-Type: text/html
Content-Length: 169
Location: http://localhost/some_page/
Connection: keep-alive
Note the lack of port 8080.
Update 2:
With nginx directive absolute_redirect off;, I get this:
$ curl -I http://localhost:8080/some_page
HTTP/1.1 301 Moved Permanently
Server: nginx/1.21.4
Date: Thu, 09 Dec 2021 16:01:31 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: /some_page/
$ curl -I http://localhost:8080/some_page/
HTTP/1.1 404 Not Found
Server: nginx/1.21.4
Date: Thu, 09 Dec 2021 16:01:34 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive
So, the question remains how a request to /some_page/ can serve up the response from /controller.php?p=some_page
A named location (e.g. location #rewrites) is usually invoked from the last element of a try_files statement.
For example:
location / {
index index.php;
try_files $uri $uri/ #rewrites;
}
In your location #rewrites block, the if statement is unnecessary, the set variable is unused, and the rewrite statement will provoke an external redirect.
Try:
location #rewrites {
rewrite ^/([0-9a-z_]+)$ /controller.php?p=$1 last;
}
I've landed on a configuration which works with the original links, but also the pretty URLs I was aiming for.
server {
listen 80;
index index.php;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /code;
location = / {
index index.php;
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~* {
rewrite ^/([0-9a-z_]+)/?$ /controller.php?p=$1 last;
}
}
The key seems to be to not use a named location for the rewrite, but just match "everything else" with location ~* if the request isn't for / or a PHP file.
I have two docker containers as below:
nginx ==> working as proxy web server (nginx web server)
dist ==> working as a php-fpm container
And this is my dist.conf:
server {
server_name dist.me.com;
root /var/www/html;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass dist:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location ~ \.php$ {
return 404;
}
error_log /var/log/nginx/dist_error.log;
access_log /var/log/nginx/dist_access.log;
}
The issue is if I enter dist.me.com, it shows my index.php contents fine. But if I enter dist.me.com/index.php or dist.me.com/index2.php, I get error 404 Not Found.
I tried changing some values of conf file but it did not help me.
Both index.php and index2.php exist in /var/www/html path.
Your existing dist.conf is designed to block URIs ending with .php. The internal directive prevents a location from being directly accessed, and there is also a location which explicitly returns 404 for any URI ending with .php.
You need to change the location rule, remove the internal directive, and delete the location block which follows it.
For example, replace location ~ ^/index\.php(/|$) { ... } and location ~ \.php$ { ... } with the single location block as follows:
location ~ \.php(/|$) {
fastcgi_pass dist:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
I'm fairly new to Nginx and web servers in general.
My setup is docker, Nginx, PHP/laravel, +let's encrypt.
I have this Nginx config file:
server {
listen 80;
server_name www.example.io;
return 301 https://example.io$request_uri;
}
server {
listen 80;
server_name example.io;
return 301 https://example.io$request_uri;
}
server {
listen 443 ssl;
server_name example.io;
ssl_certificate /etc/nginx/certs/example.io.pem;
ssl_certificate_key /etc/nginx/certs/example.io.key;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
I'm pretty sure my certificates are not what the problem is. because they do work when I have a single port 80 server and it has server_name example.io www.example.io but in that case, I'm unable to access the website through example.io as secure. while the www.example.io is secure. it also acts like two different websites. I believe the cookies in one do not implement in the other.
What I'm trying to achieve is, I wish to redirect both www.example.io and example.io to https://example.io
My current NGINX config to hosting a website in a subdirectory on a Docker server doesn't seem to work. I tried several things but nothing concluding.
server {
root /www;
access_log /logs/access.log;
error_log /logs/error.log debug;
index index.html index.php;
if ($bad_referer) { return 444; }
# Enable PHP with path_info for any php subfolder
location ~ ^(.+\.php)($|/) {
fastcgi_pass archives_php:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_intercept_errors on;
include /nginx/fastcgi_params;
}
###
### SPECIFIC SITE
###
# Cockpit
location = /site { try_files $uri /site/index.php$uri?$args; }
location /site {
try_files $uri $uri/ /site/index.php$uri?$args;
location ~ ^(.+\.php)($|/) {
fastcgi_pass archives_php:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_intercept_errors on;
include /nginx/fastcgi_params;
}
}
location /site/cockpit { try_files $uri $uri/ /site/cockpit/index.php; }
# Assets disabled logging and expiration max
include /nginx/assets.conf;
}
# Anti spam referrals
include /nginx/referral-spam.conf;
The website works when using dubsomain.site.com/site/index.php/page but this is not the behaviour I would like to have.
A similar website with the same CMS but in the root folder works like a charm.
If you need to append part of the URI to /site/index.php, you will need to use a regular expression.
For example:
location /site {
try_files $uri $uri/ #rewrite;
}
location #rewrite {
rewrite ^/site(.*)$ /site/index.php$1 last;
}
The location = /site is unnecessary, unless there is a specific action that URI needs to perform, and your second location ~ ^(.+\.php)($|/) block which is nested within the location /site block is never invoked, and being identical, is unnecessary anyway.
I'm starting a migration of a WordPress website to a rails application. The migration needs to be done gradually over the next few months, so I'll need to be able to run both sites in parallel. Using fastcgi_intercept_errors on a test environment I've managed to get any 404 errors returned by WordPress to forward on to the Rails application using the following configuration:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name mydomain.com;
root /var/www/html/wordpress;
index index.php index.html
error_page 500 502 503 504 404 #rails;
location / {
try_files $uri $uri/ /index.php?$args;
recursive_error_pages on;
error_page 404 = #rails;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
include fastcgi_params;
error_page 404 = #rails;
}
location #rails{
passenger_enabled on;
passenger_user user;
rails_env development;
root /home/user/rails_app/app/public;
}
}
The problem now comes when the rails app references any /assets links they always forward back into the rails app and always load the root location of the application.
Is there any way to fix this so that assets will also be treated as part of the rails application?
This nginx configuraton was able to do what I needed. error page directive was moved into the only the php location, and an assets location was added to redirect the default root location from the php app to the ruby application public folder.
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name mydomain.com;
root /var/www/html/wordpress;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
recursive_error_pages on;
error_page 404 = #rails;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
include fastcgi_params;
error_page 404 = #rails;
}
location ^~ /assets/ {
root /home/user/rails_app/app/public;
}
location #rails{
passenger_enabled on;
passenger_user user;
rails_env production;
root /home/user/rails_app/app/public;
}
}