diff --git a/caddy.go b/caddy.go
index c52891af0..568d682f1 100644
--- a/caddy.go
+++ b/caddy.go
@@ -73,10 +73,12 @@ type Instance struct {
 	// servers is the list of servers with their listeners.
 	servers []serverListener
 
-	// these are callbacks to execute when certain events happen
-	onStartup  []func() error
-	onRestart  []func() error
-	onShutdown []func() error
+	// these callbacks execute when certain events occur
+	onFirstStartup  []func() error // starting, not as part of a restart
+	onStartup       []func() error // starting, even as part of a restart
+	onRestart       []func() error // before restart commences
+	onShutdown      []func() error // stopping, even as part of a restart
+	onFinalShutdown []func() error // stopping, not as part of a restart
 }
 
 // Stop stops all servers contained in i. It does NOT
@@ -104,10 +106,11 @@ func (i *Instance) Stop() error {
 	return nil
 }
 
-// shutdownCallbacks executes all the shutdown callbacks of i.
-// An error returned from one does not stop execution of the rest.
-// All the errors will be returned.
-func (i *Instance) shutdownCallbacks() []error {
+// ShutdownCallbacks executes all the shutdown callbacks of i,
+// including ones that are scheduled only for the final shutdown
+// of i. An error returned from one does not stop execution of
+// the rest. All the non-nil errors will be returned.
+func (i *Instance) ShutdownCallbacks() []error {
 	var errs []error
 	for _, shutdownFunc := range i.onShutdown {
 		err := shutdownFunc()
@@ -115,6 +118,12 @@ func (i *Instance) shutdownCallbacks() []error {
 			errs = append(errs, err)
 		}
 	}
+	for _, finalShutdownFunc := range i.onFinalShutdown {
+		err := finalShutdownFunc()
+		if err != nil {
+			errs = append(errs, err)
+		}
+	}
 	return errs
 }
 
@@ -159,6 +168,12 @@ func (i *Instance) Restart(newCaddyfile Input) (*Instance, error) {
 	}
 
 	// success! stop the old instance
+	for _, shutdownFunc := range i.onShutdown {
+		err := shutdownFunc()
+		if err != nil {
+			return i, err
+		}
+	}
 	i.Stop()
 
 	log.Println("[INFO] Reloading complete")
@@ -409,6 +424,15 @@ func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]r
 		return err
 	}
 
+	// run startup callbacks
+	if restartFds == nil {
+		for _, firstStartupFunc := range inst.onFirstStartup {
+			err := firstStartupFunc()
+			if err != nil {
+				return err
+			}
+		}
+	}
 	for _, startupFunc := range inst.onStartup {
 		err := startupFunc()
 		if err != nil {
diff --git a/caddyhttp/errors/errors.go b/caddyhttp/errors/errors.go
index f933adcd1..8d4dd84a0 100644
--- a/caddyhttp/errors/errors.go
+++ b/caddyhttp/errors/errors.go
@@ -29,7 +29,8 @@ type ErrorHandler struct {
 	LogFile    string
 	Log        *log.Logger
 	LogRoller  *httpserver.LogRoller
-	Debug      bool // if true, errors are written out to client rather than to a log
+	Debug      bool     // if true, errors are written out to client rather than to a log
+	file       *os.File // a log file to close when done
 }
 
 func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
diff --git a/caddyhttp/errors/setup.go b/caddyhttp/errors/setup.go
index 36ef74d55..2b3b6dafd 100644
--- a/caddyhttp/errors/setup.go
+++ b/caddyhttp/errors/setup.go
@@ -49,11 +49,10 @@ func setup(c *caddy.Controller) error {
 			}
 			if handler.LogRoller != nil {
 				file.Close()
-
 				handler.LogRoller.Filename = handler.LogFile
-
 				writer = handler.LogRoller.GetLogWriter()
 			} else {
+				handler.file = file
 				writer = file
 			}
 		}
@@ -62,6 +61,14 @@ func setup(c *caddy.Controller) error {
 		return nil
 	})
 
+	// When server stops, close any open log file
+	c.OnShutdown(func() error {
+		if handler.file != nil {
+			handler.file.Close()
+		}
+		return nil
+	})
+
 	httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
 		handler.Next = next
 		return handler
diff --git a/caddyhttp/log/log.go b/caddyhttp/log/log.go
index e266f84f5..4d2f85037 100644
--- a/caddyhttp/log/log.go
+++ b/caddyhttp/log/log.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"log"
 	"net/http"
+	"os"
 
 	"github.com/mholt/caddy"
 	"github.com/mholt/caddy/caddyhttp/httpserver"
@@ -67,6 +68,7 @@ type Rule struct {
 	Format     string
 	Log        *log.Logger
 	Roller     *httpserver.LogRoller
+	file       *os.File // if logging to a file that needs to be closed
 }
 
 const (
diff --git a/caddyhttp/log/setup.go b/caddyhttp/log/setup.go
index ddb39da6d..8cdad9f85 100644
--- a/caddyhttp/log/setup.go
+++ b/caddyhttp/log/setup.go
@@ -43,6 +43,7 @@ func setup(c *caddy.Controller) error {
 					rules[i].Roller.Filename = rules[i].OutputFile
 					writer = rules[i].Roller.GetLogWriter()
 				} else {
+					rules[i].file = file
 					writer = file
 				}
 			}
@@ -53,6 +54,16 @@ func setup(c *caddy.Controller) error {
 		return nil
 	})
 
+	// When server stops, close any open log files
+	c.OnShutdown(func() error {
+		for _, rule := range rules {
+			if rule.file != nil {
+				rule.file.Close()
+			}
+		}
+		return nil
+	})
+
 	httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
 		return Logger{Next: next, Rules: rules, ErrorFunc: httpserver.DefaultErrorFunc}
 	})
diff --git a/controller.go b/controller.go
index 3c25e4879..890534f9b 100644
--- a/controller.go
+++ b/controller.go
@@ -54,8 +54,14 @@ func (c *Controller) ServerType() string {
 	return c.instance.serverType
 }
 
+// OnFirstStartup adds fn to the list of callback functions to execute
+// when the server is about to be started NOT as part of a restart.
+func (c *Controller) OnFirstStartup(fn func() error) {
+	c.instance.onFirstStartup = append(c.instance.onFirstStartup, fn)
+}
+
 // OnStartup adds fn to the list of callback functions to execute
-// when the server is about to be started.
+// when the server is about to be started (including restarts).
 func (c *Controller) OnStartup(fn func() error) {
 	c.instance.onStartup = append(c.instance.onStartup, fn)
 }
@@ -67,11 +73,17 @@ func (c *Controller) OnRestart(fn func() error) {
 }
 
 // OnShutdown adds fn to the list of callback functions to execute
-// when the server is about to be shut down..
+// when the server is about to be shut down (including restarts).
 func (c *Controller) OnShutdown(fn func() error) {
 	c.instance.onShutdown = append(c.instance.onShutdown, fn)
 }
 
+// OnFinalShutdown adds fn to the list of callback functions to execute
+// when the server is about to be shut down NOT as part of a restart.
+func (c *Controller) OnFinalShutdown(fn func() error) {
+	c.instance.onFinalShutdown = append(c.instance.onFinalShutdown, fn)
+}
+
 // Context gets the context associated with the instance associated with c.
 func (c *Controller) Context() Context {
 	return c.instance.context
diff --git a/sigtrap.go b/sigtrap.go
index 7acdbc491..ed7dc803a 100644
--- a/sigtrap.go
+++ b/sigtrap.go
@@ -72,7 +72,7 @@ func allShutdownCallbacks() []error {
 	var errs []error
 	instancesMu.Lock()
 	for _, inst := range instances {
-		errs = append(errs, inst.shutdownCallbacks()...)
+		errs = append(errs, inst.ShutdownCallbacks()...)
 	}
 	instancesMu.Unlock()
 	return errs
diff --git a/startupshutdown/startupshutdown.go b/startupshutdown/startupshutdown.go
index 0a14e0c82..908a4f9cc 100644
--- a/startupshutdown/startupshutdown.go
+++ b/startupshutdown/startupshutdown.go
@@ -15,12 +15,12 @@ func init() {
 
 // Startup registers a startup callback to execute during server start.
 func Startup(c *caddy.Controller) error {
-	return registerCallback(c, c.OnStartup)
+	return registerCallback(c, c.OnFirstStartup)
 }
 
 // Shutdown registers a shutdown callback to execute during server stop.
 func Shutdown(c *caddy.Controller) error {
-	return registerCallback(c, c.OnShutdown)
+	return registerCallback(c, c.OnFinalShutdown)
 }
 
 // registerCallback registers a callback function to execute by