NGINX redirect stream and web server on the same port? (port redirect for email VM)

I’ve been struggling with this for a few days and I’m not sure the right terminology to find an answer on my own.

I have a virtual machine running on my debian server that does all my mail, I chose to do this since backup is as easy as copying the drive image.
Rather than giving it it’s own IP I am trying to forward and redirect all the ports. (I’d rater not use more v4 than I have to)

all the smtp, imap, etc ports are just straight forwarded since the host server isn’t using those IP addresses. I’m only really having an issue with the http/https ports.

The VM is forwarded to port 81 and 444, I am trying to use nginx to either
a) make use of the upstream module to pass 443 to 127.0.0.1:444 (preferred because it looks cleaner)
—nginx fails to start because the port is already in use, was wondering if I could do something like this.
b) just redirect people from 443 to 444 for all situations
—it looks stupid but if “a” doesn’t work then I’d settle for it. It will probably break some things having to do with calendar and contact syncing.

I’m willing to do whatever necessary to get this working.
I tried other solutions but usually it results in the redirect working but breaking all my other server blocks which is magic.

PS: I’m clearly no professional, please don’t insult me. I’m not providing email as a service/selling it to people and if I do let other’s use it, it’s free.

Thanks a bunch.

I'm not sure If I get this right so I will restate what I understood (with some assumptions):
1. you have a HTTP/webserver application in VM, that serves on port 80 and 443.
2. you have incoming traffic to that application in VM at port 81 and 444
3. You want to push that traffic to that application.

It sounds like you simply are trying to do redirection the wrong way 443->444 instead of 444->443. And since HTTP server already is using 443 you get error message in nginx when it tries to open that port.

The other question is: why not reconfigure the http server to serve directly in ports 81 and 444 (since you do only local redisrection - "127.0.0.1:444").

Couple of questions.

  1. Are you using domains for each host? E.g. Host: example.com Email: email.example.com
  2. If not, are you using iptables for port forwarding to the VM?

Also might want to look into proxy_pass for nginx.

Well the VM runs on ports 80 and 443 but are forwarded to 81 and 444 to the host, this is mostly just so I can reuse the configuration on either a VM or physical machine

So really I'm going 443 -> 444 -> 443...
Though if I have the VM listen on 444 and 81 directly the result would be the same.
It would definitely be cleaner.

so the incoming traffic is going to ports 80 and 443 but for all intents and purposes the VM listens on 81 and 444. (that was a terrible way for me to explain it)
All I want to do is pass 80/443 traffic to and from 81/444 without conflicting with the services running on the host.

Unless I misunderstand what you're trying to say.

Yes, I am using domains for each host. Exactly like your example.
The mail subdomain correlates to that of the VM.

That's what I'm tried to do before but when trying to do SSL it knocked out my other server blocks(I was doing it within the http block). So I moved to trying to do that in a stream block (outside of the default http block) so that I could just pass through the SSL of the VM server but that actually conflicted with the web server portion which I didn't realize would happen.

I'm not sure you can do stream proxies on the same ports as a http block. Most modern browser use SNI and I don't think the stream proxy supports it. proxy_pass is probably the way to go. I can help you figure out why it's killing all your other server blocks if you want to go that route.

OK, so situation is not that simple as I originally assumed.

Yeah, I noticed that I couldn't have both a stream proxy and http block. If I could then that would of been a perfect solution.

Here's my configura--
oh...

I must admit I feel like a complete fool.

I was re-writing the config so it was easier to post and somehow I fixed it? It seems to be exactly the same as it was before except with more even indentation.

server {
	server_name mail.example.com;
	listen 443 ssl;
	listen 80;
	listen [::]:443 ssl;

#	ssl on;
	ssl_certificate /path/to/cert/chain.crt;
	ssl_certificate_key /path/to/key.key;
	ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header X-Real-IP $remote_addr;

	location / {
		proxy_pass https://127.0.0.1:444;
	}
}

I'm not sure what I changed to make this work...I moved the proxy_set_header directives out of the location section.
If that's what fixed it I'm going to be so mad at myself if not at least a bit embarrassed for asking in the first place.

At least it's working, thanks so much for the help. Even though I don't know what I did, asking here still led me to getting it working at least!

Woo! Also for future reference nginx actually has email proxies in the core modules. Just in case you ever want that for whatever reason.

1 Like

Thanks! I'll keep that in mind if I ever need it.