How to convert a simple index.php redirection from apache to nginx format?
Get the solution ↓↓↓From an old project, I got this .htaccess file, which currently handle the apache rewrite rules:
<IfModule mod_rewrite.c>
RewriteEngine On
# Folders / files to exclude from rewrite divided by Pipe goes here:
RewriteRule (^|/)install(/|$) - [L,NC]
RewriteRule (^|/)web(/|$) - [L,NC]
# turn empty requests into requests for "index.php",
# keeping the query string intact
RewriteRule ^$ index.php [QSA]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !favicon.ico$
RewriteRule ^(.+)$ index.php [QSA,L]
RewriteRule ^(.+)$ index.php [QSA,L]
</IfModule>
What the above snippet basically does, is that it rewrites all requests to index.php by keeping the query part string intact and stop after the first match, unless the file or folder exists.
So, in conclusion, by consulting the Nginx docs and by adding some additional security (permit access to sensible folders and files) and performance-related stuff (enable gzip or brotli output compression where it's possible [depending on the client, which one it is able to process]), I got this:
server {
listen 80;
listen [::]:80;
server_name subdomain.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name tdc.wunner-software.de;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Add headers to serve security-related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
# Path to the root of your installation
root /srv/www/vhosts/example.com/subdomain.example.com;
index index.php index.html;
charset utf-8;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
brotli on;
brotli_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
location ~ ^/vendor/.*$ {
deny all;
}
location ~ ^\.htaccess$ {
deny all;
}
#rewrite ^(.*)/$ index.php$is_args$args break;
location ~ /(.*)$ {
index index.php;
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi.conf;
fastcgi_param HTTP_PROXY "";
fastcgi_param HTTPS $https;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 300s;
client_body_buffer_size 128k;
fastcgi_pass php-handler;
http2_push_preload on;
}
access_log /var/log/nginx/subdomain_example_com_ccess.log;
error_log /var/log/nginx/subdomain_example_com_error.log;
}
The new Nginx configuration above downloads the PHP file instead of bypassing it to the FPM handler. I have found this and this SO questions, but it doesn't seem to do the trick for me. Also, as mentioned in Nginx documentation,if
is evil and we should avoid using it unless we are 100 percent sure what's going on. So, for my configuration, I avoided using it. Mainly because regex syntax also works withlocation
and is way more securer in that context thanif
. I mean, as far as I know. Please correct me, if I'm wrong.
The mainnginx.conf
file is dead simple right now:
user nginx;
worker_processes 1;
# load_module lib64/nginx/modules/ngx_http_fancyindex_module.so;
# load_module lib64/nginx/modules/ngx_http_geoip_module.so;
# load_module lib64/nginx/modules/ngx_http_headers_more_filter_module.so;
# load_module lib64/nginx/modules/ngx_http_image_filter_module.so;
# load_module lib64/nginx/modules/ngx_http_perl_module.so;
# load_module lib64/nginx/modules/ngx_http_xslt_filter_module.so;
# load_module lib64/nginx/modules/ngx_mail_module.so;
# load_module lib64/nginx/modules/ngx_rtmp_module.so;
# load_module lib64/nginx/modules/ngx_stream_geoip_module.so;
# load_module lib64/nginx/modules/ngx_stream_module.so;
error_log /var/log/nginx/error.log;
#error_log /var/log/nginx/error.log notice;
error_log /var/log/nginx/error.log info;
#pid /run/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
include conf.d/*.conf;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /srv/www/htdocs/;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /srv/www/htdocs/;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /srv/www/htdocs/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files if Apache's document root
# concurs with Nginx's one
#
location ~ /\.ht {
deny all;
}
}
# another virtual host using a mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root /srv/www/htdocs/;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# Allow TLS version 1.2 only, which is a recommended default these days
# by international information security standards.
# ssl_protocols TLSv1.2;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root /srv/www/htdocs/;
# index index.html index.htm;
# }
#}
include vhosts.d/*.conf;
}
The file above is mainly the openSUSE distributor shipped file, with a few changes.
And this is mybase.conf
file, which defines the FPM proxy handler for nginx (in order to don't repeat yourself; it's neccessarily needed anyways):
upstream php-handler {
server 127.0.0.1:9000;
#server unix:/var/run/php/php7.2-fpm.sock;
}
I'd appreciate any help with that issue.
Answer
Solution:
What the above snippet basically does
You might take some time to think about the less obvious things these rules do.
The new Nginx configuration above downloads the PHP file instead of bypassing it to the FPM handler
Because all your references to php scripts are being intercepted bylocation ~ \.(?:css|js|woff2?|svg|gif|map)$
which does not hand off work to the PHP FPM. Understanding the precedence in which nginx considers location{} blocks is critical to implementing a successful configuration.
Your try_files directive seems to apply to the server as a whole but you have put it in a location block. It should be in the server block such that it is applied before nginx tries to match a location block.
Using a virtual (or "named") location block provides a means of handling the case where the default option has a handler (like PHP). See the example for Drupal/Fastcgi in the documentation for try_files.
Your config should look something like
server {
...
try_files $uri @phpfpm;
location ~ \.(css|js|woff2?|svg|gif|map)$ {
add_header Cache-Control "public, max-age=15778463";
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
access_log off;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi.conf;
fastcgi_param HTTP_PROXY "";
fastcgi_param HTTPS $https;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 300s;
client_body_buffer_size 128k;
fastcgi_pass php-handler;
http2_push_preload on;
}
location @phpfpm {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi.conf;
fastcgi_param HTTP_PROXY "";
fastcgi_param HTTPS $https;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 300s;
client_body_buffer_size 128k;
fastcgi_pass php-handler;
http2_push_preload on;
}
Although you should really wrap-up all that PHP config in a separate file. Also, you seem somewhat concerned about getting good performance but are using a TCP socket connection to localhost rather than a filesystem socket - which impacts performance and capacity.
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: err_ossl_pem_no_start_line
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.