2

There is an nginx web server listening to both 80 and 443 ports. I would like to process all the http requests as usual and forward all the non-http requests to another port (say, 1234).

My question is very similar to one already answered on stackoverflow: Is it possible to forward NON-http connecting request to some other port in nginx?. Perhaps, I misunderstand the most up-voted answer, but when I add something like this to nginx.conf:

stream {
    upstream backend {
        server example.com:1234;
    }

    server {
        listen 80;
        proxy_pass backend;
    }
}

I get the (expected) bind() to 0.0.0.0:80 failed (98: Address already in use) error.

  • 2
    Why do you even expect that there would be non-HTTP traffic reaching port 80 on the server? – Tero Kilkanen Jun 26 '17 at 02:59
  • I just would like to replace BOSH with native application traffic. And there is a restriction to use only port 80. – semyonfilippov Jun 26 '17 at 10:43
  • I don't think there is such software that would distinguish between HTTP and other traffic on a single port. Even though one could look for HTTP headers / commands in the data received from the client, and therefore decide which kind of traffic it is, it would be way too fragile. You need to find some other solution to your issue. – Tero Kilkanen Jun 26 '17 at 13:11
  • @TeroKilkanen e.g. sslh distinguish SSL/SSL/OpenVPN and some other including plain HTTP. But certainly, it's not a job for nginx. – Alexey Ten Jun 27 '17 at 13:20
  • @semyonfilippov look at sslh – Alexey Ten Jun 27 '17 at 13:20
  • @AlexeyTen thanks, sslh works perfectly ) Would you add an answer, so I can mark this question solved? – semyonfilippov Jul 03 '17 at 07:17

2 Answers2

0

nginx can only provide one kind of a service to a port at the same time.

So, this configuration will work:

http {
    server {
        listen 80;

        server_name example.com;
        ...
    }
}

stream {
    server {
        listen 81;
        proxy_pass backend;
    }

    upstream backend {
        server 127.0.0.1:12345;
    }
}

You cannot use the same port on stream and http blocks, since nginx has no way of distinguishing the traffic type.

Tero Kilkanen
  • 34,499
  • 3
  • 38
  • 58
  • So, there is no way? Then I'm wondering why [this answer](https://stackoverflow.com/a/35521557/1014349) is so up-voted? – semyonfilippov Jun 26 '17 at 10:48
  • There are two distinct ports in that question / answer, so it is perfectly valid. – Tero Kilkanen Jun 26 '17 at 13:04
  • Sorry, I don't see the two distinct ports in that question. Both 80 and 443 port are supposed to receive http requests. And the question was - is it possible to redirect non-http requests sent to these ports to some other port. So, in my opinion, that answer doesn't solve the original problem. Anyway, thank you for your help. – semyonfilippov Jun 26 '17 at 15:53
0

As @AlexeyTen mentioned in his comment, sslh is the right tool for this purpose. It has built-in support for HTTP, SSL, SSH, OpenVPN, tinc and XMPP protocols and it supports custom regex tests as well.

For example, to make sslh forward http requests to nginx, and non-http requests to ejabberd, it's enough to replace in all nginx's virtual hosts

    listen 80;

with

    listen 127.0.0.1:88;

(it's also possible to use listen 127.0.0.1:80 if sslh with listen to port 80 on specific ip only, or to use e.g. listen 88), then install sslh and edit its default options:

RUN=yes
DAEMON_OPTS="--numeric --user sslh --listen 0.0.0.0:80 --http 127.0.0.1:88 --xmpp 127.0.0.1:5222 --pidfile /var/run/sslh/sslh.pid"

(/etc/default/sslh in debian). And, finally, just (re)start the services:

systemctl restart nginx
systemctl start sslh

If --transparent option for sslh is required, there would be some additional steps - they are well-documented on github.