Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

i was wondering if nginx is able to handle http and https requests on the same port. [*]

This is what i'm trying to do. I'm running a web server (lighttpd) handling http requests, and a C program that serves a particular section of the document tree through https. These two processes run on the same server.

At the firewall level, i can have only one port forwarding traffic into this server. So what i'd like to do is to set up nginx on this server so that it listens for requests on a single port and then:

A) redirects all http://myhost.com/* requests so that they go to localhost:8080 (where lighttpd is listening)

B) if a user requests a URL starting with, for example, https:// myhost.com/app, it sends that request to localhost:8008 (C program). Note that in this case, traffic between the remote browser and nginx must be encrypted.

Do you think this could be possible? If it is, how can it be done?

I know how to do this using two different ports. The challenge that i face is doing this with just a single port (unfortunately, i don't have control over the firewall configuration on this particular environment, so that's a restriction that i cannot avoid). Using techniques like reverse port fowarding through ssh to bypass the firewall won't work either, because this should work for remote users having nothing more than a web browser and an internet link.

If this is beyond nginx capabilities, do you know of any other product that could meet this requirements? (so far i've been unsuccessful in setting this up with lighttpd and pound). I'd also prefer avoiding Apache (although i'm willing to use it if it's the only possible choice).

Thanks in advance, Alex

[*] Just to be clear, i'm talking about handling encrypted and unencrypted HTTP connections through the same port. It doesn't matter if the encryption is done through SSL or TLS.

share|improve this question
    
HTTPS requests go to port 443 by default, so even if you can get this working (and I think it's possible with a bit of hackery), you'd need to use yourhost.com and yourhost.com:80 as the links (or yourhost.com:443 and yourhost.com). –  Zanchey Jul 30 '09 at 5:26
    
Ok, i'm new at Server Fault and i don't know if i can delete my own question. Since it seems that the problem hasn't been formulated clearly enough, i'll open a new question instead. Anyway, thanks a lot to everyone who has contributed with useful suggestions for this issue. –  alemartini Jul 31 '09 at 1:04
add comment

7 Answers

For those who might be searching:

Add ssl on; and error_page 497 $request_uri; to your server definition.

share|improve this answer
2  
Little improvement to HoverHells answer: Add ssl on; and error_page 497 =200 $request_uri; to your server definition. This will change the status code to 200. –  Mawi12345 Mar 19 '12 at 15:25
add comment

If you wanted to be really clever, you could use a connection proxy thing to sniff the first couple of bytes of the incoming data stream, and hand off the connection based on the contents of byte 0: if it's 0x16 (the SSL/TLS 'handshake' byte), pass the connection to the SSL side, if it's an alphabetical character, do normal HTTP. My comment about port numbering applies.

share|improve this answer
add comment

Yes, it's possible, but needs patching the nginx source code (HoverHell has solution without patching). Nginx treats this as misconfiguration rather then valid configuration.

Variable $ssl_session_id can be used to differ between plain and ssl connection.

Patch against nginx-0.7.65:

--- src/http/ngx_http_request.c-orig    2011-05-03 15:47:09.000000000 +0200
+++ src/http/ngx_http_request.c 2011-05-03 15:44:01.000000000 +0200
@@ -1545,12 +1545,14 @@

    c = r->connection;

+    /* disable plain http over https port warning
     if (r->plain_http) {
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
                       "client sent plain HTTP request to HTTPS port");
         ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
         return;
     }
+    */

#if (NGX_HTTP_SSL)

Server config:

server {
    listen 80;
    index index.html;

    location / {
        root html;
        if ($ssl_session_id) {
            root html_ssl;
        }
    }

    ssl on;
    ssl_certificate cert.crt;
    ssl_certificate_key cert.key;
}
share|improve this answer
add comment

I do not think there is anything that can handle two different protocols on a single port...

I am curious as to why you can only forward one port, but that aside... it is not ideal but if I was in your shoes, I would serve everything over https.

share|improve this answer
    
Hi Wil, and thanks for your answer! I think that serving everything over https could be an option, although i'd like to be able to set this up in the way that i've described. Maybe this could be done if the front web server (acting as a reverse proxy) could establish a normal http session and then upgrade it to https without changing ports. I think that this behavior is described in RFC2817 (upgrading to TLS withing HTTP/1.1) but i'm not sure if nginx or other web servers know how to deal with that standard. –  alemartini Jul 30 '09 at 3:54
    
I don't have time to read a whole RFC (and not sure i'm smart enough to understand it!) but are you talking about the standard negotiation before the secure session is established or full blown different sessions? I think I understand a bit more - the server is serving on two ports and it is the proxy that refers the request - sounds cool but I have never seen it done. Perhaps a solution could be via creating a single secure site on one port and having a whole virtual directory that simply inherits / imports the other website? It doesn't get over all the issues, but may just work :S –  William Hilsum Jul 30 '09 at 4:14
add comment

You cannot support both HTTP and HTTPS over the same port, because both ends of the connection are expecting to talk a certain language, and they're not clever enough to work out if the other end is speaking something else.

As your comment to Wil's answer suggested, you could use TLS upgrade (I believe newer nginx releases support it, although I haven't tried), but that's not running HTTP and HTTPS, that's just running HTTP with TLS upgrade. The problem is still browser support -- most browsers (still) don't support it. If you've got a limited pool of clients, then this is a possibility, however.

share|improve this answer
1  
Encrypted and unencrypted HTTP traffic can be handled through a single port. What i'd like to know is if this is possible by using nginx or other products (like lighttpd) acting as reverse proxies. Quite probably this kind of setup can be handled by Apache, but i forgot to mention in my original question that i'd rather prefer not having to use Apache (although i'd do it if there isn't any other choice on the Linux platform to accomplish this). –  alemartini Jul 30 '09 at 5:13
    
As I said in my answer, "I believe newer nginx release support [TLS upgrade], although I haven't tried". If you need me to read the manual for you, then you're out of luck. –  womble Jul 31 '09 at 1:38
    
I'm sorry if i gave the impression that i need someone to read a manual for me. It just seems that the problem (and the questions about it) weren't described precisely enough (my mistake), leading to different interpretations of what i was asking or needing. So i decided to open a new question about this issue and try to avoid any possible confusion with regard to the problem or the specific questions about it. Anyway, thanks for your time and for sharing your insight. –  alemartini Aug 1 '09 at 21:30
add comment

I'm not sure how it pulls it off, but CUPSD responds to both http and https on port 631. If nginx can't do that now, perhaps they can learn from how the CUPS team pulls it off, but CUPS is under the GPL, so nginx may have to look at changing its license if they do want to implement such a capability and can't find the code to do so elsewhere.

share|improve this answer
add comment

In theory, you could have a web page that is accessible via HTTP, which is able to open a WebSocket on https:443 to anywhere it wants to. The WebSocket initial handshake is HTTP. So, yes, it is possible to make a insecure looking page actually capable of secure communication. You could do this with the Netty Library.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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