First of all, I have tried to search for similar questions, but the solutions to those questions were specific lines of code, that I couldn't customise to fit my needs.
I have a Codeigniter installation, and I'm trying to migrate from Apache to nginx. However, in Apache the .htaccess was pretty simple: it would take a whitelist, and rewrite everything else to index.php.
RewriteEngine on
RewriteCond $1 !^(index\.php|css|images|core|uploads|js|robots\.txt|favicon\.ico)
RewriteRule ^(.*)$ /index.php/$1 [L]
However in nginx, I have tried out the if and try_files directives, as well as messing around with locations, to no avail. I'm still new to how nginx reads the server config, and the tutorials online were somewhat confusing to follow through.
Additionally, the index.php will not be in the web root, but in a subdirectory server.
Because of this, I also need to make sure even URI requests beginning with /server do not go to the directory, but to index.php
This is my nginx virtual host configuration so far:
server {
listen 80;
server_name example.com;
root /home/example/public_html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
index index.htm index.html index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/example.sock;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* ^.*(/|\..*) {
try_files $uri $uri/ /server/index.php;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Which helps to redirect requests to index.php, but doesn't have a whitelist. I would appreciate it if anyone could generate a working example with a brief explanation of what each part does.
I would use the $uri variable and if in a location block to achieve this.
location / {
if ( $uri !~ ^/(index\.php|css|images|core|uploads|js|robots\.txt|favicon\.ico) ) {
rewrite ^ /server/index.php last;
}
}
Also, as for the pathinfo security problems, (discussion) it's a good practice to add
try_files $uri =403;
fastcgi_split_path_info ^(.+.php)(.*)$;
to the location ~ \.php$ block.
Related
I don't have much experience with regex, and less in an Nginx context, so this one is a difficult one for me.
What I want is that when I'm on a especific page (not subfolder) the server takes images from a different root.
My current configuration to handle images in all the pages of my website right now is this one.
location ~* \.(png|jpg|jpeg|gif) {
root /usr/share/nginx/nginxTestPHP/media;
}
And I'd like that when I'm in the page example.com/My-Profile the server handles the images from /usr/share/nginx/nginxTestPHP/media/uploads, my idea is something like this, if it makes any sense.
location ~* /My-Profile/*\.(png|jpg|jpeg|gif) {
root /usr/share/nginx/nginxTestPHP/media/uploads;
}
Obviously this one doesn't work otherwise I wouldn't be here asking this, so for the regex pros out there, what would be the solution for this one ?
Also how would I apply this in 2 different pages in the same regex, something like (My-Profile|Configuration) is my idea.
My Nginx configuration
server {
listen 81;
listen [::]:81;
server_name IP;
client_max_body_size 4M;
charset UTF-8;
include /etc/nginx/mime.types;
error_log /var/log/nginx/error_log warn;
access_log /var/log/nginx/access_log main;
rewrite ^(/.*)\.html(\?.*)?$ $1$2 permanent;
rewrite ^/(.*)/$ /$1 permanent;
root /usr/share/nginx/nginxTestPHP/PHP;
index index.html index.htm Inicio.php Index.php;
location / {
try_files $uri/index.html $uri.html $uri/ #extensionless-php;
}
location #extensionless-php {
rewrite ^(.*)$ $1.php last;
}
# pass the PHP scripts to FastCGI
location ~ \.php$ {
try_files $uri =404;
fastcgi_intercept_errors on;
fastcgi_pass app:9000;
fastcgi_index Inicio.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
location ^~ /vendor/ {
deny all;
return 403;
}
# deny access to .htaccess files
location ~ /\.ht {
deny all;
}
location ^~ /en/ {
try_files $uri/.php $uri.php $uri/ #rewrite;
fastcgi_intercept_errors on;
fastcgi_pass app:9000;
fastcgi_index Index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
location ^~ /Blog/ {
try_files $uri/.php $uri.php $uri/ #rewrite;
fastcgi_intercept_errors on;
fastcgi_pass app:9000;
fastcgi_index Index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
location #rewrite {
rewrite ^/(en|Blog)(/.*\.(png|jpg|svg|ico))$ $2 last;
return 404;
}
location ~ \.css {
root /usr/share/nginx/nginxTestPHP/CSS;
default_type text/css;
add_header Content-Type text/css;
}
location ~ \.js {
root /usr/share/nginx/nginxTestPHP/JavaScript;
default_type text/javascript;
add_header Content-Type application/x-javascript;
}
location ~ \.txt {
root /usr/share/nginx/nginxTestPHP/PHP;
}
location ~* ^/Mi-Perfil/([^/]+\.(png|jpg|jpeg|gif))$ {
alias /usr/share/nginx/nginxTestPHP/media/uploads/$1;
}
location ~* \.(png|jpg|svg|ico|jpeg|gif) {
root /usr/share/nginx/nginxTestPHP/media;
}
error_page 405 =200 $uri;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/nginxTestPHP/PHP;
try_files $uri /Inicio.php;
}
}
Your regex is broken, it is a dot (.) in PCRE patterns that acts as a wildcard, not an asterisk one. If you want to match any non-zero number of characters except a / one, you can use [^/]+ regex pattern:
location ~* /My-Profile/[^/]+\.(png|jpg|jpeg|gif)$ { ... }
or to ensure that an URI started exactly with /My-Profile/ add a ^ anchor (matches start of the string):
location ~* ^/My-Profile/[^/]+\.(png|jpg|jpeg|gif)$ { ... }
Check the difference between root and alias nginx directives. With your configuration nginx will search the files inside the /usr/share/nginx/nginxTestPHP/media/uploads/My-Profile folder. Use an alias directive instead:
location ~* ^/My-Profile/[^/]+\.(png|jpg|jpeg|gif)$ {
alias /usr/share/nginx/nginxTestPHP/media/uploads;
}
Update
I think I made a serious mistake. Since this is a regex matching location an alias directive argument should contain full path to image file with filename:
location ~* ^/My-Profile/([^/]+\.(png|jpg|jpeg|gif))$ {
alias /usr/share/nginx/nginxTestPHP/media/uploads/$1;
}
Little experience with Nginx here but the regex part looks relatively simple to fix - try using:
location ~* /My-Profile/.+\.(png|jpg|jpeg|gif)$ {
root /usr/share/nginx/nginxTestPHP/media/uploads;
}
Note the .+ after My-Profile/ and the end-of-string anchor ($) - I'm assuming you want to only match images, not a URI like stackoverflow.com/test.png/somepage.
From the little research I did, you may also want to look into nginx maps, especially if you're looking to do this for multiple profile pages all following the same URI pattern.
I'm trying to modify my NGINX config to strip the .html extension from URI's before they are passed to my PHP based CMS.
In other words when a visitor enters:
http://www.example.com/foo.html
I want the URI to be changed to/;
http://www.example.com/foo
Without doing an actual browser redirect. This is easy enough to accomplish in Apache, but I can't seem to crack the nut in NGINX. Here is what I have in my config file that doesn't seem to work.
location ~ \.html {
rewrite ^(/.*)\.html(\?.*)?$ $1$2 last;
}
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
Using this code the REQUEST_URI that PHP picks up is still /foo.html.
Possible answer to my own question, or at least a workaround.
So apparently $request_uri is always going to contain the original URI, not the rewrite - that is contained in $uri. So to workaround this I'm using a variable to store and pass the modifed URI to PHP. I'm not really thrilled with this solution though.
location ~ \.html {
rewrite ^(/.*)\.html(\?.*)?$ $1$2 last;
}
location / {
set $new_uri $uri
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param REQUEST_URI $new_uri;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
※ I'm using example.com as example
I'm developing an app with ELB and EC2.
The structure is as followed.
When an user access to /manage/*, ELB will transfer to wordpress hosted instance.
Here is the ELB setting.
About ELB it works, but after transfered to wordpress side, CSS and JS files' response show 404.
When I access to /magazine/* URL, loading animation of wordpress theme starts to work but get stuck because of not loaded css and js.
I'm guessing it's because of nginx configuration but can't solve it.
This is the content of configuration file. I just add /etc/nginx/conf.d/vhosts.conf and write some settings. I don't touch other files.
# vhosts.conf
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name example.com;
root /var/www/html;
location /magazine {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
}
below /var/www/html, project's structure is as followed.
/wp-content
/wp-admin
/wp-include
index.php
wp-config.php
for other information,
I installed php-fpm.
SSL certification is set up with ACM and Route53
Additional Info
Both siteurl and home in DB table wp_options are set to https://example.com/magazine.
Result
made /var/www/html/magazine directory and move all files into it.
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name example.com;
location ~* /(wp-config|xmlrpc)\.php {
deny all;
}
location #magazine {
rewrite ^/magazine(.*) /magazine/index.php?$args;
}
location ^~ /magazine {
root /var/www/html;
index index.php index.html index.htm;
try_files $uri $uri/ #magazine;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
}
}
}
Since you are not serving wordpress from the root of your url, you must tell wordpress to load the assets from the subdirectory. How you can do this, is described in a wordpress support article. [1]
Did you check whether the WP_HOME and WP_SITEURL variables are set correctly?
Could you edit your question and include the URL your browser tries to load for the css and js files since it is not fully visible in the screenshot?
Edit:
Thanks to the additional information we know that wordpress constructs the path as expected. So, now I share your opinion that nginx is causing the issue.
I looked around and noticed two possible issues with the nginx configuration:
The root statement should probably be inside the location block. I do not know if this is really necessary, but many people do it. [2]
The location block does a prefix match and includes the prefix magazine into the $uri variable as stated in a serverfault thread. [3]
You could strip away the prefix by using a regex as follows:
location ~ ^/magazine(.*) {
root /var/www/html;
try_files $1 $1/ /index.php?$args;
}
Note: I do not know if the directory redirect $1 and default redirect to /index.php?$args make sense for serving js/css assets. You should probably remove them if they are not necessary.
References
[1] https://wordpress.org/support/article/changing-the-site-url/#changing-the-site-url
[2] https://serverfault.com/a/258540/531099
[3] https://serverfault.com/a/455853/531099
I have a website with URLs corresponding to PHP files:
www.mysite.com/cat.php?id=stuff
These PHP files don't exist anymore, how can I do a 301 redirect (for SEO reasons) to the new URL :
www.mysite.com/stuff
I tried
rewrite ^/cat\.php\?id=stuff http://www.mysite.com/stuff? permanent;
But it does not work, I get a "No input file specified".
Thank you for your help!
EDIT:
More about my config (website is powered by Wordpress):
index index.php;
root /var/www/mydirectory;
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
The issue is that you've added a ? to the end of your rewritten directory, so nginx is telling PHP to serve http://yourdomain.com/stuff?/index.php which doesn't exist.
Assuming mysites.com was a typo and you're redirecting to the same domain, try this:
rewrite ^/cat\.php\?id=(.*)$ /$1/ permanent;
There are a lot of issues with using rewrite and try_files together, I have a working config using these, something like:
I think the rule is that your rewrite rule has to come before try_files, so try this:
index index.php;
root /var/www/mydirectory;
location = / {
rewrite ^/cat\.php\?id=(.*)$ /$1/ permanent;
}
location ^(.*)$ {
try_files $uri $uri/ /index.php?$1;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
I'm trying to change my website over from the default /year/month/day/post_title permalinks, to a simple /post_title/ link, however, when changing it, all of my older links are broken. I've read a site on how to do it on Apache with .htaccess, but need some help on figuring out how to make it work with nginx's location instead of mod_rewrite.
This is the site that details how to do it on Apache http://www.rickbeckman.org/how-to-update-your-wordpress-permalinks-without-causing-link-rot/
And I tried using this htaccess to nginx converter http://winginx.com/htaccess however, the regex is probably causing a problem and I get this error when starting nginx
[emerg]: unknown directive "4}/[0-9]" in /usr/local/nginx/sites-enabled/website.com:19
And this is my configuration file
server {
listen 80;
server_name website.com;
rewrite ^/(.*) http://www.website.com/$1 permanent;
}
server {
listen 80;
server_name www.website.com;
error_log /home/user/public_html/website.com/log/error.log;
client_max_body_size 10M;
client_body_buffer_size 128k;
location / {
root /home/user/public_html/website.com/public/;
index index.php index.html;
try_files $uri $uri/ /index.php;
}
location ~ ^/[0-9]{4}/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+) {
rewrite ^(.*)$ http://website.com/$1 permanent;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$
{
fastcgi_read_timeout 120;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include /usr/local/nginx/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /home/user/public_html/website.com/public/$fastcgi_script_name;
}
}
Would anyone know how to fix it? Thanks.
the fix is easy:
location ~ ^/[0-9]{4}/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+) {
rewrite ^(.*)$ http://website.com/$1 permanent;
}
the problem with the above is that the rewrite resets the backreferences so the $1 now matches the entire url from your rewrite match, not the $1 from the location match.
the following should work:
location ~ ^/[0-9]{4}/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+) {
set $post_title $1;
rewrite ^(.*)$ http://website.com/$post_title permanent;
}
(alternatively match the regex in the rewrite rule again)
Fixed it by adding quotes around the regex.
rewrite "^/[0-9]{4}/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+)" http://www.website.com/$1;