Nginx to serve secure and non secure traffic - nginx

We have secure and non-secure domains for our website e.g. secure.xyz.com and xyz.com
I used following link to make single server handle both port 80 and 443 traffic.
http://nginx.org/en/docs/http/configuring_https_servers.html#single_http_https_server
server {
listen 80;
listen 443 ssl;
server_name secure.xyz.com xyz.com;
....
ssl_certificate secure.xyz.com.crt;
ssl_certificate_key secure.xyz.com.key;
...
}
Every thing works fine except that $_SERVER's variable 'SERVER_NAME' is set to 'secure.xyz.com'. So that this hostname appears on non-secure page with 'http', e.g., 'http://secure.xyz.com'.
My queries are:
Does Nginx always pick the first server from the config ... irrespective of what client has requested? (and passes to proxy (php-fpm)?).
We have a lot of rules, so if we create two separate server (as per following), do I need to copy the rules in both places? Is there any maintainable way, like 'include /common_rules.conf'? I tried using 'location' rules (only) in the file, also I tried using 'server' encapsulating location rules however it does not work.
server {
listen 443;
server_name secure.xyz.com;
ssl on;
ssl_certificate secure.xyz.com.crt;
...
include common_rules.conf; ===>???
}
server {
listen 80;
server_name xyz.com;
...
include common_rules.conf; ===>???
}
Any help is highly appreciated.

Related

How to mutualize listen parameters for the same address:port pair in nginx?

I’m trying to deploy different websites on the same server that all listen on 0.0.0.0:443 with HTTP/2. My Ansible template looks like this:
# This is deployed in /etc/nginx/sites-available/{{ domain }}.conf and symlinked in sites-enabled
server {
listen 443 ssl http2 reuseport;
listen [::]:443 ssl http2 reuseport;
server_name {{ domain }};
...
}
This doesn’t work because according to the nginx doc (emphasis mine):
The listen directive can have several additional parameters specific to socket-related system calls. These parameters can be specified in any listen directive, but only once for a given address:port pair.
If I were deploying these websites by hand I would use listen 443 ssl http2 reuseport; in the first one and then listen 443; in the subsequent ones. But I’m trying to simplify the setup by having a single Ansible template that I can use for any website.
It looks cumbersome to check if there’s already a deployed website with these options and don’t include them if that’s the case. Also, if I remove the website with these options, it breaks all the others.
Is there any way I could add a unique file somewhere under /etc/nginx that says "use these parameters on 0.0.0.0:443" for all listen directives? I could probably add a dummy server{} block somewhere than listens for a unexisting server name but I wonder if there’s a proper way to do that.
This is the solution I have for now:
# /etc/nginx/sites-enabled/http2 -> /etc/nginx/sites-available/http2
server {
listen 443 ssl http2 reuseport;
listen [::]:443 ssl http2 reuseport;
server_name --;
}
-- is a dummy server name that doesn’t match anything. This block serves only as a common place for the listen parameters.
Now I just deploy websites with listen 443; and no other parameter, and they all share that common config.

nginx on localhost - wildcard domains and wildcard subdomains

I configured nginx (and dnsmasq) to listen to example.test and *.example.test wildcard subdomain. Everything seems to work fine. Here is nginx.conf:
server {
listen 80;
server_name ~(\.)?example\.test$;
...
}
Now I want to respond to all other *.test domains from their own directory on disk. I just don't know how to make it happen, following config doesn't work (just disables above configuration):
server {
listen 80;
server_name \.test;
...
}
Even following configuration has same effect:
server {
listen 80;
server_name ~(?!(\.)?example)\.test;
...
}
Both these configs work, but disables *.example.test and example.test configuration and responds to them just as other *.test domains.
Here is my question:
How can I configure nginx to respond to *.test but respond to example.test and *.example.test in a different way?
After a wasting a whole day, I finally managed to fix the issue.
For those who may find themselves in such a confusing situation, here is the solution:
# First server block for default configuration:
server {
listen 80;
server_name ~^[a-zA-Z0-9\-_]+\.test$; # matches domain names (e.g. anything.test)
...
}
server {
listen 80;
server_name ~(\.)?example\.test$ example.test; # matches all subdomains (e.g. subdomain.example.test and sub.subdomain.example.test) as well as example.test
...
}

parametrize the server name in nginx conf

I have multiple domains all pointing to the same VM. (mydomain1.com, mydomain2.com, mydomain3.eu)
Now I have a huge nginx.conf which looks like this:
server {
listen 443 ssl;
server_name *.mydomain1.com;
ssl on;
ssl_certificate /etc/nginx/ssl/mydomain1.com.chained.crt;
ssl_certificate_key /etc/nginx/ssl/mydomain1.com.key;
# hundred more lines of rules
}
server {
listen 443 ssl;
server_name *.mydomain2.com;
ssl on;
ssl_certificate /etc/nginx/ssl/mydomain2.com.chained.crt;
ssl_certificate_key /etc/nginx/ssl/mydomain2.com.key;
# the same hundred more lines of rules
}
server {
listen 443 ssl;
server_name *.mydomain3.eu;
ssl on;
ssl_certificate /etc/nginx/ssl/mydomain3.eu.chained.crt;
ssl_certificate_key /etc/nginx/ssl/mydomain3.eu.key;
# the same hundred more lines of rules
}
Is there a way to shorten this - because currently I'm cloning such a huge code blcok when I have to add a new domain and only change the 3 lines where my domain name differs. I thought about some kind of parametrization, like (without knowing the correct syntax):
SERVER_NAME = {request_server_name}
ssl_certificate /etc/nginx/ssl/${SERVER_NAME}.chained.crt;
ssl_certificate_key /etc/nginx/ssl/${SERVER_NAME}.key;
is this possible? How?
There are two things you can do about it
Multi Domain SAN Certificate
You can purchase a multi domain SAN certificate. Which allows your to use different domains in the same certificate. So this way you wont have to have multiple blocks. In case you are using a self-signed certificate you can still create SAN certificate yourself
Use OpenRestry or Nginx+LUA
You can use OpenResty or Nginx with LUA support and use the ssl_certificate_by_lua_block directive of he same.
syntax: ssl_certificate_by_lua_block { lua-script }
context: server
phase: right-before-SSL-handshake
This directive runs user Lua code when NGINX is about to start the SSL handshake for the downstream SSL (https) connections.
It is particularly useful for setting the SSL certificate chain and the corresponding private key on a per-request basis. It is also useful to load such handshake configurations nonblockingly from the remote (for example, with the cosocket API). And one can also do per-request OCSP stapling handling in pure Lua here as well.
https://github.com/openresty/lua-nginx-module#ssl_certificate_by_lua_block
Also see below articles for some example implementations
https://medium.com/#mtourne/how-to-use-nginx-for-ssl-termination-for-any-domain-dc2e2c630058
https://blog.readme.io/auto-generating-ssl-certificates-for-custom-domains-using-lets-encrypt/

Running nginx on multiple ports with same rules

I'm running nginx on two ports, one for HTTPS and the other for HTTP, but identical in all other ways (i.e. location directives, etc.). I'd like to avoid writing the same rules twice.
Is there a way in nginx config files to write my rules in some sort of block and then include them inside my server directives?
yes, you can include extra files into you configuration, see the docs and example below here:
server {
listen 80;
include location_directives.conf
}
server {
ssl on;
listen 443 default spdy ssl;
include location_directives.conf
}
P.S. By the way, it's prefer to use return 301 to redirect from http to https instead of define the rules for both servers blocks
server {
listen 80;
return 301 https://$host$request_uri;
}

nginx server_name wildcard or catch-all

I have an instance of nginx running which serves several websites. The first is a status message on the server's IP address. The second is an admin console on admin.domain.com. These work great. Now I'd like all other domain requests to go to a single index.php - I have loads of domains and subdomains and it's impractical to list them all in an nginx config.
So far I've tried setting server_name to * but that failed as an invalid wildcard. *.* works until I add the other server blocks, then I guess it conflicts with them.
Is there a way to run a catch-all server block in nginx after other sites have been defined?
N.B. I'm not a spammer, these are genuine sites with useful content, they're just powered by the same CMS from a database!
Change listen option to this in your catch-all server block. (Add default_server) this will take all your non-defined connections (on the specified port).
listen 80 default_server;
if you want to push everything to index.php if the file or folder does not exist;
try_files $uri /$uri /index.php;
Per the docs, It can also be set explicitly which server should be default, with the **default_server** parameter in the listen directive
As a convention, the underscore is used as a server name for default servers.
From http://nginx.org/en/docs/http/server_names.html
In catch-all server examples the strange name “_” can be seen:
server {
listen 80 default_server;
server_name _;
return 444;
}
There is nothing special about this name, it is just one of a myriad of >invalid domain names which never intersect with any real name. Other >invalid names like “--” and “!##” may equally be used.
Note that server_name _; alone is not enough. The above example only works because of default_server in the listen directive.
This will work:
server_name ~^(.+)$
Now you can use mask:
server {
listen 80;
server_name *.example.org;
...
}
server {
listen 80;
server_name mail.*;
...
}
Look more here: http://nginx.org/en/docs/http/server_names.html
Only 1 server directive
From Nginx listen Docs
The default_server parameter, if present, will cause the server to
become the default server for the specified address:port pair. If none
of the directives have the default_server parameter then the first
server with the address:port pair will be the default server for this
pair.
If you only have 1 server directive, that will handle all request, you don't need to set anything.
Multiple server directive
If you want to match all request with specified server directive, just add default_server parameter to listen, Nginx will use this server directive as default.
server {
listen 80 default_server;
}
About server_name _;
From Nginx Docs
In catch-all server examples the strange name “_” can be seen:
server {
listen 80 default_server;
server_name _;
return 444;
}
There is nothing special about this name, it is just one of a myriad
of invalid domain names which never intersect with any real name.
Other invalid names like “--” and “!##” may equally be used.
It doesn't matter what server_name you set, it is just an invalid domain name.
For me somehow define default_server was not working. I solved it by
server_name ~^.*$
using regular expression of all.
If you also want to catch requests with empty Host header (which is allowed in HTTP/1.0) you can use both regex and empty server_name:
server {
listen 80;
server_name ~. "";
}
Try $http_host
server {
server_name $http_host;
}

Resources