I'm a user of https://github.com/proxytunnel/proxytunnel to connect to SSH over HTTPS. This requires the HTTP server to redirect the traffic to a local SSH server. Following http://dag.wiee.rs/howto/ssh-http-tunneling/ I implemented this on my server using Apache. Works great!
Now I wish to transfer that config to nginx using ngx_http_proxy_connect_module. Is this possible?
For simplicity, the following example shows the non encrypted configuration. This Apache configuration is from my NixOS config.
httpd = {
enable = true;
virtualHosts."localhost:21343" = {
listen = [
{
ip = "*";
port = 21343;
ssl = false;
}
];
extraConfig = ''
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyRequests on
AllowConnect 22
<Proxy *>
# Deny all proxying by default ...
Require all denied
</Proxy>
<Proxy 127.0.0.1>
# Now allow proxying through localhost only
Require all granted
</Proxy>
'';
};
This results in a successful connection as tested by proxytunnel.exe -v
(Here the connection goes through an additional local proxy 127.0.0.1:54450
, which is not relevant to the question)
proxytunnel.exe -v -q -p 127.0.0.1:54450 -r example.org:21343 -d 127.0.0.1:22
Tunneling to example.org:21343 (remote proxy)
Communication with local proxy:
-> CONNECT example.org:21343 HTTP/1.1
-> Host: example.org:21343
-> Proxy-Connection: Keep-Alive
<- HTTP/1.1 200 Connection established
<-
Tunneling to 127.0.0.1:22 (destination)
Communication with remote proxy:
-> CONNECT 127.0.0.1:22 HTTP/1.1
-> Host: 127.0.0.1:22
-> Proxy-Connection: Keep-Alive
<- HTTP/1.0 200 Connection Established
<- Proxy-agent: Apache/2.4.59 (Unix)
<-
Tunnel established.
SSH-2.0-OpenSSH_9.6
Now I configure the same with nginx, because nginx is my main HTTP server and I wish to do this over a subdomain, instead of another random non-standard port.
nginx = {
enable = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedBrotliSettings = true;
recommendedZstdSettings = true;
recommendedOptimisation = true;
additionalModules = [ pkgs.nginxModules.http_proxy_connect_module_v24 ];
virtualHosts = {
"example.org" = {
root = "/var/www/example.org";
enableACME = true;
forceSSL = true;
};
"ssh.example.org" = {
extraConfig = ''
proxy_connect;
proxy_connect_allow all; # For testing set to all
proxy_connect_address 127.0.0.1:22;
'';
};
};
};
Connecting to this results in a rejection however.
proxytunnel.exe -v -q -p 127.0.0.1:54450 -r ssh.example.org:80 -d 127.0.0.1:22
Tunneling to ssh.example.org:80 (remote proxy)
Communication with local proxy:
-> CONNECT ssh.example.org:80 HTTP/1.1
-> Host: ssh.example.org:80
-> Proxy-Connection: Keep-Alive
<- HTTP/1.1 200 Connection established
<-
Tunneling to 127.0.0.1:22 (destination)
Communication with remote proxy:
-> CONNECT 127.0.0.1:22 HTTP/1.1
-> Host: 127.0.0.1:22
-> Proxy-Connection: Keep-Alive
<- HTTP/1.1 405 Not Allowed
<- Server: nginx
<- Date: Fri, 10 May 2024 05:33:10 GMT
<- Content-Type: text/html
<- Content-Length: 150
<- Connection: keep-alive
<-
What am I doing wrong? Is this possible?
This has been solved. Configuring NGINX for SSH over HTTPS / HTTP with proxytunnel
has some minute details, that were elaborated in issue https://github.com/proxytunnel/proxytunnel/issues/84 .
Long story short, with https://github.com/chobits/ngx_http_proxy_connect_module compiled into NGINX:
proxy_connect;
proxy_connect_allow 22; # To limit access to only the SSH port
proxy_connect_address 127.0.0.1; # To limit access only to localhost and prevent connections to other places
Next, you need to set the server block that this is in as default_server
to prevent routing issues, details explained in the issue linked above.
Finally you can connect. If your proxy_connect
statement is in a server that has HTTPS, with a Corporate proxy in between, the connection command will look like:
proxytunnel -X -p corporate.com:8888 -r domain.com:443 -d 127.0.0.1:22
and with no corporate firewall in the way, the command looks like:
proxytunnel -E -p domain.com:443 -d 127.0.0.1:22
.
Additionally if you use HTTPS instead of HTTP and are on Windows you will need to ignore the certificate check -z, --no-check-certificate
or perform some extra steps as explained in issue: https://github.com/proxytunnel/proxytunnel/issues/82 . SSH has still its own encryption, so it doesn't particularly matter whether or not you can trust the certificate.
Tested a bunch, works flawlessly in all kinds of challenging connection scenarios. Packet sniffing firewalls don't have a clue.