Skip to content

Transparent http proxy with Golang and tproxy

Transparent http proxy with Golang and tproxy published on 2 Comments on Transparent http proxy with Golang and tproxy

Recently I started interesting in Go language. First impressions of programming in Go are very good. In short brief, I like simplicity of this language, that you can not complicate the code too much. Goroutines and channels looks promising as solution for concurrency, and it seems simple to use. Static compiled binaries are easy to deploy. Performance is good.

I would like to share description and simple implementation in Go of fully transparent reverse or forward http proxy.

Go standard libraries – net/http and net/http/httputil provides everything needed to implement it.
Below the simplest implementation of http proxy:

Now, we can just set http proxy in browser and it will be working.

Transparent http proxy

But what if we want to to setup fully transparent proxy? For example: when we don’t want to configure manually browser on clients, but all outgoing http traffic should be pass by proxy for some reasons – logging, caching, make security scan for viruses etc. In this scenario transparent proxy is located between the client and the internet. Another use case of transparent http proxy is to set up it inline in communication between services in data center and performing some operations like traffic filtering, checking authorization etc.

System Configuration (routing table, tproxy)

I will describing scenario where http transparent proxy is acting on router which is the default gateway for my local network.
My network looks as follows:

Tproxy will be use to redirect traffic.
Tproxy allows as to redirect traffic designated to remote location to the local process.

From Linux 4.18 tproxy is included in nf_tables.

How tproxy works in details is described here:

Configuration of routing table and tproxy:


Http proxy in Go

I had to wait for Go 1.11 to be able to create custom socket with IP_TRANSPARENT param. From Go 1.11 there is possible to pass socket option before start listening or dialing. ListenConfig provide this.

The key in implementation is to create custom listener for http.Serve and use LocalAddrContextKey to get destinetion address to which client want to connect. In fact address:port values from http.LocalAddrContextKey, are the values from local socket dynamicly created by tproxy.

Starting proxy:

Client from local network ( is connecting to remote site on port This connection is handled through the proxy.
Nestat is showing one very interesting thing:

Tproxy created tcp socket with remote site address ( on my local machine. My router has only and addresses, routing table 100 does the job.
Go http proxy after receive request from client (, made a connection to exactly the same address:port as it received. MAGIC! 🙂