I think there's a fundamental misunderstanding here. There is a difference between opening a port in the firewall and actually having a service listen on the port.
Consider the following scenario:
I am running a manually executed (that is, not automatically started) Django instance on port 6900 (random port I chose) locally.
I run NGINX on port 80 (HTTP) and 443 (HTTPS). Which is the frontend server to the Django backend.
When I start up the system, because the Django instance on port 6900 is not started, when you run netstat -tulpn or ss -tulpnyou will only see listening port(s) on port 80 and 443 for NGINX because port 6900 is not bound to a service or running process. Therefore, if I try to access port 6900 directly from anywhere I receive a "Connection Refused" error. Additionally, because Django isn't running, when NGINX tries to send to it, it will fail and respond with "502 Bad Gateway" for any requests.
However, if I actually run the Django instance, then Django is bound to port 6900, will show up in netstat/ss output, and will be reachable by the outside as long as I have port 6900 permitted in the firewall. And even if I didn't have port 6900 open in the firewall, NGINX would be able to pass the request to port 6900 locally, and then serve whatever Django is showing.
From your descriptions of your setup, you have NGINX running (probably on default ports) and you have the firewall set to allow connections to port 4000 and other ports with a proxy_pass directive to something running on port 4000 locally, but you do not have any program or service listening on port 4000, therefore nmap will never show anything on port 4000 and will see it as 'closed' because there's no response (whether you open it on the firewall or not), and NGINX will fail to forward with 502 Bad Gateway responses.
I think there's a fundamental misunderstanding here. There is a difference between opening a port in the firewall and actually having a service listen on the port.
Consider the following scenario:
When I start up the system, because the Django instance on port 6900 is not started, when you run
netstat -tulpn
orss -tulpn
you will only see listening port(s) on port 80 and 443 for NGINX because port 6900 is not bound to a service or running process. Therefore, if I try to access port 6900 directly from anywhere I receive a "Connection Refused" error. Additionally, because Django isn't running, when NGINX tries to send to it, it will fail and respond with "502 Bad Gateway" for any requests.However, if I actually run the Django instance, then Django is bound to port 6900, will show up in
netstat
/ss
output, and will be reachable by the outside as long as I have port 6900 permitted in the firewall. And even if I didn't have port 6900 open in the firewall, NGINX would be able to pass the request to port 6900 locally, and then serve whatever Django is showing.From your descriptions of your setup, you have NGINX running (probably on default ports) and you have the firewall set to allow connections to port 4000 and other ports with a
proxy_pass
directive to something running on port 4000 locally, but you do not have any program or service listening on port 4000, thereforenmap
will never show anything on port 4000 and will see it as 'closed' because there's no response (whether you open it on the firewall or not), and NGINX will fail to forward with 502 Bad Gateway responses.