Catch-all configuration except for www.website.com? - configuration

Using Nginx, I'm trying to configure my server to accept all domains that point to the IP of my server, by showing them a specific website, but when accessing the www.example.com (main website), I'd show an other content.
Here's what I did so far:
server {
// Redirect www to non-www
listen 80;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}
server {
listen 80;
server_name example.com;
// rest of the configuration
}
server {
// Catch all
listen 80 default_server;
// I also tried
// server_name _;
// Without any luck.
// Rest of the configuration
}
The problem with this configuration is that every request made to this server not being www.example.com or example.com is took under example.com server configuration, not the catch all.
I'd like to cath only www.example.com/example.com in the first two configurations, and all the others in the last configuration.

I suggest putting your server on top of the file :)
I think nginx wants default servers to be on top of -a- file.
I have really much files on my server, but there is one with a default server as first server declaration, and that works.

Related

Is it possible to point a specific port from a domain name?

Basically what I want is this:
first.name.com:25565 -> 127.0.0.1:25562
second.name.com:25565 -> 127.0.0.1:25565
This is for some minecraft server's I'm hosting.
What you are looking for is Name-based virtual hosting. At the layer 4 transport, you can only redirect to different services by IP or port number, however, a number of protocols including HTTP(S) transmit the domain name used in the request and this allows a reverse proxy service such as Apache or Nginx to redirect to the actual service on the same or even a different host. Squid is normally used as a forward proxy on the client side which is not helpful in this case. What you want is a reverse HTTP(S) proxy on the server side. I am most familiar with Apache so I will present that here, but Nginx and others can do it as well. You will need the name-based virtual hosting of Apache to create a different service per hostname and then reverse proxy it to the real service behind it. As a note, you can't both have Apache running on 1234 and
Listen 10.1.1.1:1234
NameVirtualHost 10.1.1.1:1234
<VirtualHost 10.1.1.1:1234>
ServerName first.name.com
ProxyPreserveHost On
ProxyPass "/" "http://127.0.0.1:4321/"
ProxyPassReverse "/" "http://127.0.0.1:4321/"
</VirtualHost>
<VirtualHost 10.1.1.1:1234>
ServerName second.name.com:1234
ProxyPreserveHost On
ProxyPass "/" "http://127.0.0.1:1234/"
ProxyPassReverse "/" "http://127.0.0.1:1234/"
</VirtualHost>
You also need to make sure that the mod_proxy and mod_proxy_http modules are enabled for Apache. On Debian/Ubuntu, this can be done with this:
$ sudo a2enmod proxy
$ sudo a2enmod proxy_http
And the final note, you asked for the same port from the proxy, 1234, to be redirected to the local host on 127.0.0.1. Normally, I would recommend using a different port for the actual service, but you can share the port if to bind Apache to the external IP explicitly as I did in the example above using 10.1.1.1, and then bind the internal service only to 127.0.0.1. If you use the normal wildcard binding which it written as either 0.0.0.0 or *, then the two services will conflict.
Ok, so here's what I ended up doing:
mc.name.com is pointed at the server's hostname using a CNAME record
The next record I added was an SRV record to make 25565 point at 25562 (or whatever port I need it to be)
_minecraft._tcp.mc.muchieman.com SRV 900 0 5 25562 mc.muchieman.com.
900 being TLS, 0 being priority, 5 being weight, 25562 being the port to point to

NGINX, proxy_pass and SPA routing in HTML5 mode

I have NGINX set up as a reverse proxy for a virtual network of docker containers running itself as a container. One of these containers serves an Angular 4 based SPA with client-side routing in HTML5 mode.
The application is mapped to location / on NGINX, so that http://server/ brings you to the SPA home screen.
server {
listen 80;
...
location / {
proxy_pass http://spa-server/;
}
location /other/ {
proxy_pass http://other/;
}
...
}
The Angular router changes the URL to http://server/home or other routes when navigating within the SPA.
However, when I try to access these URLs directly, a 404 is returned. This error originates from the spa-server, because it obviously does not have any content for these routes.
The examples I found for configuring NGINX to support this scenario always assume that the SPA's static content is served directly from NGINX and thus try_files is a viable option.
How is it possible to forward any unknown URLs to the SPA so that it can handle them itself?
The solution that works for me is to add the directives proxy_intercept_errors and error_page to the location / in NGINX:
server {
listen 80;
...
location / {
proxy_pass http://spa-server/;
proxy_intercept_errors on;
error_page 404 = /index.html;
}
location /other/ {
proxy_pass http://other/;
}
...
}
Now, NGINX will return the /index.html i.e. the SPA from the spa-server whenever an unknown URL is requested. Still, the URL is available to Angular and the router will immediately resolve it within the SPA.
Of course, now the SPA is responsible for handling "real" 404s. Fortunately, this is not a problem and a good practice within the SPA anyway.
UPDATE: Thanks to #dan

How do I redirect www traffic without triggering browsers SSL check?

I have a valid certificate for example.com. If users go to my site at http://example.com, they get redirected to https://example.com and all is good. If they go to https://example.com, all is good. If they even go to http://www.example.com, they get redirected to https://example.com and all is good.
However, if they go to https://www.example.com, Chrome triggers its SSL warning before I can redirect and tells the user to not trust this site. I don't have this problem in Safari or Firefox.
Here's my nginx configuration. What am I doing wrong?
```
# Configuration for redirecting non-ssl to ssl;
server {
listen *:80;
listen [::]:80;
server_name example.com;
return 301 https://example.com$request_uri;
}
# Configuration for redirecting www to non-www;
server {
server_name www.example.com;
ssl_certificate ssl/ssl_cert.crt;
ssl_certificate_key ssl/ssl_key.key;
listen *:80;
listen *:443 ssl spdy;
listen [::]:80 ipv6only=on;
listen [::]:443 ssl spdy ipv6only=on;
return 301 https://example.com$request_uri;
}
server {
listen *:443 ssl spdy;
listen [::]:443 ssl spdy;
ssl_certificate ssl/ssl_cert.crt;
ssl_certificate_key ssl/ssl_key.key;
server_name example.com;
}
```
EDIT: I see that this is a problematic configuration because the second block will look at the certs. What's the proper way to set this up with a cert that reads from "example.com" rather than "www.example.com"?
If your certificate is for example.com only and not for www.example.com then any access to www.example.com will trigger a certificate warning, no matter if you want just redirect it or not. Redirection is done at the HTTP level and before it talks HTTP it first does the SSL handshake (which triggers the problem), because HTTPS is just HTTP inside SSL.
And before you ask, tricks with DNS (like CNAME) will not help either because the browser will compare the certificate against the name in the URL, not against possible DNS alias names. There is simply no way around getting a proper certificate.

Nginx reverse proxy for MySQL

I'm trying to use a reverse proxy for mysql. For some reason this doesn't work (where mysql-1.example.com points to a VM with MySQL).
upstream db {
server mysql-1.example.com:3306;
}
server {
listen 3306;
server_name mysql.example.com;
location / {
proxy_pass http://db;
}
}
Is there a correct way to do this? I tried connecting via mysql, but doens't work
Make sure your config is not held within the http { } section of nginx.conf. This config should be outside of the http {}.
stream {
upstream db {
server mysql-1.example.com:3306;
}
server {
listen 3306;
proxy_pass db;
}
}
You're trying to accomplish a TCP proxy with an http proxy, which is wrong.
Nginx can do the TCP load balancing/proxy stuff but the syntax is different.
look at https://www.nginx.com/resources/admin-guide/tcp-load-balancing/ for more info
It should be possible as of nginx 1.9 using TCP reverse proxies.
You need to compile nginx with the --with-stream parameter.
Then, you can add stream block in your config like #samottenhoff said in his answer.
For more details, see https://www.nginx.com/resources/admin-guide/tcp-load-balancing/ and http://nginx.org/en/docs/stream/ngx_stream_core_module.html.
Nginx plus (paid) has proper option to do that. Another way to let the docker container access to host database directly.

nginx trailing slash issues

I'm googling a lot and found several workarounds, but you have to define every single directory.
On Apache: example.com/hi -> example.com/hi/
On nginx: example.com/hi -> Firefox can't establish a connection to the server at example.com:8888
where 8888 is what Apache is listening on (nginx's :80 -> localhost:8888)
Any ideas how to fix this and have it just forward normally like folder?
I had a similar problem with varnish and nginx (varnish on port 80 proxying to nginx listening on 8080) and needed to add "port_in_redirect off;" ... server_name_in_redirect needed to stay on so nginx knew which host it was handling.
The following should do the trick, but it needs more thought/work, because only a single location block will get used at a time:
location ~ ^(.*[^/])$ {
if (-d $document_root/$1) {
rewrite ^(.*)$ $1/ permanent;
}
}
(not tested)
You can set "server_name_in_redirect off" on your server section
server{
listen 80 default;
server_name localhost;
server_name_in_redirect off;
...
...
}
That will do the trick ;-)
HTH.
Edit: Just format.
This is the magic that works best for me:
try_files $uri $uri/ #redirect;
location #redirect {
if ($uri !~ '/$') {
return 301 $uri/$is_args$args;
}
}
The 'if' statement here is safe per: http://wiki.nginx.org/IfIsEvil