For Nginx, I'm attempting to do two things:
Redirect anyone who comes in to the site from www to non-www.
The server defaults to error 500 instead of 404 when the URL path doesn't exist.
This is my current configuration of my server:
server {
root /var/www/project/;
index index.php index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed$
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # manag$
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name example.com www.example.com;
return 404; # managed by Certbot
}
I attempted adding a forward for any www traffic to move into non-www but that didn't do anything (I think because of certbot). Also I tried to update the URL for returning 404 instead of 500, but what it did was it made anything outside of the homepage a 404. So I reset it to what you see above.
Redirect anyone who comes in to the site from www to non-www.
The cleanest solution is to define a separate server block only for this purpose:
server {
listen 80;
server_name www.example.com;
return 301 http://example.com$request_uri;
}
You can verify that it works by putting
127.0.0.1 localhost example.com www.example.com
in your computer's hosts file.
$ curl -I http://www.example.com
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Fri, 27 Aug 2021 06:14:43 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Location: http://example.com/
The server defaults to error 500 instead of 404 when the URL path doesn't exist.
The 500 HTTP status code is probably caused by your index.php script.
Related
I'm trying to configure NGINX on CentOS 8 (with SSL). I believe I have configured it properly, but I can't get rid of the NGINX welcome page. I've tried a lot of things, even deleted the entire /usr/share/nginx/html directory, but I still get NGINX welcome on example.com, whereas example.com/index.html gives me the index page of my website. In fact I have noticed that the http to https and non-www to www redirections I have implemented below don't work on example.com, but do work on example.com/index.html. The root of my website is /var/www/example.com/html. The configure file which is given below is called example.com.conf and located at /etc/nginx/conf.d/.
server {
root /var/www/example.com/html;
index index.html index.htm;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
listen [::]:443 ssl ipv6only=on default_server; # managed by Certbot
listen 443 ssl default_server; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
# Redirect non-SSL to SSL
server {
listen 80;
listen [::]:80;
server_name .example.com;
return 301 https://$host$request_uri;
}
# Redirect non-www to www
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
So it appears that you need to edit the global configuration file using sudo nano /etc/nginx/nginx.conf and comment out "default_server" in the listen statements. Alternatively deleting the whole server block in the global conf file also works, as long as you keep the include statement which reads the example.com.conf file.
include /etc/nginx/conf.d/*.conf;
server {
listen 80; # default_server;
listen [::]:80; # default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
I was trying to set up a wordpress web server using nginx on my own laptop. The certificate was installed successfully and I can visit my site through https. However, I found out that the redirecting from http to https is not working. My site always showed 400 Bad Request when I tried to visit through http. Lots of answers on Google say that this can be fixed by commenting out "ssl on" but actually I don't have this line in my code.
server {
root /var/www/html;
index index.php index.html index.htm;
server_name mydomain.com;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
server_name mydomain.com;
return 404; # managed by Certbot
}
I found out the problem was coming from my NAT setting. The external 80 and 443 connections were forwarded to my internal server's port 443 under 1 NAT rule. After separating 80 and 443 to different rules and everything works!
I have nginx running on my home server at keepsecret.ddns.net. When I request e.g. keepsecret.ddns.net/foo/ it returns to me keepsecret.ddns.net/foo/index.html. So far, so good.
Now I am trying to treat my home server as an upstream server. In front of that upstream server is a remote proxy server at www.mydomain.com. When I request e.g. www.mydomain.com/foo/index.html, it is returned to me no problem. However, when I request www.mydomain.com/foo/, nginx first issues a 301 redirect so that I then get sent to keepsecret.ddns.net/foo/, revealing my home IP Address :(
I have no idea why nginx behaves this way. My only guess is that it has something to do with the fact that the domain in the request host header does not match the domain in the request url.
Questions in summary:
Why does nginx do this?
How can I prevent nginx performing this redirect so that I always remain on www.mydomain.com?
Here is the salient part of my config for reference:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
}
}
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name keepsecret.ddns.net www.mydomain.com;
location / {
try_files $uri $uri/ =404;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/keepsecret.ddns.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/keepsecret.ddns.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = keepsecret.ddns.net) {
return 301 https://$host$request_uri;
}
if ($host = www.mydomain.com) {
return 301 https://$host$request_uri;
}
listen 80 ;
listen [::]:80 ;
server_name keepsecret.ddns.net www.mydomain.com;
return 404; # managed by Certbot
}
NGINX will be doing an internal redirect to the index.html file in all cases, but it seems to get externalised when the server_name does not match the primary server_name. I suspect that changing the server_name order so that your public (proxied) name is first may get rid of that behaviour.
The alternative would be to focus on the reverse proxy, and take a look at proxy_redirect to make the reverse-proxy rewrite location headers for you.
See: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
Update: culprit identified:
On the 4th to last line, ssl should be removed. Not sure why. If anybody can explain why, please add your answer. Thank you!
Target system info:
I'm on Debian 10, Buster, using nginx 1.42, certbot latest-stable, and php 7.3.
There are two domain names served on the same ip address and ports; so, example.com and example1.com (example.com.conf is seen below).
Everything is raw, out-of-the-box: nginx.conf is unaltered, php's config files are unaltered. Other than LEMP and Certbot, nothing has been installed.
Unwanted behavior:
Chrome: redirects http://example.com to https://example.com (good); and http://www.example.com and https://www.example.com return "ERR_EMPTY_RESPONSE".
Pale Moon (like Firefox): redirects http://www, https://www, and http:// correctly to https://example.com; all done correctly (USUALLY).
Edge: correctly redirects https://www.example.com; everything else returns Hmmm...can’t reach this page.
Curl (most important):
WolfPack'08#NV89501:/# curl www.example.com
curl: (52) Empty reply from server
WolfPack'08#NV89501:/# curl http://example.com
curl: (52) Empty reply from server
WolfPack'08#NV89501:/# curl http://www.example.com
curl: (52) Empty reply from server
WolfPack'08#NV89501:/# curl https://www.example.com
WolfPack'08#NV89501:/# curl https://example.com
<!DOCTYPE html>
Best attempt, site-specific config: see comment (###):
server {
set $base /var/www/example.com;
root $base/public;
access_log /var/log/nginx/example.com/access.log;
error_log /var/log/nginx/example.com/error.log;
index index.php;
server_name www.example.com example.com;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
}
listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name www.example.com example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
### SECTION INTENDED TO HANDLE WWW-to-NON_WWW REDIRECTS: ###
server {
if ($host = www.example.com) {
return 301 https://$host$request_uri;
}
if ($host = example.com) {
return 301 https://$host$request_uri;
}
listen [::]:80;
listen 80 ssl; ### REMOVE SSL HERE TO FIX. ###
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
Other stuff I've tried:
Putting the 301 in other places (such as at the top, under index index.php;).
Using 302's rather than 301's.
Removing listen 80 ssl;.
Using return 301 https://$host$request_uri; rather than example.com.
Deleting all of the other symlinks from sites-enabled.
Of course, I restart nginx each time, and I'm getting no errors.
try the below configurations, it basically redirects HTTP traffic to HTTPS for the defined domains and handles https only for www.example.com example.com;
server {
listen 80 default_server;
server_name _;
return 301 https://example.com$request_uri;
}
server {
listen 80;
server_name www.example.com
return 301 https://$host$request_uri;
}
server {
listen 80;
server_name example.com
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2 default_server;
server_name www.example.com example.com;
set $base /var/www/example.com;
root $base/public;
access_log /var/log/nginx/example.com/access.log;
error_log /var/log/nginx/example.com/error.log;
index index.php;
server_name www.example.com example.com;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
}
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
you must reload Nginx configs after adding the above configs and test in a private window in chrome and firefox (better to test with this curl command curl --head http://zzz)
Following this answer, I have my nginx server set up like so:
server {
server_name portal.productive.city www.portal.productive.city;
root /www/Productive-Website/my-app/build;
index index.html index.htm;
rewrite ^/(.*)/$ $1 permanent;
location / {
try_files $uri?$args $uri/ $uri.html?$args /index.html?$args;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/portal.productive.city/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/portal.productive.city/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
My other server (in the same file) (created by lets-encrypt) is:
server {
if ($host = www.portal.productive.city) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = portal.productive.city) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name portal.productive.city www.portal.productive.city;
return 404; # managed by Certbot
}
When I try to go to: www.portal.productive.city or www.portal.productive.city/signin I get a 500 Internal Server Error
My error-log file looks like:
2018/08/31 14:43:08 [error] 29581#29581: *25 rewrite or internal
redirection cycle while internally redirecting to "/index.html",
client: 74.105.149.67, server: portal.productive.city, request: "GET /
HTTP/1.1", host: "www.portal.productive.city"
2018/08/31 14:43:08 [error] 29581#29581: *26 rewrite or internal redirection cycle while
internally redirecting to "/index.html", client: 74.105.149.67,
server: portal.productive.city, request: "GET /favicon.ico HTTP/1.1",
host: "www.portal.productive.city", referrer:
"https://www.portal.productive.city/"
The favicon.ico exists under path/to/repo/build
Edit: I cleared cache and restructured the server as follows:
server {
server_name portal.productive.city www.portal.productive.city;
root /www/Productive-Website/my-app/build;
index index.html index.htm;
location / {
try_files $uri?$args $uri/ $uri.html?$args /index.html?$args;
}
listen 80;
if ($scheme != "https") {
return 301 https://$host$request_uri?$args;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/portal.productive.city/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/portal.productive.city/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
The error-file is now:
2018/08/31 15:17:54 [error] 29789#29789: *17 rewrite or internal
redirection cycle while internally redirecting to "/index.html",
client: 74.105.149.67, server: portal.productive.city, request: "GET
/? HTTP/1.1", host: "www.portal.productive.city"
2018/08/31 15:17:54
[error] 29789#29789: *18 rewrite or internal redirection cycle while
internally redirecting to "/index.html", client: 74.105.149.67,
server: portal.productive.city, request: "GET /favicon.ico HTTP/1.1",
host: "www.portal.productive.city", referrer:
"https://www.portal.productive.city/?"
You shouldn't have 2 server files with the same server_name, this makes your configuration harder to find. And, if by chance you configure both of them to listen to the same ports, it will confuse NGINX on which one to render. First, move them into the same one and redirect based on $scheme instead of $host. But that is not the real issue. You've got an redirect that is looping because it matches every request ending with '/'
server {
server_name portal.productive.city www.portal.productive.city;
root /www/Productive-Website/my-app/build;
index index.html index.htm;
# rewrite ^/(.*)/$ $1 permanent; Your REAL problem is here. You've got an redirect that is looping because it matches every request ending with '/'
location / {
try_files $uri?$args $uri/ $uri.html?$args /index.html?$args;
}
listen 80;
if ($scheme != "https") {
return 301 https://$host$request_uri?$args
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/portal.productive.city/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/portal.productive.city/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
The https redirect like this means: "If the $scheme is not 'https', redirect to https://$host$request_uri?$args". Which translates to: "https:// address on the same host, on the same path and whith the same URL arguments used on the access".