Using multiple roots directories to access the same project with NGINX - nginx

So I've got this NGINX config
server{
listen 80 default_server;
listen [::]:80 default_server;
server_name cerdman.me;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443;
server_name cerdman.me;
ssl_certificate /etc/letsencrypt/live/cerdman.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cerdman.me/privkey.pem;
root /home/ubuntu/portfolio/resume/; #show users the resume by default
index index.html;
# Other config you desire (TLS, logging, etc)...
location /resume/ {
root /home/ubuntu/portfolio;
index index.html;
}
location /weatherapp/ {
root /home/ubuntu/portfolio;
index index.html;
}
}
What I'm trying to achieve here is to have my resume be served by default if someone goes to https://cerdman.me. I'm having trouble doing this in a way that doesn't interfere with my other project(s).
My second project, at /weatherapp/ was created using create-react-app. As is, my app will try to access resources from several urls, lets take the example https://cerdman.me/static/js/2.70e4302a.chunk.js. When this url request is sent to my server, the server doesn't have a location block for it, so it tries to use the server's root directory. In the end it looks in /home/ubuntu/portfolio/resume/static/js/2.70e4302a.chunk.js instead of /home/ubuntu/portfolio/weatherapp/static/js/2.70e4302a.chunk.js where the files actually are.
What I need to do is somehow to redirect these resource requests being made by the weatherapp project such that I can maintain my current file structure, or to find an alternative structure that circumvents the problem entirely while still being scalable. Maybe putting both projects into one server isn't the right way?

Related

What is '_' in Nginx server name? [duplicate]

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;
}

nginx Redirect specific subdomain and path

Our nginx config serves multiple sites with their own subdomains.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name ~^(?P<sub>.+)\.(example1|example2)\.com$;
root /var/www/instances/$sub;
...
}
I want to redirect one specific subdomain with its path to different sites, but I cannot figure out how to write the check. I need to check for the host part and then check for the path to decide where the redirect should land.
The map looks somehting like this:
Old URI
New URI
sub1.example1.com/wiki/0/$path
newSub1.example1.com/wiki/0/$path
sub1.example1.com/wiki/20/$path
newSub2.example1.com/wiki/0/$path
Where $path is simply the rest of the request URI
All other requests to sub1.example1.com should work as before.
The obvious solution is to split sub1.example1.com into a separate server block. As you will see from this document a server_name with an exact name always takes precedence over a server_name with a regular expression.
This means that there are two server blocks with near identical contents, but this can be mitigated by using the include directive.
Alternatively, you can test the value of $host$request_uri using a map directive. This is less efficient, as you will be testing the URL in every site.
For example:
map $host$request_uri $redirect {
default 0;
~*^sub1.example1.com/wiki/0/(?<path>.*)$ //newSub1.example1.com/wiki/0/$path;
~*^sub1.example1.com/wiki/20/(?<path>.*)$ //newSub2.example1.com/wiki/0/$path;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name ~^(?P<sub>.+)\.(example1|example2)\.com$;
root /var/www/instances/$sub;
if ($redirect) { return 301 $scheme:$redirect; }
...
}

How does nginx know my servers url adress?

I installed nginx using sudo apt-get install nginx.
Now this allows me to go to my_ip:port and it allows me to visit the website.
Yet, i can also do my_url:port and it will also direct me to the website.
How can nginx know my_url when I have not told it my_url anymore?
I was running Apache before, can that explain it?
Nginx was able to load via the fqdn my_url:port even though you haven't added my_url in the nginx config because config default_server (usually there by default) was specified.
default_server parameter specifies which block should serve a request if the server_name requested does not match any of the available server blocks:
For example
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;
}
}
Nginx doesn't need it (at least, not yet). Your web browser looks up my_url in the DNS, and then uses my_ip (from DNS) :port (which you entered in your browser) to connect to Nginx.
Your Nginx is probably only configured with one site, which means any connection to it - regardless of whether it is by IP or by domain name - causes Nginx to serve that site. You can change this by going into your Nginx configuration files and setting (or changing) the value of the server_name parameter, for example:
server { # You already have a server block somewhere in the config file
listen 80; # Or 443, if you've enabled SSL
server_name example.com www.example.com; # Add (or change) this line to the list of addresses you want to answer to

How to configure nginx to redirect to https ... except for one directory

I'm setting up an nginx webserver to support multiple virtual hosts. Following best practice, I want any http:// request to be redirected to the equivalent https://.
That much is straightforward, but I want to have one exception: any request for any file under /.well-known/ should be served as http, without the https redirect. Anyone who's worked with LetsEncrypt will recognize the '.well-known' directory as the place that LetsEncrypt looks for verification files. These must be served over HTTP.
So far, I have a configuration file for 'default' that looks like:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/default/www;
index index.php index.html index.htm;
location ^~ /.well-known/ {
allow all;
}
location / {
return 301 https://$host$request_uri;
}
}
Then, for each virtual host, I have a separate file that looks like:
server {
listen 443 ssl;
server_name myexamplevirtualhost.com;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# lots more SSL-related stuff
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name myexamplevirtualhost.com;
location / {
return 301 https://$server_name$request_uri;
}
location /.well-known/ { }
}
If I request, for example, http://myexamplevirtualhost.com/, I get redirected to https://myexamplevirtualhost.com/ -- which is what I want. Similarly, a direct request for https://myexamplevirtualhost.com/ works as intended.
However, if I try: http://myexamplevirtualhost.com/.well-known/foo123, instead of the server simply serving up http://myexamplevirtualhost.com/.well-known/foo123 (which is the goal), it does a redirect to https://myexamplevirtualhost.com/.well-known/foo123.
I've tried a lot of different things -- changing the order of location rules, etc. -- but I still can't seem to get the behaviour I want.
What am I doing wrong?
If you have HSTS (HTTP Strict Transport Security) enabled you won't be able to "turn off" https for certain pages, since https will be forced for the whole domain. You might be able to use some convoluted setup of HTTP 302 redirects to make this work, but I'm not sure why you would want to. Let's Encrypt will have no trouble renewing certs if your .well-known directory is served over HTTPS.

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