diff --git a/config.go b/config.go
index d76841d..7d6050a 100644
--- a/config.go
+++ b/config.go
@@ -284,7 +284,7 @@ func defaultConfiguration() tConfiguration {
 }
 
 // Load and check the configuration file
-func loadConfiguration(file string) (tConfiguration, error) {
+func LoadConfiguration(file string) (tConfiguration, error) {
 	cfg := defaultConfiguration()
 	cfgData, err := ioutil.ReadFile(file)
 	if err != nil {
diff --git a/main.go b/main.go
index dfc0ca9..195202b 100644
--- a/main.go
+++ b/main.go
@@ -60,7 +60,7 @@ func main() {
 		log.WithField("error", err).Fatal("Failed to configure logging.")
 	}
 
-	cfg, err := loadConfiguration(flags.cfgFile)
+	cfg, err := LoadConfiguration(flags.cfgFile)
 	if err != nil {
 		log.WithField("error", err).Fatal("Failed to load initial configuration.")
 	}
@@ -69,32 +69,32 @@ func main() {
 	if err != nil {
 		log.WithField("error", err).Fatal("Failed to initialize socket.")
 	}
-	listener.Close()
-
-	conn := NewLdapConnection(cfg.LdapConfig)
-	if conn == nil {
-		return
-	}
-	defer conn.Close()
-	for i := range cfg.Certificates {
-		builder := NewCertificateBuilder(conn, &cfg.Certificates[i])
-		err := builder.Build()
-		if err != nil {
-			log.WithField("error", err).Error("Failed to build data for certificate '", cfg.Certificates[i].Path, "'")
-			continue
-		}
-		if builder.MustWrite() {
-			err := builder.WriteFile()
+	defer listener.Close()
+	for {
+		cmd := socketServer(&cfg, listener)
+		if cmd == CMD_QUIT {
+			break
+		} else if cmd == CMD_RELOAD {
+			new_cfg, err := LoadConfiguration(flags.cfgFile)
 			if err != nil {
-				log.WithField("error", err).Error("Failed to write '", cfg.Certificates[i].Path, "'")
-				continue
+				log.WithField("error", err).Error("Failed to load updated configuration.")
+			} else {
+				replace_ok := true
+				if new_cfg.Socket.Path != cfg.Socket.Path {
+					new_listener, err := initSocket(new_cfg.Socket)
+					if err != nil {
+						log.WithField("error", err).Error("Failed to initialize new server socket.")
+						replace_ok = false
+					} else {
+						listener.Close()
+						listener = new_listener
+					}
+				}
+				if replace_ok {
+					cfg = new_cfg
+					log.Info("Configuration reloaded")
+				}
 			}
 		}
-		err = builder.UpdatePrivileges()
-		if err != nil {
-			log.WithField("error", err).Error("Failed to update privileges on '", cfg.Certificates[i].Path, "'")
-			continue
-		}
-		builder.RunCommandsIfChanged()
 	}
 }
diff --git a/socket.go b/socket.go
index 5e8e078..81a668e 100644
--- a/socket.go
+++ b/socket.go
@@ -6,8 +6,27 @@ import (
 	"os"
 	"os/user"
 	"strconv"
+	"time"
+	"unicode/utf8"
+
+	"github.com/sirupsen/logrus"
 )
 
+type TCommandType int
+
+const (
+	CMD_IGNORE TCommandType = iota
+	CMD_QUIT
+	CMD_RELOAD
+	CMD_UPDATE
+)
+
+type TCommand struct {
+	CommandType TCommandType
+	Force       bool
+	Selector    string
+}
+
 func configureSocket(cfg tSocketConfig) error {
 	if cfg.Group != "" {
 		group, err := user.LookupGroup(cfg.Group)
@@ -47,3 +66,119 @@ func initSocket(cfg tSocketConfig) (net.Listener, error) {
 	log.WithField("path", cfg.Path).Info("UNIX socket created")
 	return listener, nil
 }
+
+func socketServer(cfg *tConfiguration, listener net.Listener) TCommandType {
+	for {
+		fd, err := listener.Accept()
+		if err != nil {
+			log.WithField("error", err).Fatal("Error while waiting for connections.")
+		}
+		cmd := executeFromSocket(cfg, fd)
+		if cmd != CMD_IGNORE {
+			return cmd
+		}
+	}
+}
+
+func executeFromSocket(cfg *tConfiguration, conn net.Conn) TCommandType {
+	defer conn.Close()
+	log.Debug("Received connection")
+
+	buf := make([]byte, 512)
+	conn.SetReadDeadline(time.Now().Add(1 * time.Second))
+	n, err := conn.Read(buf)
+	if err != nil {
+		log.WithField("error", err).Error("Could not read from socket")
+		return CMD_IGNORE
+	}
+	command := parseCommand(n, buf)
+	if command == nil {
+		return CMD_IGNORE
+	}
+	if command.CommandType == CMD_UPDATE {
+		log.WithFields(logrus.Fields{
+			"force":    command.Force,
+			"selector": command.Selector,
+		}).Info("Update request received")
+		success := executeUpdate(cfg, command)
+		conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
+		var bval byte
+		if success {
+			bval = '1'
+		} else {
+			bval = '0'
+		}
+		conn.Write([]byte{bval})
+		return CMD_IGNORE
+	}
+	return command.CommandType
+}
+
+func parseCommand(n int, buf []byte) *TCommand {
+	if n == 512 {
+		log.Warn("Too much data received")
+		return nil
+	}
+	if n == 0 {
+		log.Warn("Not enough data received")
+		return nil
+	}
+	if n == 1 {
+		if buf[0] == 'Q' {
+			return &TCommand{CommandType: CMD_QUIT}
+		} else if buf[0] == 'R' {
+			return &TCommand{CommandType: CMD_RELOAD}
+		}
+	} else if n > 2 && buf[0] == 'U' {
+		res := &TCommand{CommandType: CMD_UPDATE}
+		if buf[1] == '!' {
+			res.Force = true
+		}
+		if utf8.Valid(buf[2:]) {
+			res.Selector = string(buf[2:n])
+			return res
+		}
+	}
+	log.Warn("Invalid command received")
+	return nil
+}
+
+func executeUpdate(cfg *tConfiguration, cmd *TCommand) bool {
+	conn := NewLdapConnection(cfg.LdapConfig)
+	if conn == nil {
+		return false
+	}
+	defer conn.Close()
+
+	had_errors := false
+	for i := range cfg.Certificates {
+		// TODO apply selector
+		builder := NewCertificateBuilder(conn, &cfg.Certificates[i])
+		err := builder.Build()
+		if err != nil {
+			log.WithField("error", err).Error("Failed to build data for certificate '", cfg.Certificates[i].Path, "'")
+			had_errors = true
+			continue
+		}
+		if builder.MustWrite() || cmd.Force {
+			err := builder.WriteFile()
+			if err != nil {
+				log.WithField("error", err).Error("Failed to write '", cfg.Certificates[i].Path, "'")
+				had_errors = true
+				continue
+			}
+		}
+		err = builder.UpdatePrivileges()
+		if err != nil {
+			log.WithField("error", err).Error("Failed to update privileges on '", cfg.Certificates[i].Path, "'")
+			had_errors = true
+			continue
+		}
+		err = builder.RunCommandsIfChanged()
+		if err != nil {
+			log.WithField("error", err).Error("Failed to run commands after update of '", cfg.Certificates[i].Path, "'")
+			had_errors = true
+		}
+	}
+	return !had_errors
+}