5

I know this must have been answered already, but I have been searching for quite a while, and cannot find the answer. Just not looking in the right place I guess, maybe someone can help me out.

Basically I am running phpmyadmin through SSL on a non-standard port, in this example 12345.

Now I have https://example.com:12345 set up ok, it works and everything. Now I want to add the ability to just type http://example.com:12345 and be redirected to the https://.

I asumed the following would work, but it does not.

server {
  listen        12345;
  server_name   php.myadmin.com;

  if ( $scheme = http ) {
    rewrite ^ https://php.myadmin.com:12345$request_uri? redirect;
  }
  root         /var/www/php;

  ssl           on;

  [....]
}

This gives me a 400 bad request.

Now before posting an answer make sure to have a good look at the redirect form. Check the pitfall in the link bellow.

https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#taxing-rewrites

Further, it would be nice if this can even be done without an if-statement:

https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#using-if

Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
Saif Bechan
  • 10,892
  • 10
  • 40
  • 63

3 Answers3

18

I do exactly this. gWaldo is correct, but you don't want to serve content over HTTP, just a redirect. The trick is to catch the http-on-an-https-port error and use that to bounce the client to the correct place.

server {
    listen   12345;
    server_name  my.domain.com;

    ssl on;
    ssl_certificate /etc/ssl/certs/your.pem;
    ssl_certificate_key /etc/ssl/private/your.key;

    # If they come here using HTTP, bounce them to the correct scheme
    error_page 497 https://$server_name:$server_port$request_uri;
    # Or if you're on the default port 443, then this should work too
    # error_page 497 https://$server_name$request_uri;

    location / {
        # Your config here...
    }
}
theJPster
  • 281
  • 2
  • 4
  • 2
    This is the actual answer to the question above. I guess the op just gave up and figured he was trying to do something impossible. – jchysk Mar 23 '13 at 21:30
  • 1
    A StackOverflow user notes "You probably want $server_name instead of $host, the server_name presumably being set to the CN that the SSL cert authenticates. That way, the user won't get a scare screen if they came in via an IP or localhost." (From https://stackoverflow.com/questions/8768946/dealing-with-nginx-400-the-plain-http-request-was-sent-to-https-port-error#comment29560742_12610382) – Blaisorblade Jul 29 '15 at 11:20
  • 1
    @Blaisorblade Answer updated. – theJPster Jul 08 '16 at 10:10
  • Using this script works, but for some reason the URL shows the port now on the browser (so basically `www.example.com:80`), anyway to make it not show the port? – Fadi Aug 16 '17 at 14:00
  • 1
    In my case I was on non-standard ports, but if your HTTPS server is on port 443 then you can probably leave out `:$server_port` on the error_page line. – theJPster Aug 16 '17 at 14:40
1

Unfortunately, you can't handle http and https requests using a single port with nginx.

What you can do is have a proxy pre-handle requests, however. This is how we handle the scheme-processing:

set $real_scheme http;
if ($http_x_forwarded_proto) { set $real_scheme $http_x_forwarded_proto; }

set $target_scheme https;

if ($real_scheme != $target_scheme) {
  rewrite ^ $target_scheme://$host$request_uri redirect;
}
gWaldo
  • 11,887
  • 8
  • 41
  • 68
  • +1 Ok, I do not understand that piece of code at all. I will try it, but it looks pretty complicated. I think I will just access the domain using the complete url, begin https://php.myadmin.com:12345. – Saif Bechan Dec 07 '11 at 20:57
-2

You can redirect access to port 80 to port 443 (to work with the default ports). But this would require you to run iptables on that host.

Not sure if you would get a 400 as well because of the SSL, but that is basically how transparent proxying works.

 iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 443

Apart from that you can redirect http-requests from port 80 to port 443 (or any port combo) in nginx, but not have them work on the same port, just like mentioned above.

EDIT: As mentioned/commented below this approach will result in a 400 due to protocol mixture.

Would it be an option to programmatically solve the problem? Try to use something like the following snippet at the top of your starter file in phpMyAdmin. This should redirect your initial call to https. After that, the rest of your page is under the SSL context anyways as long as you configured it to be served via SSL (of course).

<?php
 if ($_SERVER['SERVER_PORT']!=443) {
     $url = "https://". $_SERVER['SERVER_NAME'] . ":443".$_SERVER['REQUEST_URI'];
     header("Location: $url");
 }
?>

(Doesn't explicitly save you from jumping in w/o SSL, e.g. via bookmark as long as your session is still valid)

Chris
  • 1,155
  • 2
  • 9
  • 18
  • Yeah I know about the 80 -> 433 port redirect. You do not need iptables for that in nginx, it's just a small config. The thing is I want to run phpmyadmin on non-standard ports, that's the whole issue. – Saif Bechan Dec 07 '11 at 20:55
  • Thx for clarifying this. Updated my answer to reflect it. Maybe the programmers approach is helping tho. – Chris Dec 08 '11 at 09:30