# proxytunnel: carrying a TCP connection over an HTTP proxy

> proxytunnel is a small C program that connects standard input and standard output to a remote origin server through an industry standard HTTPS proxy, which makes it a natural fit as an OpenSSH ProxyCommand when the only way out of a network is through a corporate proxy. It supports Basic and NTLM proxy authentication, credentials from a file or the environment, and encryption on either leg of the tunnel.

**proxytunnel/proxytunnel** — Stealth tunneling through HTTP(S) proxies

- Repository: https://github.com/proxytunnel/proxytunnel
- Website: http://proxytunnel.sf.net/
- Stars: 547 · Forks: 106
- Language: C
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/proxytunnel-proxytunnel

## stdin and stdout to an origin server, through a proxy

proxytunnel is a program that connects stdin and stdout to an origin server somewhere in the Internet through an industry standard HTTPS proxy.

That one sentence is the whole design, and it is worth reading carefully. It is not a proxy client in the sense of a client that speaks to a proxy as a proxy. It takes the two file descriptors it is given and splices a TCP connection onto them, so it can sit between any program that reads and writes a socket and the network. The original author's use was as an extension to SSH, so that he could reach a box at home.

The authors are Jos Visser and Mark Janssen, the primary language is C, and the project home is proxytunnel.sf.net. The build documentation is in INSTALL.md and the manual page is in docs/proxytunnel.1.adoc.

The repository carries a Travis CI build badge and, more tellingly, a Maintainers Wanted badge, which tells you the project is looking for someone to take it on. The licence is a custom one that GitHub cannot classify, with the terms in LICENSE.txt, and there are KNOWN_ISSUES, TODO, RELNOTES, CHANGES and CREDITS files alongside the code.

The releases are v1.12.2 in March 2024, v1.12.3 in March 2025 and v1.13.0 on 2026-05-31, with the last push to the repository on the same day as the release.

The audience is narrow and identifiable: anybody whose network egress is an HTTP proxy and who needs a raw TCP connection through it, most often SSH.

## The SSH ProxyCommand recipe, which is the use case

The README spends most of its length on one thing, and that is the honest usage guide.

To use the program with OpenSSH to connect to a host somewhere, you create a file in your home directory called .ssh/config with a Host entry, a ProtocolKeepAlives setting and a ProxyCommand line pointing at the proxytunnel binary. The example is a host named foobar, keepalives every thirty seconds, and a command that runs proxytunnel with encryption to the proxy, the proxy host and port, a username, and the destination host and port:

```bash
ProxyCommand /path/to/proxytunnel -E -p proxy:8080 -P username -d mybox.athome.nl:443
```


Each element in that line is explained in the README, which is helpful because the mapping between the flags and the concepts is not obvious on first reading. The symbolic name of the host is the name you will use with ssh. The -E option turns on encryption to the proxy, which means using https rather than plain http to reach it. The host name and port are where the proxy software listens. The username is the proxy user id, and the password is prompted for rather than given on the command line. The final host name and port are the box you are actually connecting to, which is where the SSH daemon runs.

Then there is the optional -z for a proxy that presents a self-signed certificate, so that the server certificate is not verified.

And the payoff is one line: when all this is in place, execute an ssh foobar and you are in business.

So the integration is with OpenSSH rather than with a browser or a mail client, and the whole point is that the destination port does not have to be 443 and the proxy does not have to know anything about SSH. The proxy sees a CONNECT request and a tunnel, and the SSH client sees a pipe.

## What the flags actually switch on

The help output lists the options in three groups, and reading the group names is the fastest way to understand the design. The program prints them with the help option:

```bash
$ ./proxytunnel --help
```


The standard options are the ones that decide the shape of the tunnel. --inetd runs the program from inetd instead of as a normal process. --standalone makes it a daemon listening on a port or an address and port combination. --proxy is the local proxy host and port, and --remproxy is a remote proxy host and port used when you chain two proxies. --dest is the destination host and port. Then three encryption switches: --encrypt for SSL between the local proxy and the destination, --encrypt-proxy for SSL between the client and the local proxy, and --encrypt-remproxy for SSL between the local and the remote proxy.

The additional options are the ones for specific features. --no-check-certificate skips server certificate verification, and --cacert points at a trusted CA certificate or directory. --ipv4 and --ipv6 enforce the address family for the connection to the local proxy. --passfile reads credentials from a file and --proxyauth and --remproxyauth take a user and password combination. --cert and --key give the client SSL certificate chain and key. --ntlm selects NTLM based authentication and --domain sets the NTLM domain, defaulting to autodetect. --header adds extra HTTP headers to send to the proxy, --host sends a custom Host header and SNI, --no-sni disables SNI entirely, and --proctitle sets a different process title.

The miscellaneous group is the usual one: --verbose, --quiet, --help and --version.

The three encryption flags are the part worth planning around, and they map onto the three legs of the connection independently. Most people need only --encrypt-proxy, because the proxy is the hop that is on the other side of the restricted network.

## Why you might need to encrypt the second hop too

There is a specific failure mode that the README explains, and it is the reason the --encrypt option exists.

If your proxy is more advanced and does protocol inspection, it will detect that your connection is not a real HTTPS or SSL connection. A CONNECT tunnel that carries, say, an SSH handshake, is not what the proxy expects to see inside a TLS session, and an inspecting proxy will notice.

The workaround is to enable SSL encryption with -e, which works around this problem. The cost is that you then need to set up stunnel4 on the other side, or connect to a process that understands SSL itself.

So the shape of the solution is a double encryption: the client speaks TLS to the proxy, and the proxy relays a TLS session to the destination, where something terminates it and hands the plaintext on. The README points at a complete guide with illustrations for encrypted tunnelling and server-side setup with Nginx, Apache or Caddy, in an article on tunnelling corporate firewalls for developers, and specifically at its chapter on HTTPS tunnelling.

That article is the practical half of this project. proxytunnel gives you the client side, and it gives you the flags, but making it work in a corporate network is a matter of the server side configuration, which is where the guide earns its place.

The chain of proxies is the related feature. If you want the first proxy to connect to another http proxy, one you can control, you specify -r proxy2:port, and the first proxy will then connect to the remote proxy, which is asked to connect to the requested destination.

## Ports 443 and 563, and the firewall workaround

One paragraph in the README explains why the tunnel is sometimes more complicated than the ProxyCommand line suggests.

Most HTTPS proxies do not allow access to ports other than 443 for HTTPS and 563 for SNEWS, so some hacking is necessary to start the SSH daemon on the required port. On the server side you add an extra Port statement in the sshd_config file, or use a redirect rule in your firewall.

That is the practical constraint that decides whether proxytunnel works at all in your network, and it is worth checking before anything else. A proxy that only allows CONNECT to 443 cannot reach an SSH daemon on port 22 no matter how clever the client is. The two workarounds are the server listening on a second port as well, so that 443 is one of the ports it answers on, or the firewall redirecting traffic that arrives on an allowed port to the real SSH port.

Both put the burden on the server you control, which is why this technique works for reaching a machine you administer and not for reaching one you do not.

The chain of proxies exists for the same reason. A corporate proxy in one network may only be reachable from another proxy, and -r proxy2:port lets the first proxy make the CONNECT request on your behalf. The README links an older how-to on SSH over HTTP tunnelling for the details of that arrangement.

The proxy credentials, in the meantime, come from the usual places. If the proxy does not require a username and password you can skip those options. If you do not provide the password on the command line, which the README recommends, you are prompted for it. And on a trusted system you can put the password in the environment variable PROXYPASS.

## Credentials from files, environment variables and NTLM

There are three separate ways to give proxytunnel the credentials it needs, and each suits a different situation.

The first is the command line, with --proxyauth and --remproxyauth taking a user and password combination. The README recommends against putting the password there, and the alternatives are the environment and a file.

The environment variables are PROXYUSER for the proxy user name, PROXYPASS for the proxy password, REMPROXYUSER and REMPROXYPASS for the remote proxy, and HTTP_PROXY, whose format is documented as carrying the primary proxy host and port information.

The file is read with -F or --passfile, and its format is deliberately simple: one field and value per line, with one space before and after the equal sign. The accepted fields are proxy_user, proxy_passwd, remproxy_user and remproxy_passwd.

That third mechanism is the one to reach for in a script, because the password is not in the process arguments and not in the environment of every process on the machine. A passfile can be created with restrictive permissions and referenced from a ProxyCommand line.

NTLM gets its own section, and it is the one with a real caveat. When your proxy uses NTLM authentication, like a Microsoft IIS proxy, you need to specify -N to enable NTLM, and then specify your username and password and optionally the domain if autodetection fails. The README is blunt about the reliability of autodetection: the NT domain can be specified on the command line if the auto-detection does not work for you, which is usually the case.

So for NTLM proxies, expect to pass -t explicitly.

## Where proxytunnel is the wrong tool

There are cases where a dedicated tunnelling tool is the wrong answer, and they come from what proxytunnel is not.

It is not a proxy client. It does not speak SOCKS, it does not understand PAC files, and it does not route arbitrary applications. It relays one TCP connection, which is exactly what an SSH ProxyCommand needs and nothing more. If you want a system-wide proxy, you want a different program.

It does not work where the proxy forbids CONNECT. The technique depends on the proxy relaying a tunnel to the destination, and a proxy that only permits plain web requests to specific ports will not do it.

It does not replace a VPN. The traffic it carries is one connection at a time, it does not cover other applications on the machine, and the routing question does not arise. In a network where a VPN client is permitted, that is the better tool.

The custom licence is worth reading before you deploy it. GitHub cannot classify it, the terms are in LICENSE.txt, and the README carries a Maintainers Wanted badge, which means the upstream expects the project to need a new maintainer.

There is also a modern alternative inside OpenSSH itself, and it is the one to try first. OpenSSH can be told to connect through an HTTP proxy using its own ProxyJump and ProxyCommand mechanisms with a CONNECT-capable helper, and other helpers exist that speak the same role. The difference in approach is that a modern client integrates with SSH's own reconnection, keepalive and configuration handling, while proxytunnel gives you a single small binary with a man page and no dependency beyond OpenSSL.

For the specific case of getting SSH out through a corporate proxy, proxytunnel is the tool people have been using for two decades, and the flags for per-hop encryption, NTLM and chained proxies are the reason it is still maintained.

## Conclusion

proxytunnel suits an engineer whose only route out is through an HTTP proxy that allows CONNECT on port 443, and who needs to reach a server with SSH without installing a VPN client. It does not suit a network where the proxy only permits port 80 without CONNECT, since the technique depends on the proxy relaying a tunnel, and it does not suit a deployment that needs a supported, signed toolchain, because the licence is a custom one and the README carries a maintainers wanted badge. Check three things before you rely on it: that your proxy allows CONNECT to the port you need, since most HTTPS proxies restrict it to 443 and 563, whether the proxy inspects traffic, because protocol inspection is what the -e option exists to work around, and which authentication scheme your proxy uses, since NTLM needs -N and usually an explicit -t domain because autodetection fails. The last push to the repository was on 2026-05-31 and the newest release is v1.13.0.

## FAQ

### What is proxytunnel and what does it connect?

It is a C program that connects stdin and stdout to an origin server somewhere on the Internet through an industry standard HTTPS proxy. The original use was as an extension to SSH, so the author could SSH to a box at home.

### How do I use proxytunnel with SSH?

Add a Host entry to your .ssh/config with a ProtocolKeepAlives setting and a ProxyCommand line running proxytunnel with the proxy host and port, a username and the destination host and port, then connect with ssh and the host name. The README explains each element of the command line.

### Why would I need the --encrypt option in proxytunnel?

An advanced proxy that does protocol inspection will detect that the connection is not a real HTTPS or SSL connection. The --encrypt option works around that, and it requires stunnel4 on the other side or a process that understands SSL itself.

### Which ports can proxytunnel reach through a proxy?

Most HTTPS proxies only allow access to ports other than 443 for HTTPS and 563 for SNEWS, so some hacking is necessary. On the server side you add an extra Port statement in sshd_config or use a redirect rule in your firewall.

### How does proxytunnel handle NTLM proxy authentication?

You need to specify -N to enable NTLM, then give the username and password and optionally the domain. The README notes that the domain can be specified on the command line if the auto-detection does not work, which is usually the case.

## Sources

- [Issues](https://github.com/proxytunnel/proxytunnel/issues)
- [Project website](http://proxytunnel.sf.net/)
- [proxytunnel/proxytunnel on GitHub](https://github.com/proxytunnel/proxytunnel)
- [README](https://github.com/proxytunnel/proxytunnel/blob/master/README.md)
- [Releases](https://github.com/proxytunnel/proxytunnel/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/proxytunnel-proxytunnel
