Nginx Remove WWW And Respond To Both - nginx

I have the following nginx configuration fragment:
server {
listen 80;
server_name mydomain.io;
root /srv/www/domains/mydomain.io;
index index.html index.php;
access_log /var/log/nginx/domains/mydomain.io/access.log;
error_log /var/log/nginx/domains/mydomain.io/error.log;
location ~\.php {
try_files $uri =404;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
fastcgi_pass 127.0.0.1:9000;
include /etc/nginx/fastcgi_params;
}
}
First, how can I make the server block respond to both http://www.mydomain.io and also http://mydomain.io. Second, I want to force if they come from http://www.mydomain.io to redirect to http://mydomain.io.
Thanks.

According to https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#server-name-if, you should use:
server {
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}
server {
server_name example.com;
# [...]
}

I believe it's better to add two seperate server blocks to avoid unnecessary checking by the if block. I also use the $scheme variable so that HTTPS requests will not be redirected to their insecure counterparts.
server {
listen 80;
server_name www.mydomain.io;
rewrite ^ $scheme://mydomain.io$uri permanent;
}
server {
listen 80;
server_name mydomain.io;
# your normal server block definitions here
}

For a generic approach, without having to mention any specific domain or protocol, I have used this quite successfully:
# rewrite to remove www.
if ( $host ~ ^www\.(.+)$ ) {
set $without_www $1;
rewrite ^ $scheme://$without_www$uri permanent;
}
This will redirect: https://www.api.example.com/person/123?q=45
to https://api.example.com/person/123?q=45

Another way to code it :
if ($http_host ~* "^www\.(.+)$"){
rewrite ^(.*)$ http://%1$request_uri redirect;
}
It works even with multiple domain names on the same code.

server {
listen 80;
server_name www.mydomain.io;
return 301 https://$host$request_uri;
}
server {
listen 80;
server_name mydomain.io;
...
}

On the first question - simply add both domains:
server_name mydomain.io www.mydomain.io;
For the second, you'll need this simple redirect:
server {
listen 80;
server_name www.mydomain.io mydomain.io;
if ($host = 'www.mydomain.io' ) {
rewrite ^/(.*)$ http://mydomain.io/$1 permanent;
}

Related

nginx subdomain with different site than root

I have the following configuration in my sites-available (with a symbolic link to enable):
#subdomain site
server {
listen 443 ssl http2;
server_name dokuwiki.[censored].org;
root /var/www/html/dokuwiki;
index index.php index.html;
include /etc/nginx/templates/ssl.tmpl;
location / {
try_files $uri $uri/ #dokuwiki;
}
location #dokuwiki {
rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
rewrite ^/(.*) /doku.php?id=$1&$args last;
}
location ~ \.php$ {
# Caution: be sure the php7.2-fpm.sock matches your version
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /(data|conf|bin|inc|vendor)/ {
deny all;
}
}
I want to have a different site at the site root:
#root site
server {
listen 80;
server_name [censored].org;
root /var/www/html/site;
index index.html;
}
The root site is just a dummy for now. When I try to load it, the browser tries to load the subdomain site, but issues a warning because the ssl certificate (which is set up for the subdomain) doesn't match.
Clearly I'm doing something wrong, but what?
Try scaling back to a minimal configuration without SSL and ensure things work for 2 domains first:
server {
listen 80;
server_name example.com;
return 200 "example.com";
}
server {
listen 80;
server_name 1.example.com;
return 200 "1.example.com";
}
$ curl http://example.com/
example.com
$ curl http://1.example.com/
1.example.com
Then, add SSL to an HTTPs endpoint to ensure that works:
server {
listen 443 ssl http2;
ssl_certificate example.com.crt;
ssl_certificate_key example.com.key;
server_name example.com;
return 200 "example.com";
}
$ curl https://example.com/
example.com

Minimizing and optimizing NGINX vhost config

Is it possible to optimize/minimize the config posted below?
I feel that it should be possible to merge all the redirects into something more simple.
http:// & http://www & https://www > https://
Though I've had issues and settled.
I understand variables are not supported in NGINX config, so I have to manually define the log locations for example. Would there be a way to set a default location for all vhosts?
I use the same ssl-params.conf file for all vhosts. Can this be defaulted and disabled on a per-vhost basis?
# Redirect http:// & http://www to https://
server {
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# Redirect https://www to https://
server {
listen 443 ssl;
server_name www.example.com;
return 301 https://example.com/$request_uri;
}
# Main config
server {
listen 443 ssl;
server_name example.com;
# SSL config
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
# Error logs
access_log /srv/logs/nginx.access.example.com.log;
error_log srv/logs/nginx.error.example.com.log;
# Root dir
location / {
root /srv/example.com/_site/;
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
}
# Caching
location ~ .php$ {
root /srv/example.com/_site/;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
root /srv/example.com/_site/;
expires 365d;
}
location ~* \.(pdf)$ {
root /srv/example.com/_site/;
expires 30d;
}
# SSL
location /.well-known {
allow all;
}
}
I understand variables are not supported in NGINX config, so I have to manually define the log locations for example. Would there be a way to set a default location for all vhosts?
Yes, just define it in the http context of your config or stick with the default of your distro (e.g. /var/log/nginx/access.log).
I use the same ssl-params.conf file for all vhosts. Can this be defaulted and disabled on a per-vhost basis?
It works the other way around you enable it where you need it through the include directive.
Here is a shorter config (untested):
http {
error_log /srv/logs/nginx.error.example.com.log;
access_log /srv/logs/nginx.access.example.com.log;
index index.php index.html index.htm;
server {
listen 80;
listen 443 ssl;
server_name .example.com;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
root /srv/example.com/_site/;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
location / {
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
}
location ~* \.(jpe?g|png|gif|ico|css|js)$ {
expires 365d;
}
location ~* \.(pdf)$ {
expires 30d;
}
try_files $uri $uri/ /index.php?$args;
}
location /.well-known {
allow all;
}
}
}

Convert /#<handle> to /users/profile/<handle> with nginx

I'm looking for an nginx rule that would do this:
input url: http://domain.com/#johndoe
what our backend sees: http://domain.com/users/profile/johndoe
Example: http://medium.com/#stuartkhall
The current rule I'm using (removed things that don't have to do with this question):
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name _;
root /var/html;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass mainphp;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
What kind of rule I can add to my current nginx config? I experimented with a rewrite but wasn't able to get it to work.
Better practice is location + return instead of rewrite, so try this (place before any location):
location ~ ^/#(.*)$ {
return 301 /users/profile/$1;
}
or identical rewrite in case you prefer it
rewrite ^/#(.*)$ /users/profile/$1 last;

NGINX Rewrite single HTTPS URL to HTTP

On my NGINX server, I have all non-SSL traffic redirected to my SSL site.
Now, I want to have a single URL excluded from this, specifically:
https://pyronexus.com/forum/pages.php and everything appended to pages.php, such as pages.php?page=blahblah redirected to http://pyronexus.com/forum/pages.php, etc.
My config file looks like this so far, but I've not had any luck in getting my rewrite for this single url to work.
server {
server_name
www.pyronexus.com
;
listen 80 default;
listen 443 ssl;
ssl_certificate ssl/pyronexus.com.crt;
ssl_certificate_key ssl/pyronexus.com.key;
return 301 https://pyronexus.com$request_uri;
}
server {
server_name
pyronexus.com
;
listen 80;
listen 443 default ssl;
ssl_certificate ssl/pyronexus.com.crt;
ssl_certificate_key ssl/pyronexus.com.key;
root /home/nginx/pyronexus.com/public;
index index.html index.php;
access_log /home/nginx/pyronexus.com/logs/access.log;
error_log /home/nginx/pyronexus.com/logs/error.log;
include php.conf;
include mime.types;
location /forum/ {
#include pyronexus-naxsi.rules;
rewrite ^/forum/forum-([0-9]+)\.html$ /forum/forumdisplay.php?fid=$1;
rewrite ^/forum/forum-([0-9]+)-page-([0-9]+)\.html$ /forum/forumdisplay.php?fid=$1&page=$2;
rewrite ^/forum/thread-([0-9]+)\.html$ /forum/showthread.php?tid=$1;
rewrite ^/forum/thread-([0-9]+)-page-([0-9]+)\.html$ /forum/showthread.php?tid=$1&page=$2;
rewrite ^/forum/thread-([0-9]+)-lastpost\.html$ /forum/showthread.php?tid=$1&action=lastpost;
rewrite ^/forum/thread-([0-9]+)-nextnewest\.html$ /forum/showthread.php?tid=$1&action=nextnewest;
rewrite ^/forum/thread-([0-9]+)-nextoldest\.html$ /forum/showthread.php?tid=$1&action=nextoldest;
rewrite ^/forum/thread-([0-9]+)-newpost\.html$ /forum/showthread.php?tid=$1&action=newpost;
rewrite ^/forum/thread-([0-9]+)-post-([0-9]+)\.html$ /forum/showthread.php?tid=$1&pid=$2;
rewrite ^/forum/post-([0-9]+)\.html$ /forum/showthread.php?pid=$1;
rewrite ^/forum/announcement-([0-9]+)\.html$ /forum/announcements.php?aid=$1;
rewrite ^/forum/user-([0-9]+)\.html$ /forum/member.php?action=profile&uid=$1;
rewrite ^/forum/calendar-([0-9]+)\.html$ /forum/calendar.php?calendar=$1;
rewrite ^/forum/calendar-([0-9]+)-year-([0-9]+)\.html$ /forum/calendar.php?action=yearview&calendar=$1&year=$2;
rewrite ^/forum/calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)\.html$ /forum/calendar.php?calendar=$1&year=$2&month=$3;
rewrite ^/forum/calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)-day-([0-9]+)\.html$ /forum/calendar.php?action=dayview&calendar=$1&year=$2&month=$3&day=$4;
rewrite ^/forum/calendar-([0-9]+)-week-(n?[0-9]+)\.html$ /forum/calendar.php?action=weekview&calendar=$1&week=$2;
rewrite ^/forum/event-([0-9]+)\.html$ /forum/calendar.php?action=event&eid=$1;
rewrite ^/forum/archive/index\.php/forum-([0-9]+)\.html$ /forum/archive/index.php?forum-$1.html;
rewrite ^/forum/archive/index\.php/thread-([0-9]+)\.html$ /forum/archive/index.php?thread-$1.html;
}
location ~ /forum/(inc) {
deny all;
}
}
The rewrite rule I have tried is this, but I'm still getting to grips on how these rules work:
rewrite ^https://pyronexus.com/forum/pages\.php(.*)$ http://pyronexus.com/forum/pages.php$1;
Open up the configuration for your site, mine is /etc/nginx/sites-enabled/pyronexus.com.
Add the following server directive, adjusting the variables as needed:
server {
server_name
www.your-site.com
;
listen 80;
listen 443 ssl;
ssl_certificate ssl/your-certificate.crt;
ssl_certificate_key ssl/your-certificate.key;
return 301 https://your-site.com$request_uri;
}
This directive will force any www connections, be it through SSL or non-SSL, to non-www.
Add another directive. Although in this directive you can add any exclusions of pages you don’t want to be SSL-enabled. Add them before the location ~ / {} directive (I’ve included an example in there, which excludes http://your-site.com/forum/pages.php from HTTPS connections):
server {
server_name
your-site.com
;
listen 80 default;
root /your/site/root;
access_log /your/logs/location/access.log;
error_log /your/logs/location/error.log;
include global.conf;
# This excludes forum/pages.php from being forced through HTTPS
location ~ ^/forum/pages\.php$ {
include php.conf;
}
# This will force any http:// connections through https://
location ~ / {
return 301 https://your-site.com$request_uri;
}
}
Add a third, and final directive. This one is the directive that handles all SSL connections. You’ll need to put any exclusions you put above in here as well, and redirect people to a http connection:
server {
server_name
your-site.com
;
listen 443 default ssl;
ssl_certificate ssl/your-site.crt;
ssl_certificate_key ssl/your-site.key;
root /your/site/root;
access_log /your/logs/location/access.log;
error_log /your/logs/location/error.log;
include global.conf;
# This will force forum/pages.php through http://
location ~ ^/forum/pages\.php$ {
return 301 http://your-site.com$request_uri;
}
include php.conf;
}
That’s it! Test your configuration out!
If you’re wondering what’s in my global.conf and php.conf, then here they are:
global.conf:
# Tries to access the file directly before handing over to index.php
location / {
try_files $uri $uri/ /index.php?$args;
}
# Exclude common static file formats from logging and cache as long as possible
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|txt)$ {
access_log off;
log_not_found off;
expires max;
}
# Deny access to files that start with a dot, such as .htaccess
location ~ /\. {
deny all;
}
# Deny access to php files in folders named uploads and files (this is to prevent people uploading php files and executing them)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
php.conf:
# Pass all php files to php5-fpm
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
}
Source: https://pyronexus.com/blog/2015/01/11/nginx-remove-www-and-force-ssl-connections/

nginx server configuration: subdomain to folder

I migrated from Apache 2 to nginx and I've got problems to handly my subdomain control.
What I want: When x.domain.tld is requested, internally rewrite to domain.tld/x
The problem I've got is that nginx always redirects the page by telling the browser to redirect to. But what I really want is to do this internally, like Apache 2 did.
Also, if I only request x.domain.tld, nginx returns a 404. It only works when I do x.domain.tld/index.php
Here's my config:
server {
listen 80 default;
server_name _ domain.tld www.domain.tld ~^(?<sub>.+)\.domain\.tld$;
root /home/domain/docs/;
if ($sub) {
rewrite (.*) /$sub;
}
# HIDDEN FILES AND FOLDERS
rewrite ^(.*)\/\.(.*)$ #404 break;
location = #404 {
return 404;
}
# PHP
location ~ ^(.*)\.php$ {
if (!-f $request_filename) {
return 404;
}
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/etc/nginx/sockets/domain.socket;
}
}
Thanks!
As I found this Q&A on Google while looking for a solution for the same problem, I wanted to post the solution I finally used.
The first server block by MTeck looks pretty nice, but for the subdomains part you could simply do the following:
server {
listen 80;
server_name "~^(?<sub>.+)\.domain\.tld$";
root /path/to/document/root/$sub;
location / { try_files $uri $uri/ /index.php; }
location ~ \.php {
include fastcgi_params;
fastcgi_pass unix:/etc/nginx/sockets/domain.socket;
}
}
This makes the root configuration directive dependent on the subdomain.
I spent hours beating my head against the wall and this is what works for me
server {
listen 80;
server_name ~^(?P<sub>.+)\.example\.com$; #<-- Note P before sub, it was critical for my nginx
root /var/www/$sub; #<-- most important line cause it defines $document_root for SCRIPT_FILENAME
location / {
index index.php index.html; #<-- try_files didn't work as well
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; #<-- probably you have another option here e.g. fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
}
}
You should take a look at http://wiki.nginx.org/IfIsEvil. You're doing a whole lot wrong in this configuration file.
server {
server_name domain.tld www.domain.tld;
location / {
try_files $uri /index.php;
}
location ~ \.php {
include fastcgi_params;
fastcgi_pass unix:/etc/nginx/sockets/domain.socket;
}
}
server {
server_name "~^(?<sub>.+)*\.(?<domain>.*)$";
return 301 $scheme://$domain/$sub$request_uri;
}
If what you want is to keep that internal, you won't be able to rewrite it. By definition, a cross site rewrite needs to be sent back to the browser. You'll have to proxy the request.
server {
server_name "~^(?<sub>.+)*\.(?<domain>.*)$";
proxy_pass http://$domain/$sub$request_uri;
}
You should read the Nginx wiki. All of this is explained in depth.
This will work for www also.
server {
listen 80 default_server;
listen [::]:80 default_server;
index index.php index.html index.htm index.nginx-debian.html;
server_name ~^www\.(?P<sub>.+)\.domain\.com$ ~^(?P<sub>.+)\.domain\.com$;
root /var/www/html/$sub;
location / {
try_files $uri $uri/ /index.php?$args;
}
}

Resources