NGINX: HTTP to HTTPS redirect not working

5,568

Solution 1

Please use $server instead of $host

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

Please refer below docs. might be helpful https://www.digitalocean.com/community/questions/best-way-to-configure-nginx-ssl-force-http-to-redirect-to-https-force-www-to-non-www-on-serverpilot-free-plan-by-using-nginx-configuration-file-only

Solution 2

I'm answering this although it's been accepted because I think the answer is wrong.

I'm pasting your config below as-is, with only a comment pointing to the wrongly placed (extra it seems) curly bracked closing the server block:

server {
    listen 443 ssl default_server;
    server_name example.com

    server_tokens off;
    charset utf-8;
}                                 <--------- CLOSED BLOCK WITH EXTRA BRACKET

... SSL config stuff ...

    location / {
      proxy_pass http://localhost:8000/;

      proxy_http_version 1.1;

      proxy_set_header Host               $host;
      proxy_set_header X-Real-IP          $remote_addr;
      proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto  $scheme;
      proxy_set_header Proxy "";
    }
}
server {
      listen 80;
      server_name example.com

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

The recommended way is to use the $host as you had it initially. The $server_name variable will be replaced by the virtualhost definition instead of the URL entered by the user. This could cause you problems if you are using server_alias for example. You can read the definition of each variable in the official nginx documentation. Here is a quote:

$server_name
    name of the server which accepted a request 

$host
    in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request 

So. I think your problem was the curly bracket, and not the variable. You should probably return to the $host and try again if it works.

ps. also remove the proxy_http_version line and the proxy_set_header with the empty "", they are not needed unless you have a very specific use-case.

Share:
5,568

Related videos on Youtube

Kristoh
Author by

Kristoh

Updated on September 18, 2022

Comments

  • Kristoh
    Kristoh over 1 year

    First time posting here. I've been searching on here for about two days to find a solution to my problem and nothing is working.

    I know, there is a ton of posts about this same problem but none of the threads solutions I have came across, have worked so far. I am using NodeJS w/ Angular 5 on an Amazon EC2 instance.

    Navigating to https://example.com works fine. The web page loads correctly. But, http://example.com gives me the "Welcome to nginx!" page.

    Here is my nginx server config blocks:

    server {
        listen 443 ssl default_server;
        server_name example.com
    
        server_tokens off;
        charset utf-8;
    }
    
    ... SSL config stuff ...
    
        location / {
          proxy_pass http://localhost:8000/;
    
          proxy_http_version 1.1;
    
          proxy_set_header Host               $host;
          proxy_set_header X-Real-IP          $remote_addr;
          proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto  $scheme;
          proxy_set_header Proxy "";
        }
    }
    server {
          listen 80;
          server_name example.com
    
          return 301 https://$host$request_uri;
    }
    
    • Tried changing default_server to the port 80 block
    • Tried using $server_name instead of $host on the redirect line
    • Tried having the port 80 block on top of the port 443 block
    • Checked for syntax errors in the config files (everything is fine)

    Also checked for any conflicting files (none that I saw linked to nginx.conf).

    curl -I http://example.com
    HTTP/1.1 200 OK
    Server: nginx/1.10.3 (Ubuntu)
    Date: Wed, 18 Jul 2018 04:18:49 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 31 Jan 2017 15:01:11 GMT
    Connection: keep-alive
    ETag: "5890a6b7-264"
    Accept-Ranges: bytes
    

    As you can see, when I curl http://example.com (not actually example.com), it returns a status of 200 rather than 301. Also, the "Network" tab in Firefox's developer tools, shows a status of 304.

  • Kristoh
    Kristoh almost 6 years
    I am not sure how or why, but I must be going crazy. I had $server_name instead of $host before I posted my config here but it wasn't working that way either. Now it somehow is. Regardless, thank you so much!
  • Tero Kilkanen
    Tero Kilkanen almost 6 years
    There are use cases for both using $host and $server_name. If one has multiple virtual hosts, then $host can be used to implement the redirect for all virtual hosts. If there is only one virtual host and one wants to implement the redirect for only that host, then $server_name is better.
  • Leo
    Leo almost 6 years
    Not necessarily only with virtual hosts, $server_name could mess with redirects too, by overwriting the URL to the virtual host definition. Using instead $host variable, you are respecting the user/browser input, as the “Host” header field of the request is tested against the server_name entries of the server blocks.
  • Kristoh
    Kristoh almost 6 years
    That extra bracket was an accident when I was pasting the config over. I tried $host and $server_name before I posted here (as I saw many different reasons from different threads on to use one or the other), i tried IPv6 port configs on both 80 and 443 before I posted as well. All i did was change $host back to $server_name and added the IPv6 port config only for port 80 this time and it worked. Not really understanding why it started working either.