basmariot
By:
basmariot

Two domains on one droplet with one SSL certificate

April 22, 2017 397 views
Deployment Nginx Let's Encrypt Ubuntu 16.04

Hi there!

I am trying to get two domains running on one droplet (nginx) with the same SSL certificate, and as a newbie to this, I have been tearing out my hair for a day trying to get it to work.

My configuration for the first domain is this the following. Its a node app, and it’s working fine:

#domain1

server {
        listen 80 default_server;

        root /home/Bas/domain1;
        index index.html index.htm;

        server_name www.domain1.com domain1.com;
        return 301 https://$server_name$request_uri;
}

server {
        server_name www.domain1.com domain1.com;
        listen 443 ssl http2;

        ssl_certificate /etc/letsencrypt/live/www.domain1.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.domain1.com/privkey.pem;
        include /etc/nginx/snippets/ssl-params.conf;

    location / {
        proxy_pass http://localhost:3001;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
     }
     location ~ /.well-known {
             allow all;
    }
  }

The second domain is for a static website, and it was working before I tried to install the https. I think I got something wrong in the configuration file which you can see below:

#domain2

server {
    listen 80;
    server_name domain2.com www.domain2.com
    return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2;
  server_name domain2.com www.domain2.com;

  root /home/Bas/domain2;
  index index.html index.htm;

  ssl_certificate /etc/letsencrypt/live/domain2.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/domain2.com/privkey.pem;

  include /etc/nginx/snippets/ssl-params.conf;

  location / {
         try_files $uri $uri/ =404;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-NginX-Proxy true;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_pass http://localhost:80/;
         proxy_ssl_session_reuse off;
         proxy_set_header Host $http_host
         proxy_cache_bypass $http_upgrade;
         proxy_redirect off; 
 }

 location ~ /.well-known {
             allow all;
     }
}

I’ve been trying a lot of different solutions and I have been running into multiple different errors, depending on my configuration: 502 bad gateway, “Welcome to Nginx, further configuration is required”, “too many redirects”, and at the moment I get the first Node app on both domains. Really stuck here, so any help would be much appreciated!

5 Answers
hansen April 22, 2017
Accepted Answer

Hi @basmariot

You domain2 configuration is redirecting non-https traffic to https, but then it's proxying back from https to non-https.

Just remove all the proxy_... from domain2 configuration and reload Nginx - that's it.

  • Thanks! Unfortunately still the same problem after I did that: domain2 still directs to the app at domain1 (and the url changes to domain1.com as well).

    Domain2 configuration now looks like this:

    server {
        listen 80;
        server_name domain2.com www.domain2.com;
        return 301 https://$server_name$request_uri;
    
        root /home/Bas/domain2;
        index index.html index.htm;
    
        location / {
             try_files $uri $uri/ =404;
        }
    }
    
    server {
      listen 443 ssl http2;
      server_name domain2.com www.domain2.com;
    
      root /home/Bas/domain2;
      index index.html index.htm;
    
      ssl_certificate /etc/letsencrypt/live/domain2.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/domain2.com/privkey.pem;
    
      include /etc/nginx/snippets/ssl-params.conf;
    
      location / {
             try_files $uri $uri/ =404;
             }
    }
    
    • @basmariot

      You can't use a return and try_files in the way that you're using it. With the current setup (on Port 80), the return takes place before try_files, thus it has priority.

      What the server block should look like is:

      server {
          listen 80;
          server_name domain2.com www.domain2.com;
      
          return 301 https://$server_name$request_uri;
      }
      
      server {
          listen 443 ssl http2;
          server_name domain2.com www.domain2.com;
      
          root /home/Bas/domain2;
      
          index index.html index.htm;
      
          ssl_certificate /etc/letsencrypt/live/domain2.com/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/domain2.com/privkey.pem;
      
          include /etc/nginx/snippets/ssl-params.conf;
      
          location / {
              try_files $uri $uri/ =404;
          }
      }
      
      • @basmariot

        As a general note, when it comes to HTTPS / SSL, you want the server block that does the handling of requests on Port 80 to be minimal. It doesn't need to process files, only the request as it passes it over to HTTPS.

        That's why we don't need the try_files directive in the first server block, or really any directive other than listen, server_name and return.

        • Thanks again, your explanation makes it much more clear. The server block now looks like in your last post, but it is still directing to the domain1. Could there be another configuration in another file that needs to be changed? Or maybe in the configuration of domain1?

          • @basmariot

            If you would, please post both of the domain configurations as you have them now so we can take another look to make sure everything is correct.

            Are there any other configuration files (server blocks) as well or are there only those two?

Okay so the issue is the port set in proxy pass (for the second domain).
You do a 301 redirect from normal http server to https server, and in https server you proxy_pass back to localhost:80 on standard http. This creates a redirect unending loop.

Https support for static websites does not need or work with proxy_pass, to fix this remove it. You do not need a location / { } block for a static website, just set a root folder and an index file and it should work and keep the .well-known location block, you will need that for Let's Encrypt.

Also to #domain1 you may want to add $request_uri to the end

proxy_pass http://localhost:3001?$request_uri;

Hope this helps.

@basmariot

What's inside of /etc/nginx/snippets/ssl-params.conf?

...

As far as the server blocks go, let's start with the two that listen on Port 80.

When you're proxying requests, you don't need the same directives that you would need if you were not. We can shrink down the first two server blocks.

domain1.com

This:

server {
        listen 80 default_server;

        root /home/Bas/domain1;
        index index.html index.htm;

        server_name www.domain1.com domain1.com;
        return 301 https://$server_name$request_uri;
}

Becomes:

server {
    listen 80;
    server_name www.domain1.com domain1.com;

    return 301 https://$server_name$request_uri;
}

domain2.com

The second domain is already using the shrunken down version, so no changes are needed.

...

Now let's focus on the server blocks listening on Port 443 (SSL). Your first domain looks ok in terms of basic setup, though domain2.com is where the issue is.

domain2.com

This is where the issue is:

  location / {
         try_files $uri $uri/ =404;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-NginX-Proxy true;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_pass http://localhost:80/;
         proxy_ssl_session_reuse off;
         proxy_set_header Host $http_host
         proxy_cache_bypass $http_upgrade;
         proxy_redirect off; 
 }

1). When proxying, don't use try_files, so the first step is removing that line.

2). When proxying, you can't proxy to Port 80 and have a redirect that redirects 80 back to 443, this is what's causing the endless loop.

So the above should look like:

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://localhost:80/;
    proxy_ssl_session_reuse off;
    proxy_set_header Host $http_host
    proxy_cache_bypass $http_upgrade;
    proxy_redirect off; 
}

But you need to change proxy_pass http://localhost:80/; and change 80 to the port of your app.

  • Thanks for your help! The second domain is a static website, so I don't have it running on a port. Maybe that's where the problem comes from (as the answer below stated)? I deleted all the proxy configuration, but unfortunately domain2 is still directing to the the app at domain1.

    My /etc/nginx/snippets/ssl-params.conf looks as following:

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off; # Requires nginx >= 1.5.9
    ssl_stapling on; # Requires nginx >= 1.3.7
    ssl_stapling_verify on; # Requires nginx => 1.3.7
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    

These are the only 2 configuration files, I have removed the default file from the sites-enabled. Domain 1 as following:

#domain1

server {
        listen 80 default_server;
        server_name www.domain1.com domain1.com;
        return 301 https://$server_name$request_uri;
}

server {
        server_name www.domain1.com domain1.com;
        listen 443 ssl http2;

        ssl_certificate /etc/letsencrypt/live/www.domain1.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.domain1.com/privkey.pem;
        include /etc/nginx/snippets/ssl-params.conf;

    location / {
        proxy_pass http://localhost:3001;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
     }
     location ~ /.well-known {
             allow all;
    }
}

And domain2:

#domain2
server {
    listen 80;
    server_name domain2.com www.domain2.com;
    return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2;
  server_name domain2.com www.domain2.com;

  root /home/Bas/domain2;
  index index.html index.htm;

  ssl_certificate /etc/letsencrypt/live/domain2.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/domain2.com/privkey.pem;

  include /etc/nginx/snippets/ssl-params.conf;

  location / {
         try_files $uri $uri/ =404;
         }
}

It seems the problem has been solved now with the above configuration. I had to remove the first domain from the sites-enabled first though. After that the second domain worked. When I re-added the first domain to the sites-enabled, they both worked properly.

Have another answer? Share your knowledge.