diff --git a/io/config/json/json.go b/io/config/json/json.go
deleted file mode 100644
index 98735c733..000000000
--- a/io/config/json/json.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Package json contains io library for VConfig in Json format.
-package json
-
-import (
-	"encoding/json"
-	_ "fmt"
-
-	"github.com/v2ray/v2ray-core"
-)
-
-type JsonVUser struct {
-	id    string `json:"id"`
-	email string `json:"email"`
-}
-
-type JsonVConfig struct {
-	Port     uint8       `json:"port"`
-	Clients  []JsonVUser `json:"users"`
-	Protocol string      `json:"protocol"`
-}
-
-type JsonVConfigUnmarshaller struct {
-}
-
-func StringToVUser(id string) (u core.VUser, err error) {
-	return
-}
-
-func (*JsonVConfigUnmarshaller) Unmarshall(data []byte) (*core.VConfig, error) {
-	var jsonConfig JsonVConfig
-	err := json.Unmarshal(data, &jsonConfig)
-	if err != nil {
-		return nil, err
-	}
-	var vconfig = new(core.VConfig)
-	return vconfig, nil
-}
diff --git a/io/socks/socks.go b/io/socks/socks.go
index 2e633ba45..d9cc0e8d1 100644
--- a/io/socks/socks.go
+++ b/io/socks/socks.go
@@ -13,9 +13,10 @@ import (
 const (
 	socksVersion = uint8(5)
 
-	AuthNotRequired = byte(0x00)
-	AuthGssApi      = byte(0x01)
-	AuthUserPass    = byte(0x02)
+	AuthNotRequired      = byte(0x00)
+	AuthGssApi           = byte(0x01)
+	AuthUserPass         = byte(0x02)
+	AuthNoMatchingMethod = byte(0xFF)
 )
 
 // Authentication request header of Socks5 protocol
diff --git a/log/log.go b/log/log.go
index 7c5a7fbb0..45f936214 100644
--- a/log/log.go
+++ b/log/log.go
@@ -28,6 +28,11 @@ func writeLog(data string, level LogLevel) {
 	log.Print(data)
 }
 
+func Debug(format string, v ...interface{}) {
+	data := fmt.Sprintf(format, v)
+	writeLog("[Debug]"+data, DebugLevel)
+}
+
 func Info(format string, v ...interface{}) {
 	data := fmt.Sprintf(format, v)
 	writeLog("[Info]"+data, InfoLevel)
diff --git a/net/freedom/freedom.go b/net/freedom/freedom.go
index 7727c69a6..8d5242229 100644
--- a/net/freedom/freedom.go
+++ b/net/freedom/freedom.go
@@ -10,13 +10,11 @@ import (
 )
 
 type VFreeConnection struct {
-	vPoint *core.VPoint
-	dest   v2net.VAddress
+	dest v2net.VAddress
 }
 
-func NewVFreeConnection(vp *core.VPoint, dest v2net.VAddress) *VFreeConnection {
+func NewVFreeConnection(dest v2net.VAddress) *VFreeConnection {
 	conn := new(VFreeConnection)
-	conn.vPoint = vp
 	conn.dest = dest
 	return conn
 }
diff --git a/net/freedom/freedomfactory.go b/net/freedom/freedomfactory.go
index b07367f99..a9ed27081 100644
--- a/net/freedom/freedomfactory.go
+++ b/net/freedom/freedomfactory.go
@@ -8,6 +8,6 @@ import (
 type FreedomFactory struct {
 }
 
-func (factory FreedomFactory) Create(vp *core.VPoint, dest v2net.VAddress) (core.OutboundConnectionHandler, error) {
-	return NewVFreeConnection(vp, dest), nil
+func (factory FreedomFactory) Create(vp *core.VPoint, config []byte, dest v2net.VAddress) (core.OutboundConnectionHandler, error) {
+	return NewVFreeConnection(dest), nil
 }
diff --git a/net/socks/config.go b/net/socks/config.go
new file mode 100644
index 000000000..4e0d61eb3
--- /dev/null
+++ b/net/socks/config.go
@@ -0,0 +1,22 @@
+package socks
+
+import (
+	"encoding/json"
+)
+
+const (
+	JsonAuthMethodNoAuth   = "noauth"
+	JsonAuthMethodUserPass = "password"
+)
+
+type SocksConfig struct {
+	AuthMethod string `json:"auth"`
+	Username   string `json:"user"`
+	Password   string `json:"pass"`
+}
+
+func loadConfig(rawConfig []byte) (SocksConfig, error) {
+	config := SocksConfig{}
+	err := json.Unmarshal(rawConfig, &config)
+	return config, err
+}
diff --git a/net/socks/socks.go b/net/socks/socks.go
index 7478cb7e2..f4c341319 100644
--- a/net/socks/socks.go
+++ b/net/socks/socks.go
@@ -3,12 +3,12 @@ package socks
 import (
 	"errors"
 	"io"
-	"log"
 	"net"
 	"strconv"
 
 	"github.com/v2ray/v2ray-core"
 	socksio "github.com/v2ray/v2ray-core/io/socks"
+	"github.com/v2ray/v2ray-core/log"
 )
 
 var (
@@ -20,18 +20,24 @@ var (
 type SocksServer struct {
 	accepting bool
 	vPoint    *core.VPoint
+	config    SocksConfig
 }
 
-func NewSocksServer(vp *core.VPoint) *SocksServer {
+func NewSocksServer(vp *core.VPoint, rawConfig []byte) *SocksServer {
 	server := new(SocksServer)
 	server.vPoint = vp
+	config, err := loadConfig(rawConfig)
+	if err != nil {
+		panic(log.Error("Unable to load socks config: %v", err))
+	}
+	server.config = config
 	return server
 }
 
 func (server *SocksServer) Listen(port uint16) error {
 	listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(port)))
 	if err != nil {
-		return err
+		return log.Error("Error on listening port %d: %v", port, err)
 	}
 	server.accepting = true
 	go server.AcceptConnections(listener)
@@ -42,8 +48,7 @@ func (server *SocksServer) AcceptConnections(listener net.Listener) error {
 	for server.accepting {
 		connection, err := listener.Accept()
 		if err != nil {
-			log.Print(err)
-			return err
+			return log.Error("Error on accepting socks connection: %v", err)
 		}
 		go server.HandleConnection(connection)
 	}
@@ -55,14 +60,19 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
 
 	auth, err := socksio.ReadAuthentication(connection)
 	if err != nil {
-		log.Print(err)
-		return err
+		return log.Error("Error on reading authentication: %v", err)
 	}
-	log.Print(auth)
 
-	if !auth.HasAuthMethod(socksio.AuthNotRequired) {
-		// TODO send response with FF
-		log.Print(ErrorAuthenticationFailed)
+	expectedAuthMethod := socksio.AuthNotRequired
+	if server.config.AuthMethod == JsonAuthMethodUserPass {
+		expectedAuthMethod = socksio.AuthUserPass
+	}
+
+	if !auth.HasAuthMethod(expectedAuthMethod) {
+		authResponse := socksio.NewAuthenticationResponse(socksio.AuthNoMatchingMethod)
+		socksio.WriteAuthentication(connection, authResponse)
+
+		log.Info("Client doesn't support allowed any auth methods.")
 		return ErrorAuthenticationFailed
 	}
 
@@ -71,8 +81,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
 
 	request, err := socksio.ReadRequest(connection)
 	if err != nil {
-		log.Print(err)
-		return err
+		return log.Error("Error on reading socks request: %v", err)
 	}
 
 	response := socksio.NewSocks5Response()
@@ -81,7 +90,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
 		response := socksio.NewSocks5Response()
 		response.Error = socksio.ErrorCommandNotSupported
 		socksio.WriteResponse(connection, response)
-		log.Print(ErrorCommandNotSupported)
+		log.Info("Unsupported socks command %d", request.Command)
 		return ErrorCommandNotSupported
 	}
 
@@ -114,7 +123,7 @@ func (server *SocksServer) dumpInput(conn net.Conn, input chan<- []byte, finish
 	for {
 		buffer := make([]byte, 256)
 		nBytes, err := conn.Read(buffer)
-		log.Printf("Reading %d bytes, with error %v", nBytes, err)
+		log.Debug("Reading %d bytes, with error %v", nBytes, err)
 		if err == io.EOF {
 			close(input)
 			finish <- true
@@ -132,7 +141,7 @@ func (server *SocksServer) dumpOutput(conn net.Conn, output <-chan []byte, finis
 			break
 		}
 		nBytes, _ := conn.Write(buffer)
-		log.Printf("Writing %d bytes", nBytes)
+		log.Debug("Writing %d bytes", nBytes)
 	}
 }
 
diff --git a/net/socks/socksfactory.go b/net/socks/socksfactory.go
index 928bb2c74..8c7635676 100644
--- a/net/socks/socksfactory.go
+++ b/net/socks/socksfactory.go
@@ -7,6 +7,6 @@ import (
 type SocksServerFactory struct {
 }
 
-func (factory SocksServerFactory) Create(vp *core.VPoint) (core.InboundConnectionHandler, error) {
-	return NewSocksServer(vp), nil
+func (factory SocksServerFactory) Create(vp *core.VPoint, config []byte) (core.InboundConnectionHandler, error) {
+	return NewSocksServer(vp, config), nil
 }
diff --git a/net/vmess/config.go b/net/vmess/config.go
new file mode 100644
index 000000000..b6c426e6e
--- /dev/null
+++ b/net/vmess/config.go
@@ -0,0 +1,40 @@
+package vmess
+
+import (
+	"encoding/json"
+
+	"github.com/v2ray/v2ray-core"
+	v2net "github.com/v2ray/v2ray-core/net"
+)
+
+type VMessInboundConfig struct {
+	AllowedClients []core.VUser `json:"clients"`
+}
+
+func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) {
+	config := VMessInboundConfig{}
+	err := json.Unmarshal(rawConfig, &config)
+	return config, err
+}
+
+type VNextConfig struct {
+	Address string       `json:"address"`
+	Port    uint16       `json:"port"`
+	Users   []core.VUser `json:"users"`
+}
+
+func (config VNextConfig) ToVNextServer() VNextServer {
+	return VNextServer{
+		v2net.DomainAddress(config.Address, config.Port),
+		config.Users}
+}
+
+type VMessOutboundConfig struct {
+	VNextList []VNextConfig
+}
+
+func loadOutboundConfig(rawConfig []byte) (VMessOutboundConfig, error) {
+	config := VMessOutboundConfig{}
+	err := json.Unmarshal(rawConfig, &config)
+	return config, err
+}
diff --git a/net/vmess/vmessin.go b/net/vmess/vmessin.go
index 3447c1482..9e041040b 100644
--- a/net/vmess/vmessin.go
+++ b/net/vmess/vmessin.go
@@ -8,6 +8,7 @@ import (
 	"github.com/v2ray/v2ray-core"
 	v2io "github.com/v2ray/v2ray-core/io"
 	vmessio "github.com/v2ray/v2ray-core/io/vmess"
+	"github.com/v2ray/v2ray-core/log"
 )
 
 type VMessInboundHandler struct {
@@ -89,6 +90,7 @@ func (handler *VMessInboundHandler) dumpInput(reader io.Reader, input chan<- []b
 		buffer := make([]byte, BufferSize)
 		nBytes, err := reader.Read(buffer)
 		if err == io.EOF {
+			close(input)
 			finish <- true
 			break
 		}
@@ -114,18 +116,16 @@ func (handler *VMessInboundHandler) waitForFinish(finish <-chan bool) {
 }
 
 type VMessInboundHandlerFactory struct {
-	allowedClients *core.VUserSet
 }
 
-func NewVMessInboundHandlerFactory(clients []core.VUser) *VMessInboundHandlerFactory {
-	factory := new(VMessInboundHandlerFactory)
-	factory.allowedClients = core.NewVUserSet()
-	for _, user := range clients {
-		factory.allowedClients.AddUser(user)
+func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte) *VMessInboundHandler {
+	config, err := loadInboundConfig(rawConfig)
+	if err != nil {
+		panic(log.Error("Failed to load VMess inbound config: %v", err))
 	}
-	return factory
-}
-
-func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint) *VMessInboundHandler {
-	return NewVMessInboundHandler(vp, factory.allowedClients)
+	allowedClients := core.NewVUserSet()
+	for _, user := range config.AllowedClients {
+		allowedClients.AddUser(user)
+	}
+	return NewVMessInboundHandler(vp, allowedClients)
 }
diff --git a/net/vmess/vmessout.go b/net/vmess/vmessout.go
index 49c07fc9c..567809321 100644
--- a/net/vmess/vmessout.go
+++ b/net/vmess/vmessout.go
@@ -10,28 +10,37 @@ import (
 	"github.com/v2ray/v2ray-core"
 	v2io "github.com/v2ray/v2ray-core/io"
 	vmessio "github.com/v2ray/v2ray-core/io/vmess"
+	"github.com/v2ray/v2ray-core/log"
 	v2net "github.com/v2ray/v2ray-core/net"
 )
 
-type VMessOutboundHandler struct {
-	vPoint *core.VPoint
-	dest   v2net.VAddress
+// VNext is the next VPoint server in the connection chain.
+type VNextServer struct {
+	Address v2net.VAddress // Address of VNext server
+	Users   []core.VUser   // User accounts for accessing VNext.
 }
 
-func NewVMessOutboundHandler(vp *core.VPoint, dest v2net.VAddress) *VMessOutboundHandler {
+type VMessOutboundHandler struct {
+	vPoint    *core.VPoint
+	dest      v2net.VAddress
+	vNextList []VNextServer
+}
+
+func NewVMessOutboundHandler(vp *core.VPoint, vNextList []VNextServer, dest v2net.VAddress) *VMessOutboundHandler {
 	handler := new(VMessOutboundHandler)
 	handler.vPoint = vp
 	handler.dest = dest
+	handler.vNextList = vNextList
 	return handler
 }
 
 func (handler *VMessOutboundHandler) pickVNext() (v2net.VAddress, core.VUser) {
-	vNextLen := len(handler.vPoint.Config.VNextList)
+	vNextLen := len(handler.vNextList)
 	if vNextLen == 0 {
 		panic("Zero vNext is configured.")
 	}
 	vNextIndex := mrand.Intn(vNextLen)
-	vNext := handler.vPoint.Config.VNextList[vNextIndex]
+	vNext := handler.vNextList[vNextIndex]
 	vNextUserLen := len(vNext.Users)
 	if vNextUserLen == 0 {
 		panic("Zero User account.")
@@ -91,6 +100,7 @@ func (handler *VMessOutboundHandler) dumpOutput(reader io.Reader, output chan<-
 		buffer := make([]byte, BufferSize)
 		nBytes, err := reader.Read(buffer)
 		if err == io.EOF {
+			close(output)
 			finish <- true
 			break
 		}
@@ -118,6 +128,14 @@ func (handler *VMessOutboundHandler) waitForFinish(finish <-chan bool) {
 type VMessOutboundHandlerFactory struct {
 }
 
-func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, destination v2net.VAddress) *VMessOutboundHandler {
-	return NewVMessOutboundHandler(vp, destination)
+func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, rawConfig []byte, destination v2net.VAddress) *VMessOutboundHandler {
+	config, err := loadOutboundConfig(rawConfig)
+	if err != nil {
+		panic(log.Error("Failed to load VMess outbound config: %v", err))
+	}
+	servers := make([]VNextServer, 0, len(config.VNextList))
+	for _, server := range config.VNextList {
+		servers = append(servers, server.ToVNextServer())
+	}
+	return NewVMessOutboundHandler(vp, servers, destination)
 }
diff --git a/release/server/main.go b/release/server/main.go
new file mode 100644
index 000000000..790580777
--- /dev/null
+++ b/release/server/main.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+
+}
diff --git a/release/server/socks/main.go b/release/server/socks/main.go
deleted file mode 100644
index 116f00faa..000000000
--- a/release/server/socks/main.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package main
-
-import (
-	"log"
-
-	"github.com/v2ray/v2ray-core"
-	"github.com/v2ray/v2ray-core/net/freedom"
-	"github.com/v2ray/v2ray-core/net/socks"
-)
-
-func main() {
-	port := uint16(8888)
-
-	uuid := "2418d087-648d-4990-86e8-19dca1d006d3"
-	vid, err := core.UUIDToVID(uuid)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	config := core.VConfig{
-		port,
-		[]core.VUser{core.VUser{vid}},
-		"",
-		[]core.VNext{}}
-
-	vpoint, err := core.NewVPoint(&config, socks.SocksServerFactory{}, freedom.FreedomFactory{})
-	if err != nil {
-		log.Fatal(err)
-	}
-	err = vpoint.Start()
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	finish := make(chan bool)
-	<-finish
-}
diff --git a/vconfig.go b/vconfig.go
index 6d57bf8cc..b8f8a4162 100644
--- a/vconfig.go
+++ b/vconfig.go
@@ -1,32 +1,28 @@
 package core
 
 import (
-	v2net "github.com/v2ray/v2ray-core/net"
+	"encoding/json"
 )
 
 // VUser is the user account that is used for connection to a VPoint
 type VUser struct {
-	Id VID // The ID of this VUser.
+	Id VID `json:"id"` // The ID of this VUser.
 }
 
-// VNext is the next VPoint server in the connection chain.
-type VNext struct {
-	Address v2net.VAddress // Address of VNext server
-	Users   []VUser        // User accounts for accessing VNext.
+type VConnectionConfig struct {
+	Protocol string `json:"protocol"`
+	File     string `json:"file"`
 }
 
 // VConfig is the config for VPoint server.
 type VConfig struct {
-	Port           uint16 // Port of this VPoint server.
-	AllowedClients []VUser
-	ClientProtocol string
-	VNextList      []VNext
+	Port           uint16            `json:"port"` // Port of this VPoint server.
+	InboundConfig  VConnectionConfig `json:"inbound"`
+	OutboundConfig VConnectionConfig `json:"outbound"`
 }
 
-type VConfigMarshaller interface {
-	Marshal(config VConfig) ([]byte, error)
-}
-
-type VConfigUnmarshaller interface {
-	Unmarshal(data []byte) (VConfig, error)
+func LoadVConfig(rawConfig []byte) (VConfig, error) {
+	config := VConfig{}
+	err := json.Unmarshal(rawConfig, &config)
+	return config, err
 }
diff --git a/vpoint.go b/vpoint.go
index de5695c94..5a3fb4506 100644
--- a/vpoint.go
+++ b/vpoint.go
@@ -1,31 +1,76 @@
 package core
 
 import (
-	"fmt"
+	"io/ioutil"
 
+	"github.com/v2ray/v2ray-core/log"
 	v2net "github.com/v2ray/v2ray-core/net"
 )
 
+var (
+	inboundFactories  = make(map[string]InboundConnectionHandlerFactory)
+	outboundFactories = make(map[string]OutboundConnectionHandlerFactory)
+)
+
+func RegisterInboundConnectionHandlerFactory(name string, factory InboundConnectionHandlerFactory) error {
+	// TODO check name
+	inboundFactories[name] = factory
+	return nil
+}
+
+func RegisterOutboundConnectionHandlerFactory(name string, factory OutboundConnectionHandlerFactory) error {
+	// TODO check name
+	outboundFactories[name] = factory
+	return nil
+}
+
 // VPoint is an single server in V2Ray system.
 type VPoint struct {
-	Config     VConfig
+	port       uint16
 	ichFactory InboundConnectionHandlerFactory
+	ichConfig  []byte
 	ochFactory OutboundConnectionHandlerFactory
+	ochConfig  []byte
 }
 
 // NewVPoint returns a new VPoint server based on given configuration.
 // The server is not started at this point.
-func NewVPoint(config *VConfig, ichFactory InboundConnectionHandlerFactory, ochFactory OutboundConnectionHandlerFactory) (*VPoint, error) {
+func NewVPoint(config VConfig) (*VPoint, error) {
 	var vpoint = new(VPoint)
-	vpoint.Config = *config
+	vpoint.port = config.Port
+
+	ichFactory, ok := inboundFactories[config.InboundConfig.Protocol]
+	if !ok {
+		panic(log.Error("Unknown inbound connection handler factory %s", config.InboundConfig.Protocol))
+	}
 	vpoint.ichFactory = ichFactory
+	if len(config.InboundConfig.File) > 0 {
+		ichConfig, err := ioutil.ReadFile(config.InboundConfig.File)
+		if err != nil {
+			panic(log.Error("Unable to read config file %v", err))
+		}
+		vpoint.ichConfig = ichConfig
+	}
+
+	ochFactory, ok := outboundFactories[config.OutboundConfig.Protocol]
+	if !ok {
+		panic(log.Error("Unknown outbound connection handler factory %s", config.OutboundConfig.Protocol))
+	}
+
 	vpoint.ochFactory = ochFactory
+	if len(config.OutboundConfig.File) > 0 {
+		ochConfig, err := ioutil.ReadFile(config.OutboundConfig.File)
+		if err != nil {
+			panic(log.Error("Unable to read config file %v", err))
+		}
+		vpoint.ochConfig = ochConfig
+	}
 
 	return vpoint, nil
 }
 
 type InboundConnectionHandlerFactory interface {
-	Create(vPoint *VPoint) (InboundConnectionHandler, error)
+	Create(vp *VPoint, config []byte) (InboundConnectionHandler, error)
 }
 
 type InboundConnectionHandler interface {
@@ -33,7 +78,7 @@ type InboundConnectionHandler interface {
 }
 
 type OutboundConnectionHandlerFactory interface {
-	Create(vPoint *VPoint, dest v2net.VAddress) (OutboundConnectionHandler, error)
+	Create(VP *VPoint, config []byte, dest v2net.VAddress) (OutboundConnectionHandler, error)
 }
 
 type OutboundConnectionHandler interface {
@@ -43,21 +88,21 @@ type OutboundConnectionHandler interface {
 // Start starts the VPoint server, and return any error during the process.
 // In the case of any errors, the state of the server is unpredicatable.
 func (vp *VPoint) Start() error {
-	if vp.Config.Port <= 0 {
-		return fmt.Errorf("Invalid port %d", vp.Config.Port)
+	if vp.port <= 0 {
+		return log.Error("Invalid port %d", vp.port)
 	}
-	inboundConnectionHandler, err := vp.ichFactory.Create(vp)
+	inboundConnectionHandler, err := vp.ichFactory.Create(vp, vp.ichConfig)
 	if err != nil {
 		return err
 	}
-	err = inboundConnectionHandler.Listen(vp.Config.Port)
+	err = inboundConnectionHandler.Listen(vp.port)
 	return nil
 }
 
 func (vp *VPoint) NewInboundConnectionAccepted(destination v2net.VAddress) InboundVRay {
 	ray := NewVRay()
 	// TODO: handle error
-	och, _ := vp.ochFactory.Create(vp, destination)
+	och, _ := vp.ochFactory.Create(vp, vp.ochConfig, destination)
 	_ = och.Start(ray)
 	return ray
 }