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.
According to wikipedia article on status codes, Nginx has a custom error code when http traffic is sent to https port(error code 497)
And according to nginx docs on error_page, you can define a URI that will be shown for a specific error.
Thus we can create a uri that clients will be sent to when error code 497 is raised.
nginx.conf
However if a client makes a request via any other method except a GET, that request will be turned into a GET. Thus to preserve the request method that the client came in via; we use error processing redirects as shown in nginx docs on error_page
And thats why we use the
301 =307
redirect.Using the nginx.conf file shown here, we are able to have http and https listen in on the same port
For those who might be searching:
Add
ssl on;
anderror_page 497 $request_uri;
to your server definition.This is finally possible to do properly since 1.15.2. See the information here.
In your nginx.conf add a block like this (outside the http block):
Then you can create your normal server block, but listening on these different ports:
This way, the stream block is able to preread and detect if it is TLS or not (on port 8080 in this example), and then proxy passes it to the correct server port locally.
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.
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:
Server config:
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.
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.
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.
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.