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.

39

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 {
    }
}
| improve this answer | |
  • 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 '11 at 1:11
  • 1
    I edited. Does it look OK? I also took out listen 80 and added http_host. – pbreitenbach May 18 '11 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 '15 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. – Chuck Dries Mar 20 '17 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.

| improve this answer | |
  • 2
    It's ineffective to make nginx check scheme for every request. – Alexey Ten Jun 16 '14 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 '14 at 7:48
  • 1
    Well, you should read wiki.nginx.org/IfIsEvil – Alexey Ten Jun 16 '14 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 '14 at 7:52
  • 2
    Use include directive for common directives. Some duplication is OK. – Alexey Ten Jun 16 '14 at 7:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.