27

How do I set up Nginx conf file to force SSL on only one of the paths in my site and non-SSL on all the rest?

For example, I want all of the URLs under /user to be https but all the rest of the URLs to be http.

For the first part I have:

rewrite ^/user(.*) https://$http_host$request_uri?;

I don't want to use "if". I assume it would take advantage of order of operation but I don't want to end up in a loop.

2 Answers 2

40

In your nginx configuration, you should have two "server" areas. One for port 80, and one for port 443 (non-SSL and SSL). Simply add a location in your non-SSL website to redirect to your SSL page.

server {
    root /var/www/
    location / {
    }
    location /user {
        rewrite ^ https://$host$request_uri? permanent;
    }
}

it will forward all traffic that ends up at /user to your https:// server.

Then, in your 443 server, you do the opposite.

server {
    listen 443;
    root /var/www/
    location / {
        rewrite ^ http://$host$request_uri? permanent;
    }
    location /user {
    }
}
4
  • 2
    This approach is good, but it falls into a couple of common Pitfalls, specifically "Root inside location block" and "Taxing rewrites"
    – kolbyjack
    May 17, 2011 at 1:11
  • 1
    I edited. Does it look OK? I also took out listen 80 and added http_host. May 18, 2011 at 4:23
  • With this configuration, the connection switches from/to ssl/non-ssl when a user navigate the pages on the site, ssl for urls started with /user and non-ssl for all other urls. As a result, even user explicitly types https://www.example.com/ in the address bar of the browser, the resulting page is http://www.example.com/. Is there a way to implement the auto-url-rewrite between ssl/non-ssl as achieved by the settings described in this answer, but still respect the explicit ssl request if it's explicitly typed by user in the address bar? Thanks!
    – goodbyeera
    Jun 13, 2015 at 9:00
  • @goodbyeera yeah. If the idea is to force users to use SSL in certain areas, we can override their protocols there but honor them everywhere else by simply removing the rewrite commands from the 443 server configuration. Of course, now when they go to a secured part, they'll still be browsing with SSL when they go somewhere else, but it allows people to choose to use SSL from the get go. Mar 20, 2017 at 14:13
13

Nginx allows to process both HTTP and HTTPS within the same server block. Thus you don't have to duplicate directives for both and can redirect the path you want to secure

server {
  listen 80 default_server;
  listen 443 ssl;
  ... ssl certificate and other configs ...

  location /user {
    if ($scheme = 'http') {
      rewrite ^ https://$http_host$request_uri? permanent;
    }
  }

  ... your basic configuration ...
}

Be sure not to put ssl on line there because it'll break plain HTTP.

Optionally, you can redirect all other requests from HTTPS back to HTTP the same way:

if ($scheme = 'https') {
  rewrite ^ http://$http_host$request_uri? permanent;
}

UPDATE: as Alexey Ten kindly points out in comments section, checking scheme on each request is not a very bright idea. You should follow declarative way of configuring your nginx. In this case, declare two server blocks with redirects by location, move common logic to a separate file and include it in both. So GruffTech's answer is better.

8
  • 2
    It's ineffective to make nginx check scheme for every request.
    – Alexey Ten
    Jun 16, 2014 at 7:48
  • 1
    I know the question was answered 3 years ago, but I found it while struggling to do what I gradually did and just wanted to share my results with people who will follow my steps.
    – Hnatt
    Jun 16, 2014 at 7:48
  • 1
    Well, you should read wiki.nginx.org/IfIsEvil
    – Alexey Ten
    Jun 16, 2014 at 7:50
  • 1
    @AlexeyTen isn't it the case "when you can't avoid using an if"? Is there any other way to have same configuration for HTTP and HTTPS without duplicating directives?
    – Hnatt
    Jun 16, 2014 at 7:52
  • 2
    Use include directive for common directives. Some duplication is OK.
    – Alexey Ten
    Jun 16, 2014 at 7:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .