Simple TCP socket and HTTP proxy on single port with nginx - sockets

I have a process listening to port 23333 and I also have some files I would like to serve through HTTPS in a directory on my server, say /var/www/files/
Can I use nginx to serve files and act as a proxy to the socket on a single port, e.g. 21000?
E.g. be able to do:
telnet example.com 21000
and
curl https://example.com:21000/files/file.txt

Related

nginx proxy unidirectional udp connection to HTTPS connection

I need to forward an unidirectional stream of udp packets from one side to an HTTPS connection on the other end.
I can potentially solve it using python, but this server should be able to forward large amount of traffic so I would like to rely on Nginx for this task.
can Nginx do such a thing?
What I tried
I tried:
stream {
server {
listen 9990 udp;
proxy_pass localhost:9995;
}
}
which forward correctly UDP packets.
I tested it running 2 servers
nc -u -l 9995 # listen on udp port 9995
nc -u localhost 9990 # send packets to nginx listening on udp port 9990
this test worked when both connections are udp. my goal to listen on TCP on port 9995 instead of udp, currently I couldn't do it with nginx.
Why?
additional context, not part of the question
I have a wire that can transfer packets only in one direction. so TCP connection can't be established. the other end requires https connection, so I can go around this by another server in the middle that will accept udp socket on one end and http/tcp socket on the other end, that will forward any udp packet coming from one end as an HTTP msg over TCP with the other end

Docker: run multiple container on same tcp ports with different hostname

Is there a way to run multiple docker containers on the same ports? For example, I have used the ports 80/443 (HTTP), 3306 (TCP/MySQL) and 22 (TCP/SSH) in my docker-compose file. Now I want to run this docker-compose for different hostnames on the same ip address on my machine.
- traffic from example1.com (default public ip) => container1
- traffic from example2.com (default public ip) => container2
I have already found a solution only for the HTTP traffic by using an additional nginx/haproxy as a proxy on my machine. But unfortunately, this can't handle other TCP ports.
This isn't possible in the general (non-HTTP) case.
At a lower level, if I connect to 10.20.30.40:3306, the Linux kernel selects a single process that's listening on that port and sends the request there. You're not allowed to bind(2) a second process to the same port. (This is also why you get an error if you try to docker run -p picking a host port that's already in use.)
In the case of HTTP, there's the further detail that the host-name part of the URL is also sent in an HTTP Host: header: the Web browser both does a DNS lookup for e.g. stackoverflow.com and connects to its IP address, and also sends a Host: stackoverflow.com HTTP header. That's the specific mechanism that lets you run a proxy on port 80, and then forward to some other backend service via a virtual-host setup.
That mechanism is very specific to HTTP, though, and doesn't work for other protocols that don't have support for it. I don't think either MySQL or ssh have similar mechanisms in their wire protocol.
(In the particular situation you describe this is probably relatively easy to handle. You wouldn't want to make either your internal database or an sshd visible publicly, so delete their ports: from your docker-compose.yml file, and then just worry about proxying the HTTP service. It's pretty unusual and a complex setup to run sshd in Docker so you also might remove that and simplify your stack a little.)

HAProxy config for sub-domains

I need an example HAProxy config to do the following:
Server1 = 192.168.0.177 ( I did not give the servers names - only IP's)
On Server1, I run HAproxy as well as Apache.
Apache on Server1 is setup to listen on port 8080 now, and has two Virtual Hosts correctly setup for two sub-domains - each serving its own website content.
Sub-domain 1 = s.mydomain.com
Sub-domain 2 = x.mydomain.com
I have a second server running on 192.168.0.233.
I want to setup HAProxy to listen to s.mydomain.com and then forward it to Apache on the same server ( 192.168.0.177), x.mydomain.com and forward it to Apache on the same server (192.168.0.177) and y.mydomain.com and forward traffic to the second server (192.168.0.233).
I do not need any load balancing at this point, just routing/forwarding as described above.
Here you go,
global
#debug
defaults
mode http
option httpclose
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
backend same_server
server same_server 127.0.0.1:8001
backend second_server
server second_server 192.168.0.233:80
frontend app *:80
acl sub_y hdr(host) -i y.mydomain.com
use_backend second_server if sub_y
default_backend same_server

How do my browser knows it needs to connect to port 443 or port 80?

This is what I am trying to do:
Open a browser and start to browse any https website like Gmail or Google.com
I can see through Wireshark that the name resolution is being done by the DNS server.
But after that, the connection is directly established to port 443 (starting from TCP handshake)
One thing I am not able to understand is, how does the browser knows that it needs to connect to port 443, I tried exploring the DNS packet, but it contains only the destination address, and there is no info which tells that it needs to connect to port 443.
Even if say, the browser has a priority in querying for the first time, it sees that if the port 443 is open then connect to it or connect to port 80, but I am not able to see any such behavior if I connect to a normal HTTP website, in the sense that, if I go to a normal HTTP website, there is no traffic flow from the browser indicating that it had searched first the port 443 and then went to port 80.
I am sure that I am missing something here, but not sure what it is.
The presence of https: in the URL tells it that.
The browser (client) uses the HTTP or HTTPS in the address to determine which port to use...
However the server can be configured to require HTTPS, and to switch/redirect an HTTP port 80 connection to HTTPS port 443 with encryption & certificate. So if the browser connects to a server via HTTP port 80, the server can then immediately switch/redirect the connection to HTTPS port 443. The server may even be configured the other way around to switch/redirect a connection from HTTPS port 443 to HTTP port 80.
I think this is sort of like asking why does a FTP client use the FTP port
Unless you specify a port with "http://...:port" the browser uses 80 for http and 443 for https as thats what the protocol defines but....
A server may respond with a "Strict-Transport-Security: max-age=..." and the browser is then required to retry on https and remember this
In addition Chrome , see HSTS, ships with a large preseeded HSTS list
so even if you type http for a site in the HSTS list - the browser will look at its HSTS configuration see that the site is specified and instead change to HTTPS on port 443 without trying http on port 80 first

multiple connections on one port

I run multiple bonjour client using pidgin, A, B, and C.
when B and C talk to A , I find A uses the same port (with wireshark I can see the packets) for MDNS and communication,
but B and C, each has two different ports one for MDNS ,one for socket connection.
how does A work, why it can work with only one port? how can one port provides multiple connections?
Attention: if it is multithread ,then when it accepts a connection it will create a new socket with another free port, but I saw the packets from wireshark, client A did just use the same port for communication and MDNS.
A TCP connection is actually identified by the tuple: (source_address, source_port, destination_address, destination_port). So as long as one of these is different there is no problem.
In practice, what you say happens when a program listens for connections in a given port: any new connection is created with the same server port (but different client port or address).
For exmample, in my Linux machine, where I have a web server listening at port 80:
$ telnet localhost 80 &
$ telnet localhost 80 &
$ lsof -n -i TCP
...
TCP 127.0.0.1:45601->127.0.0.1:80
TCP 127.0.0.1:45602->127.0.0.1:80