diff --git a/.travis.yml b/.travis.yml
index b49aa7c3..8494825d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@ sudo: false
 language: go
 
 go:
-    - 1.7.x
     - 1.8.x
 
 install:
diff --git a/client/proxy.go b/client/proxy.go
index 4e1d020f..3dbedf8e 100644
--- a/client/proxy.go
+++ b/client/proxy.go
@@ -103,7 +103,6 @@ func (pxy *TcpProxy) Close() {
 }
 
 func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn) {
-	defer conn.Close()
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn)
 }
 
@@ -132,7 +131,6 @@ func (pxy *HttpProxy) Close() {
 }
 
 func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn) {
-	defer conn.Close()
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn)
 }
 
@@ -161,7 +159,6 @@ func (pxy *HttpsProxy) Close() {
 }
 
 func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn) {
-	defer conn.Close()
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn)
 }
 
diff --git a/conf/frpc_full.ini b/conf/frpc_full.ini
index f6b6b8a2..93fe53df 100644
--- a/conf/frpc_full.ini
+++ b/conf/frpc_full.ini
@@ -90,11 +90,18 @@ use_compression = false
 subdomain = web01
 custom_domains = web02.yourdomain.com
 
-[unix_domain_socket]
+[plugin_unix_domain_socket]
 type = tcp
-remote_port = 6001
+remote_port = 6003
 # if plugin is defined, local_ip and local_port is useless
 # plugin will handle connections got from frps
 plugin = unix_domain_socket
 # params set with prefix "plugin_" that plugin needed
 plugin_unix_path = /var/run/docker.sock
+
+[plugin_http_proxy]
+type = tcp
+remote_port = 6004
+plugin = http_proxy
+plugin_http_user = abc
+plugin_http_passwd = abc
diff --git a/models/plugin/http-proxy/config/config.json b/models/plugin/http-proxy/config/config.json
deleted file mode 100644
index 3574ab25..00000000
--- a/models/plugin/http-proxy/config/config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "port":":8080"
-}
diff --git a/models/plugin/http-proxy/proxy/config.go b/models/plugin/http-proxy/proxy/config.go
deleted file mode 100644
index 4e8d0c16..00000000
--- a/models/plugin/http-proxy/proxy/config.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package proxy
-
-import (
-	"bufio"
-	"encoding/json"
-	"os"
-)
-
-// Config 保存代理服务器的配置
-type Config struct {
-	Port string `json:"port"`
-	Auth bool   `json:"auth"`
-
-	User map[string]string `json:"user"`
-}
-
-// 从指定json文件读取config配置
-func (c *Config) GetConfig(filename string) error {
-
-	configFile, err := os.Open(filename)
-	if err != nil {
-		return err
-	}
-	defer configFile.Close()
-
-	br := bufio.NewReader(configFile)
-	err = json.NewDecoder(br).Decode(c)
-	if err != nil {
-		return err
-	}
-	return nil
-}
diff --git a/models/plugin/http-proxy/proxy/proxy.go b/models/plugin/http-proxy/proxy/proxy.go
deleted file mode 100644
index 062b99d3..00000000
--- a/models/plugin/http-proxy/proxy/proxy.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package proxy
-
-import (
-	"fmt"
-	"io"
-	"net"
-	"net/http"
-	"os"
-	"time"
-
-	"github.com/fatedier/frp/models/plugin"
-	"github.com/fatedier/frp/utils/log"
-	wrap "github.com/fatedier/frp/utils/net"
-)
-
-var (
-	HTTP_200  = []byte("HTTP/1.1 200 Connection Established\r\n\r\n")
-	ProxyName = "default-proxy"
-	cnfg      Config
-)
-
-func init() {
-	// 加载配置文件
-	err := cnfg.GetConfig("../config/config.json")
-	if err != nil {
-		log.Error("can not load config file:%v\n", err)
-		os.Exit(-1)
-	}
-	plugin.Register(ProxyName, NewProxyPlugin)
-}
-
-type ProxyServer struct {
-	Tr *http.Transport
-}
-
-type Proxy struct {
-	Server *http.Server
-	Ln     net.Listener
-}
-
-func NewProxyPlugin(params map[string]string) (p plugin.Plugin, err error) {
-
-	listen, err := net.Listen("tcp", cnfg.Port)
-	if err != nil {
-		log.Error("can not listen %v port", cnfg.Port)
-		return
-	}
-
-	proxy := &Proxy{
-		Server: NewProxyServer(),
-		Ln:     listen,
-	}
-	go proxy.Server.Serve(proxy.Ln)
-
-	return proxy, nil
-}
-
-func (proxy *Proxy) Name() string {
-	return ProxyName
-}
-
-// right??
-func (proxy *Proxy) Handle(conn io.ReadWriteCloser) {
-	wrapConn := wrap.WrapReadWriteCloserToConn(conn)
-
-	remote, err := net.Dial("tcp", cnfg.Port)
-	if err != nil {
-		log.Error("dial tcp error:%v", err)
-		return
-	}
-
-	// or tcp.Join(remote,wrapConn)
-	_, err = io.Copy(remote, wrapConn)
-	if err != nil && err != io.EOF {
-		log.Error("io copy data error:%v", err)
-		return
-	}
-	return
-}
-
-func (proxy *Proxy) Close() error {
-	return proxy.Server.Close()
-}
-
-func NewProxyServer() *http.Server {
-
-	return &http.Server{
-		Addr:           cnfg.Port,
-		Handler:        &ProxyServer{Tr: http.DefaultTransport.(*http.Transport)},
-		ReadTimeout:    10 * time.Second,
-		WriteTimeout:   10 * time.Second,
-		MaxHeaderBytes: 1 << 20,
-	}
-}
-
-func (proxy *ProxyServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
-	defer func() {
-		if err := recover(); err != nil {
-			rw.WriteHeader(http.StatusInternalServerError)
-			log.Error("Panic: %v", err)
-			fmt.Fprintf(rw, fmt.Sprintln(err))
-		}
-	}()
-
-	if req.Method == "CONNECT" { // 是connect连接
-		proxy.HttpsHandler(rw, req)
-	} else {
-		proxy.HttpHandler(rw, req)
-	}
-}
-
-// 处理普通的http请求
-func (proxy *ProxyServer) HttpHandler(rw http.ResponseWriter, req *http.Request) {
-	log.Info("is sending request %v %v ", req.Method, req.URL.Host)
-	removeProxyHeaders(req) // 去除不必要的头
-
-	resp, err := proxy.Tr.RoundTrip(req)
-	if err != nil {
-		log.Error("transport RoundTrip error: %v", err)
-		http.Error(rw, err.Error(), http.StatusInternalServerError)
-		return
-	}
-	defer resp.Body.Close()
-
-	clearHeaders(rw.Header()) // 得到一个空的Header
-	copyHeaders(rw.Header(), resp.Header)
-	rw.WriteHeader(resp.StatusCode)
-
-	nr, err := io.Copy(rw, resp.Body)
-	if err != nil && err != io.EOF {
-		log.Error("got an error when copy remote response to client.%v", err)
-		return
-	}
-	log.Info("copied %v bytes from remote host %v.", nr, req.URL.Host)
-}
-
-// 处理https连接,主要用于CONNECT方法
-func (proxy *ProxyServer) HttpsHandler(rw http.ResponseWriter, req *http.Request) {
-	log.Info("[CONNECT] tried to connect to remote host %v", req.URL.Host)
-
-	hj, _ := rw.(http.Hijacker)
-	client, _, err := hj.Hijack() //获取客户端与代理服务器的tcp连接
-	if err != nil {
-		log.Error("failed to get Tcp connection of", req.RequestURI)
-		http.Error(rw, "Failed", http.StatusBadRequest)
-		return
-	}
-
-	remote, err := net.Dial("tcp", req.URL.Host) //建立服务端和代理服务器的tcp连接
-	if err != nil {
-		log.Error("failed to connect %v", req.RequestURI)
-		http.Error(rw, "Failed", http.StatusBadRequest)
-		client.Close()
-		return
-	}
-
-	client.Write(HTTP_200)
-
-	go copyRemoteToClient(remote, client)
-	go copyRemoteToClient(client, remote)
-}
-
-// data copy between two socket
-func copyRemoteToClient(remote, client net.Conn) {
-	defer func() {
-		remote.Close()
-		client.Close()
-	}()
-
-	nr, err := io.Copy(remote, client)
-	if err != nil && err != io.EOF {
-		log.Error("got an error when handles CONNECT %v", err)
-		return
-	}
-	log.Info("[CONNECT]  transported %v bytes betwwen %v and %v", nr, remote.RemoteAddr(), client.RemoteAddr())
-}
-
-func copyHeaders(dst, src http.Header) {
-	for key, values := range src {
-		for _, value := range values {
-			dst.Add(key, value)
-		}
-	}
-}
-
-func clearHeaders(headers http.Header) {
-	for key, _ := range headers {
-		headers.Del(key)
-	}
-}
-
-func removeProxyHeaders(req *http.Request) {
-	req.RequestURI = ""
-	req.Header.Del("Proxy-Connection")
-	req.Header.Del("Connection")
-	req.Header.Del("Keep-Alive")
-	req.Header.Del("Proxy-Authenticate")
-	req.Header.Del("Proxy-Authorization")
-	req.Header.Del("TE")
-	req.Header.Del("Trailers")
-	req.Header.Del("Transfer-Encoding")
-	req.Header.Del("Upgrade")
-}
diff --git a/models/plugin/http_proxy.go b/models/plugin/http_proxy.go
new file mode 100644
index 00000000..1e03f215
--- /dev/null
+++ b/models/plugin/http_proxy.go
@@ -0,0 +1,226 @@
+// Copyright 2017 frp team
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package plugin
+
+import (
+	"encoding/base64"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"strings"
+	"sync"
+
+	"github.com/fatedier/frp/models/proto/tcp"
+	"github.com/fatedier/frp/utils/errors"
+	frpNet "github.com/fatedier/frp/utils/net"
+)
+
+const PluginHttpProxy = "http_proxy"
+
+func init() {
+	Register(PluginHttpProxy, NewHttpProxyPlugin)
+}
+
+type Listener struct {
+	conns  chan net.Conn
+	closed bool
+	mu     sync.Mutex
+}
+
+func NewProxyListener() *Listener {
+	return &Listener{
+		conns: make(chan net.Conn, 64),
+	}
+}
+
+func (l *Listener) Accept() (net.Conn, error) {
+	conn, ok := <-l.conns
+	if !ok {
+		return nil, fmt.Errorf("listener closed")
+	}
+	return conn, nil
+}
+
+func (l *Listener) PutConn(conn net.Conn) error {
+	err := errors.PanicToError(func() {
+		l.conns <- conn
+	})
+	return err
+}
+
+func (l *Listener) Close() error {
+	l.mu.Lock()
+	defer l.mu.Unlock()
+	if !l.closed {
+		close(l.conns)
+	}
+	return nil
+}
+
+func (l *Listener) Addr() net.Addr {
+	return (*net.TCPAddr)(nil)
+}
+
+type HttpProxy struct {
+	l          *Listener
+	s          *http.Server
+	AuthUser   string
+	AuthPasswd string
+}
+
+func NewHttpProxyPlugin(params map[string]string) (Plugin, error) {
+	user := params["plugin_http_user"]
+	passwd := params["plugin_http_passwd"]
+	listener := NewProxyListener()
+
+	hp := &HttpProxy{
+		l:          listener,
+		AuthUser:   user,
+		AuthPasswd: passwd,
+	}
+
+	hp.s = &http.Server{
+		Handler: hp,
+	}
+
+	go hp.s.Serve(listener)
+	return hp, nil
+}
+
+func (hp *HttpProxy) Name() string {
+	return PluginHttpProxy
+}
+
+func (hp *HttpProxy) Handle(conn io.ReadWriteCloser) {
+	var wrapConn net.Conn
+	if realConn, ok := conn.(net.Conn); ok {
+		wrapConn = realConn
+	} else {
+		wrapConn = frpNet.WrapReadWriteCloserToConn(conn)
+	}
+
+	hp.l.PutConn(wrapConn)
+	return
+}
+
+func (hp *HttpProxy) Close() error {
+	hp.s.Close()
+	hp.l.Close()
+	return nil
+}
+
+func (hp *HttpProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
+	if ok := hp.Auth(rw, req); !ok {
+		rw.Header().Set("Proxy-Authenticate", "Basic")
+		rw.WriteHeader(http.StatusProxyAuthRequired)
+		return
+	}
+
+	if req.Method == "CONNECT" {
+		hp.ConnectHandler(rw, req)
+	} else {
+		hp.HttpHandler(rw, req)
+	}
+}
+
+func (hp *HttpProxy) HttpHandler(rw http.ResponseWriter, req *http.Request) {
+	removeProxyHeaders(req)
+
+	resp, err := http.DefaultTransport.RoundTrip(req)
+	if err != nil {
+		http.Error(rw, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	defer resp.Body.Close()
+
+	copyHeaders(rw.Header(), resp.Header)
+	rw.WriteHeader(resp.StatusCode)
+
+	_, err = io.Copy(rw, resp.Body)
+	if err != nil && err != io.EOF {
+		return
+	}
+}
+
+func (hp *HttpProxy) ConnectHandler(rw http.ResponseWriter, req *http.Request) {
+	hj, ok := rw.(http.Hijacker)
+	if !ok {
+		rw.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	client, _, err := hj.Hijack()
+	if err != nil {
+		rw.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	remote, err := net.Dial("tcp", req.URL.Host)
+	if err != nil {
+		http.Error(rw, "Failed", http.StatusBadRequest)
+		client.Close()
+		return
+	}
+	client.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
+
+	go tcp.Join(remote, client)
+}
+
+func (hp *HttpProxy) Auth(rw http.ResponseWriter, req *http.Request) bool {
+	if hp.AuthUser == "" && hp.AuthPasswd == "" {
+		return true
+	}
+
+	s := strings.SplitN(req.Header.Get("Proxy-Authorization"), " ", 2)
+	if len(s) != 2 {
+		return false
+	}
+
+	b, err := base64.StdEncoding.DecodeString(s[1])
+	if err != nil {
+		return false
+	}
+
+	pair := strings.SplitN(string(b), ":", 2)
+	if len(pair) != 2 {
+		return false
+	}
+
+	if pair[0] != hp.AuthUser || pair[1] != hp.AuthPasswd {
+		return false
+	}
+	return true
+}
+
+func copyHeaders(dst, src http.Header) {
+	for key, values := range src {
+		for _, value := range values {
+			dst.Add(key, value)
+		}
+	}
+}
+
+func removeProxyHeaders(req *http.Request) {
+	req.RequestURI = ""
+	req.Header.Del("Proxy-Connection")
+	req.Header.Del("Connection")
+	req.Header.Del("Proxy-Authenticate")
+	req.Header.Del("Proxy-Authorization")
+	req.Header.Del("TE")
+	req.Header.Del("Trailers")
+	req.Header.Del("Transfer-Encoding")
+	req.Header.Del("Upgrade")
+}
diff --git a/utils/net/conn.go b/utils/net/conn.go
index c085fe71..5f172bca 100644
--- a/utils/net/conn.go
+++ b/utils/net/conn.go
@@ -46,11 +46,11 @@ type WrapReadWriteCloserConn struct {
 }
 
 func (conn *WrapReadWriteCloserConn) LocalAddr() net.Addr {
-	return nil
+	return (*net.TCPAddr)(nil)
 }
 
 func (conn *WrapReadWriteCloserConn) RemoteAddr() net.Addr {
-	return nil
+	return (*net.TCPAddr)(nil)
 }
 
 func (conn *WrapReadWriteCloserConn) SetDeadline(t time.Time) error {