├── README.md └── proxy.go /README.md: -------------------------------------------------------------------------------- 1 | # socket-tcp-proxy 2 | 3 | This repo was origin created for docker(tcp port)<------->nginx(unix socket) content transportation. 4 | 5 | It works as : 6 | 7 | nginx proxy -> use unix socket as upstream -> socket-tcp-proxy -> mapped to docker container. 8 | 9 | ## To solve: 10 | Container ip changes after docker restart. 11 | We do not want to spend time solving it. 12 | However, if you can get it done, the socker-tcp-proxy is useless for you. 13 | 14 | ## Principle 15 | 16 | Start with pre-defined json configuration `/etc/socket-proxy/proxy.json`. 17 | 18 | The json configuration defined socket path, docker name and docker port, 19 | 20 | The socket-tcp-proxy would get the docker ip automatically and generate the transportation. 21 | 22 | the proxy.json example : 23 | ``` 24 | { 25 | "logfile":"/var/log/socket-proxy/proxy.log", 26 | "proxy":[ 27 | { 28 | "socket":"/home/data/socket/gitlab.sock", 29 | "docker":"gitlab", 30 | "port":"80" 31 | } 32 | ] 33 | } 34 | ``` 35 | 36 | the nginx configuration example : 37 | 38 | ``` 39 | upstream gitlab_upstream{ 40 | server unix:/home/data/socket/gitlab.sock; 41 | } 42 | 43 | server { 44 | listen 80; 45 | server_name git.starstudio.org; 46 | 47 | location / { 48 | proxy_set_header Host $host; 49 | proxy_set_header X-Real-IP $http_x_real_ip; 50 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 51 | proxy_pass http://gitlab_upstream; 52 | } 53 | include conf.d/whiteips.conf; 54 | 55 | access_log /var/log/nginx/gitlab_access.log; 56 | error_log /var/log/nginx/gitlab_error.log; 57 | } 58 | ``` 59 | 60 | -------------------------------------------------------------------------------- /proxy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "io/ioutil" 7 | "log" 8 | "net" 9 | "os" 10 | "os/exec" 11 | "os/signal" 12 | "runtime" 13 | "sync" 14 | "sync/atomic" 15 | "syscall" 16 | 17 | docker "github.com/fsouza/go-dockerclient" 18 | ) 19 | 20 | //compiler-settable version 21 | var VERSION = "0.0.0-src" 22 | 23 | //detailed statistics 24 | var count uint64 25 | 26 | type Conf struct { 27 | Logfile string `json:"logfile"` 28 | Proxy []Proxy `json:"proxy"` 29 | } 30 | 31 | type Proxy struct { 32 | Docker string `json:"docker"` 33 | Socket string `json:"socket"` 34 | Port string `json:"port"` 35 | DockerIp string `json:"docker_ip"` 36 | //store ip like 172.1.1.1 37 | DockerAddr string `json:"docker_addr"` 38 | //store tcp like 172.1.1.1:80 39 | } 40 | 41 | func (p *Proxy) StartForward() { 42 | log.Println("[INFO] Forwarding " + p.Socket + " to " + p.DockerAddr) 43 | 44 | l, err := net.Listen("unix", p.Socket) 45 | exec.Command("chmod", "777", p.Socket).Run() 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | for { 50 | uconn, err := l.Accept() 51 | if err != nil { 52 | log.Println("[ERROR] For Forwarding " + p.Socket + " to " + p.DockerAddr + " " + err.Error()) 53 | continue 54 | } 55 | go forward(p, uconn) 56 | } 57 | } 58 | 59 | func forward(p *Proxy, uconn net.Conn) { 60 | id := atomic.AddUint64(&count, 1) 61 | 62 | tconn, err := net.Dial("tcp", p.DockerAddr) 63 | if err != nil { 64 | log.Printf("[ERROR]Local dial failed: %s "+p.Socket+" to "+p.DockerAddr+"\n", err) 65 | return 66 | } 67 | log.Printf("[%d] connected from "+p.Socket+" to "+p.DockerAddr, id) 68 | 69 | var wg sync.WaitGroup 70 | go func(uconn net.Conn, tconn net.Conn) { 71 | wg.Add(1) 72 | defer wg.Done() 73 | io.Copy(uconn, tconn) 74 | uconn.Close() 75 | }(uconn, tconn) 76 | go func(uconn net.Conn, tconn net.Conn) { 77 | wg.Add(1) 78 | defer wg.Done() 79 | io.Copy(tconn, uconn) 80 | tconn.Close() 81 | }(uconn, tconn) 82 | wg.Wait() 83 | } 84 | 85 | func ReadToString(filePath string) (string, error) { 86 | b, err := ioutil.ReadFile(filePath) 87 | if err != nil { 88 | return "", err 89 | } 90 | return string(b), nil 91 | } 92 | 93 | var conf Conf 94 | var configFilePath string 95 | var debug bool 96 | 97 | var dockerclient *docker.Client 98 | 99 | func init() { 100 | debug = (runtime.GOOS == "darwin") 101 | configFilePath = "/etc/socket-proxy/proxy.json" 102 | jsonString, err := ReadToString(configFilePath) 103 | if err != nil { 104 | if !debug { 105 | log.Fatal(err) 106 | } 107 | } 108 | json.Unmarshal([]byte(jsonString), &conf) 109 | 110 | dockerclient, err = docker.NewClientFromEnv() 111 | if err != nil { 112 | if !debug { 113 | log.Fatal(err) 114 | } 115 | } 116 | 117 | //fire on the fly 118 | runtime.GOMAXPROCS(runtime.NumCPU()) 119 | } 120 | 121 | func main() { 122 | 123 | log.SetFlags(log.Lshortfile | log.Ltime | log.Ldate) 124 | logFile, err := os.OpenFile(conf.Logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 125 | if err != nil && !debug { 126 | log.Println("error opening log file:", err) 127 | os.Exit(1) 128 | } else if !debug { 129 | log.SetOutput(logFile) 130 | } 131 | defer logFile.Close() 132 | 133 | for k, v := range conf.Proxy { 134 | name, err := dockerclient.InspectContainer(v.Docker) 135 | if err != nil { 136 | log.Fatal(err) 137 | } 138 | log.Println(v.Docker, name.NetworkSettings.IPAddress) 139 | v.DockerIp = name.NetworkSettings.IPAddress 140 | v.DockerAddr = name.NetworkSettings.IPAddress + ":" + v.Port 141 | conf.Proxy[k] = v 142 | } 143 | 144 | log.Println(conf.Proxy) 145 | for _, v := range conf.Proxy { 146 | go v.StartForward() 147 | } 148 | 149 | c := make(chan os.Signal) 150 | //we do not want to clean the signals 151 | signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP, syscall.SIGTERM) 152 | //hang the process and wait for kill 153 | <-c 154 | 155 | for _, v := range conf.Proxy { 156 | os.Remove(v.Socket) 157 | } 158 | log.Println("Closed listener signal") 159 | os.Exit(0) 160 | } 161 | 162 | --------------------------------------------------------------------------------