0

I have a server with 2 websites. Let's call them foo.com and bar.com.

foo.com has a subdomain, called mail.foo.com.

Both foo.com and bar.com are WordPress sites, and their NGINX configuration is the usual WP configuration you'd find in WP's instructions.

I also have a docker that is running a Mailcow image, which is listening on ports 0.0.0.0:3333 (http) and 0.0.0.0:3334 (https).

Is there a way I can configure NGINX so that opening a browser and going to:

  • foo.com will show my site foo
  • bar.com will show my site bar (those two points are currently working as expected)
  • http://mail.foo.com will make NGINX pass-thru to 127.0.0.1:3333
  • https://mail.foo.com will make NGINX pass-thru to 127.0.0.1:3334

Currently I'm trying to achieve this with the following:

stream {
    map $ssl_preread_server_name $name {
        mail.foo.com mailcow;
    }

    upstream mailcow {
        server 127.0.0.1:3333;
    }

    server {
        listen 0.0.0.0:80;
        proxy_pass $name;
        ssl_preread on;
    }
}

But as soon as I try to start NGINX, it says that port 80 is already in use. Nothing is listening on port 80. And I suspect the actual reason why NGINX is saying so is because the http block in the configuration of each virtual host (domain) listens to port 80 too.

So, then, probably my question should be: can I listen to port 80 in both stream and http sections?

If "no", how would I ssl pass-thru the traffic from mail.foo.com?

alexandernst
  • 494
  • 3
  • 7
  • 21

1 Answers1

1

You cannot have multiple application layer protocols on the same combination of IP address and port. This means that you cannot have both HTTP and HTTPS at the same port but also that you cannot have HTTP and stream (i.e. unspecified application layer protocol) on the same ip:port.

But given that you actually use stream to forward HTTP and HTTPS you might just use normal reverse proxies (proxy_pass) instead of stream, i.e. have virtual hosts for foo.com and bar.com as you currently have and then have another virtual host for mail.foo.com which is a reverse proxy to your mailcow instance. Since this will be a real HTTP/HTTPS reverse proxy and not a TCP level pass-thru the certificate for mailcow need to be installed on nginx. You also can simply forward both the external HTTPS and HTTP to the HTTP interface of mailcow and let only nginx deal with HTTPS. The setup would look something like this:

server {
    listen 80;
    servername mail.foo.com;
    location / {
        proxy_pass http://127.0.0.1:3333;
    }
}
server {
    listen 443 ssl;
    servername mail.foo.com;
    ssl_certificate ...
    ssl_certificate_key ...
    location / {
        proxy_pass http://127.0.0.1:3333;
    }
}
Steffen Ullrich
  • 12,227
  • 24
  • 37
  • I knew about that way of doing it, but unfortunately for me it's not that simple. Mailcow depends on those certificates for dovecot/postfix. So I can't let NGINX handle the creation of the certs, unless I find some way of sharing the certs between the container of mailcow and nginx. – alexandernst Jun 02 '18 at 16:57
  • @alexandernst: The certificates for dovecot and postfix are for different protocols (which are also different ports). These are for IMAP, POP and SMTP and not relevant for HTTPS. You can have your own certificate for HTTPS on `mail.foo.com` in nginx independent from the certificates for dovecot and postfix. – Steffen Ullrich Jun 02 '18 at 17:02