Nginx 404 pages request method is always GET - nginx

When I post to a 404 page, nginx is stripping the post data and changing the request method to "GET". How do I prevent this? I have nginx configured to serve a php file as the error 404 page that is in the root of the domain directory. I would like to keep a log of whatever is posted to it.
nginx.conf
server {
listen 80;
error_page 404 = /404.php;
set $oldhost $host;
root /var/www/www/$oldhost;
location ~* \.(?:ico|css|js|gif|jpg|png|html|htm)$ {
expires 3d;
add_header Pragma public;
add_header Cache-Control "public";
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location / {
index index.php index.htm index.html;
try_files $uri $uri/ /index.php?$args;
}
location ~ .php$ {
location ~ \..*/.*\.php$ {return 404;}
expires 1d;
add_header Pragma public;
client_max_body_size 80m;
add_header Cache-Control "public";
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_intercept_errors on;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

This happens because when nginx cannot find a page, it will redirect (GET) the user to that 404.php page you defined.
What you need to do is to add it to the try_files directive, so nginx will try to post to it when it cannot find the others, or make it that you can handle 404 error directly on your index.php (like wordpress does).
EDIT:
location / {
index index.php index.htm index.html;
try_files $uri $uri/ /index.php?$args 404.php 404.php?$args;
}

Related

How to map requests from a path?

I have the following domain:
https://example.com
I want, when the following /path/ is hit:
https://example.com/path/subpath/?param1=value1&param2=value2
​
the content from this url to be served:
https://example.com/subpath/?param1=value1&param2=value2
​
without performing a redirect.
​
I have tried using an alias like this:
​
location /path/ {
alias /home/forge/example.com/current/;
}
​
where current is a symlink pointing to the latest release:
​
current -> /root/example.com/releases/timestamp/
​
But it doesn't work. it gives 404.
How can I achieve this?
The entire server block:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
server_tokens off;
root /home/forge/example.com/current;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location /path/ {
alias /home/forge/example.com/current/;
}
location / {
gzip_static on;
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log /var/log/nginx/example.com-access.log;
error_log /var/log/nginx/example.com-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
gzip on;
}
I don't see any reason why
rewrite ^/path(/.*) $1;
didn't work as expected. But if you want to use an alias solution instead, you should take into account that regex matching locations have a greater priority than prefix ones and any request for /path/subpath/index.php would be processed by location ~ \.php { ... } rather than location /path/ { ... }. You can override this with ^~ location modifier using a second nested PHP handler:
location ^~ /path/ {
alias /home/forge/example.com/current/;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}

Wordpress on nginx not loading css/js/images

I have a html/jQuery website(mysite.com) with a wordpress blog(mysite.com/blog). Html site(mysite.com) is hosted on ec2 A instance(and working fine) and blog(mysite.com/blog) is hosted on ec2 B instance.
The blog(WordPress) is loading the HTML page but all the CSS/JS and images hosted on ec2 B are not loading and ending up 404. Even if I try to access the CSS in the browser, it ends up 404, although the file exists on the server.
I tried to tweak the Nginx config but couldn't able to resolve the issue. Any help would be much appreciated.
My nginx config
server {
listen 80;
server_name mysite.com;
root /opt/mysite-blog;
index index.php index.html;
access_log /var/log/nginx/mysite_blog-access.log;
error_log /var/log/nginx/mysite_blog-error.log error;
keepalive_timeout 70;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location /blog {
index index.php;
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass backend_php;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|svg|woff|woff2|ttf)\$ {
expires 30d;
proxy_cache staticcache;
proxy_cache_valid 200 30d;
add_header Cache-Control public;
access_log /dev/null;
}
location ~* \.(?:css|js)\$ {
expires 1d;
add_header Cache-Control public;
access_log /dev/null;
}
location ~ /\.ht {
deny all;
}
}
Resolved the issue by making the following changes
server_name mysite.com;
root /opt/mysite;
location /blog {
index index.php;
alias /opt/mysite-blog;
try_files $uri $uri/ /index.php?$args;
}
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}

Nginx give access to subdirectory

We're running a Wordpress site on a Nginx server, I am now trying to install Piwik there in the /stats folder.
This is the default Nginx configuration that came with the install, I added the "/stats" block myself, but it doesn't work - it gets rendered by WordPress whenever I go to mysite.com/stats instead of going to that folder.
Desired behavior would be that the /stats subdirectory (and all files and directories in it) is just parsed by PHP as would be on a default install without Nginx rules
Any clue what I'm missing?
server_name _;
port_in_redirect off;
client_header_buffer_size 4k;
client_body_buffer_size 128k;
client_max_body_size 16m;
root /var/www/html;
index index.html index.php;
charset utf-8;
log_not_found off;
gzip_static on;
gzip_types text/css application/javascript text/xml;
gzip_vary on;
gzip on;
# redirect server error pages to the static page /50x.html
#
error_page 500 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location #rewrite {
rewrite ^.*$ /index.php?$args;
}
error_page 404 #rewrite;
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
# WP Multisite rewrites
rewrite /([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) /$2 last;
rewrite /([_0-9a-zA-Z-]+/)?(.*\.php)$ /$2 last;
location / {
try_files $uri $uri.gz $uri/ #rewrite;
}
location ~ \.sql$ {
rewrite ^.*$ /index.php?$args;
}
# We do not want to run php from wp uploads
location ~* /(?:uploads|files)/.*\.php$ {
rewrite ^.*$ /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors off;
}
location /stats {
try_files $uri $uri/ /index.php?$args;
index index.php;
}
location = /favicon.ico {
access_log off;
expires 2w;
add_header Cache-Control public;
try_files $uri #rewrite;
}
location ~* \.(js|css|jpg|jpeg|png|gif|ico|woff|woff2|ttf|otf|eot|pdf|xml|mp4|ogg|mp3|mov|wmv|avi|cur|rtf|txt|swf)$ {
add_header Cache-Control public;
add_header Access-Control-Allow-Origin *;
expires 2w;
try_files $uri $uri.gz;
}
The rules for multi-site WordPress, particularly this one: rewrite /([_0-9a-zA-Z-]+/)?(.*\.php)$ /$2 last; will redirect any /stats/index.php URI back to WordPress's /index.php.
If you are not using a multi-site WordPress, you can safely delete the redundant rewrite rules.
If you are using a multi-site WordPress, some redesign is required.

Enable HTTP cached in Nginx

I'm using Nginx as a web server for my site.
My goal is to enable caching on my site so my site can load faster.
I've tried added
proxy_cache one;
Nginx Config File
server {
listen 80 default_server;
server_name default;
root /home/forge/web-app/public;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
index index.html index.htm index.php;
charset utf-8;
location ~* \.html$ {
expires -1;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
#configure cache
proxy_cache one; <----------------------------- Added HERE
proxy_cache_valid any 1m;
}
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 168h;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/default-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
#configure cache
proxy_cache one;
proxy_cache_valid any 1m;
}
location ~ /\.ht {
deny all;
}
}
How do I properly enable HTTP cached in Nginx, and test my work ?
Any hints / suggestions will be much appreciated !
You need to define this cache zone first using proxy_cache_path. Here's the tutorial.

Nginx reverse proxy to Wordpress on an URI

I have a Symfony 2.5.X app running on an nginx server. I will call it domain.com.
The /news URI within that server is configured as a reverse proxy to a remote machine, where I run Wordpress blog on nginx server again. I will call it blog.domain.com.
domain.com's configuration looks like that:
server {
listen 80;
server_name domain.com;
set $project_path /home/webserver/prod.domain.com;
root $project_path/web;
error_log /home/webserver/prod.domain.com/app/logs/nginx_error.log;
access_log /home/webserver/prod.domain.com/app/logs/nginx_access.log;
charset utf-8;
client_max_body_size 65m;
# Some extra speed
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Reverse-proxy all /news calls to remote machine
location ~ /news?(.*) {
access_log off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_set_header Host blog.domain.com; # without it it doesn't work
#proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_set_header X-Custom-Secret 6ffe3dba7213c678324a101827aa3cf22c;
proxy_redirect off;
proxy_buffering off;
#proxy_intercept_errors on;
proxy_pass http://blog.domain.com:80;
break;
}
# Default URLs
location / {
try_files $uri /app.php$is_args$args;
}
# Error pages (static)
#error_page 403 /errorpages/403.html;
error_page 404 /errorpages/404.html;
#error_page 405 /errorpages/405.html;
error_page 500 501 502 503 504 /errorpages/5xx.html;
# Don't log garbage, add some browser caching
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
try_files $uri /app.php?$query_string;
}
location ~* ^.+\.(css|js)$ {
expires modified +1m;
add_header Pragma "private";
add_header Cache-Control "private";
etag on;
try_files $uri /app.php?$query_string;
}
location = /robots.txt {
allow all;
access_log off;
log_not_found off;
}
# Disallow .htaccess, .htpasswd and .git
location ~ /\.(ht|git) {
deny all;
}
# Parse PHP
location ~ ^/(app|app_dev|config)\.php(/|$) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass php;
}
}
blog.domain.com's configuration looks like that:
server {
listen 80;
server_name blog.domain.com;
root /home/webserver-blog/news;
access_log /home/webserver-blog/logs/http_access.log;
error_log /home/webserver-blog/logs/http_error.log;
charset utf-8;
client_max_body_size 65m;
# Some extra speed
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Default URLs
location / {
# This never gets parsed as / is reserved for our main server
}
location ~* ^/news/(wp-content|wp-admin) { # without this directive I didn't have any static files
root /home/webserver-topblog/;
}
location ~* ^/news {
try_files $uri $uri/ /index.php?args;
}
# Don't log garbage
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
location = /robots.txt {
allow all;
access_log off;
log_not_found off;
}
# Disallow .htaccess or .htpasswd
location ~ /\.ht {
deny all;
}
# Disallow logs
location ~ ^/logs/.*\.(log|txt)$ {
deny all;
}
# Parse PHP
location ~ \.php$ {
#if (!-e $request_filename) { rewrite / /index.php last; }
try_files $uri =404;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php;
}
}
As you can figure out, my Wordpress resides in /home/webserver-blog/news/. I have a slightly modified index.php file in Wordpress that checks for X-Custom-Secret header, and if it's not present (or invalid), it forces a 301 redirection to domain.com/news/
Now I have tried several different approaches to get it running properly.
First (and most obvious) was pointing the root of blog.domain.com's to /home/webserver-blog/ and allowing nginx to naturally pass the request URI to the subdirectory, /news. This worked quite well, yet it didn't allow me to utilize Wordpress' permalinks and just worked with query strings. Other strange behaviour it produced was actually exposing blog.domain.com in HTTP redirect if you called /news without trailing slash. Those redirects were quickly handled by my custom index.php, but still I want to avoid exposing blog.domain.com completely.
Second (and pretty-much current) approach was again pointing the root of blog.domain.com's directly to Wordpress' directory, /home/webserver-blog/news/ and cheating all the requests for static files with location ~* ^/news/(wp-content|wp-admin) directive pointing it's root directory one levelel up. This worked for both permalinks and static files, but again - /news/wp-login.php gives me infinite redirects to itself, and /news/wp-admin/ actually downloads the index.php file instead of parsing it (sends it as application/octet-stream)
I am completely out of ideas... Any help would be much appreciated.
I think I managed to come with a so-so solution. Far from being perfect or clean, but... well, it works.
blog.domain.com's config:
server {
listen 80;
server_name blog.domain.com;
root /home/webserver-blog;
access_log /home/webserver-blog/logs/http_access.log;
error_log /home/webserver-blog/logs/http_error.log;
charset utf-8;
client_max_body_size 65m;
# Some extra speed
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Default URLs
location ~* ^/news$ {
rewrite ^ $scheme://domain.com/news/ permanent; # ** HARDCODED production url
break;
}
location / {
try_files $uri $uri/ #redir;
}
location #redir {
rewrite ^/news/(.*)$ /news/index.php?$1 last;
}
# Don't log garbage
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
location = /robots.txt {
allow all;
access_log off;
log_not_found off;
}
# Disallow .htaccess or .htpasswd
location ~ /\.ht {
deny all;
}
# Disallow logs
location ~ ^/logs/.*\.(log|txt)$ {
deny all;
}
# Parse PHP
location ~ \.php$ {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass php;
}
}
So the trick is I'm still operating on filesystem directories and not fancy all-the-way-around rewrites and redirects. news/ still remains a physical directory in the filesystem that gets read with the location / directive from nginx. Previous issues with exposing the blog.domain.com domain on trying to access without slashes seem to be native nginx's behaviour - it sees a directory, it adds a slash at the end; and since it's server_name is set to blog.domain.com, here we go. Hardcoding production URL and putting that rule on top pretty much fixed the problem.
#redir location again enabled the Wordpress' permalinks nicely.
One more thing I have added to entire setup to prevent people form going directly on http://blog.domain.com/ is another index.php file stored directly in /home/webserver-blog/:
<?php
/*
* domain.com redirector
*/
$production = 'http://domain.com/news/';
// Redirect nicely
if(isset($_SERVER['REQUEST_URI']) and $_SERVER['REQUEST_URI'] !== '/') {
$target = sprintf('%s%s', $production, preg_replace('/^\//', null, $_SERVER['REQUEST_URI']));
header('Location: ' . $target);
}
else header('Location: ' . $production);
...and, as mentioned before, few lines on top of Wordpress' original index.php:
<?php
/*
* wordpress loader
*/
$production = 'http://domain.com/news/';
// Allow only reverse-proxied requests
if(!isset($_SERVER['HTTP_X_CUSTOM_SECRET']) or $_SERVER['HTTP_X_CUSTOM_SECRET'] !== md5('your-md5encoded-text-in-proxy_set_header-X-Custom-Secret')) {
die(header('Location: ' . $production));
}
require_once dirname(__FILE__) . '/index-wp-org.php';
Ugly... but works.
I'd still be happy to hear nicer solutons. :)

Resources