Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
restic plugin for Caddy
example.com
# specifying an empty root is not strictly necessary but not a bad
# idea if all you are serving on this site is the backups
root empty_www/
# authentication is required when using the Caddy plugin;
# this line assumes all requests are protected
basicauth / user pass
# enable restic for all requests, and store repos in /mnt/backup
restic / /home/matt/mybackups
# All valid restic syntaxes:
#
# restic
# This enables restic for all requests and uses the default data path
#
# restic /backups
# This enables restic for all requests to /backups with default data path
#
# restic /backups /datapath
# This enables restic for all requests to /backups and stores data in /datapath
package restic
import (
"net/http"
"strings"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
type ResticHandler struct {
Next httpserver.Handler
BasePath string
RestServerMux http.Handler
}
func (h ResticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if !httpserver.Path(r.URL.Path).Matches(h.BasePath) {
return h.Next.ServeHTTP(w, r)
}
// basic auth is required (some authentication is required, for obvious reasons)
basicAuthUser, ok := r.Context().Value(httpserver.RemoteUserCtxKey).(string)
if !ok || basicAuthUser == "" {
return http.StatusForbidden, nil
}
// strip the base path from the request so that the restic mux can load
// the repo relative to its Config.Path base path.
r.URL.Path = strings.TrimPrefix(r.URL.Path, h.BasePath)
if !strings.HasPrefix(r.URL.Path, "/") {
r.URL.Path = "/" + r.URL.Path
}
// TODO: this doesn't return values so errors may not be handled properly. Oh well.
h.RestServerMux.ServeHTTP(w, r)
return 0, nil
}
package restic
import (
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
restserver "github.com/restic/rest-server"
)
func init() {
caddy.RegisterPlugin("restic", caddy.Plugin{
ServerType: "http",
Action: setup,
})
}
func setup(c *caddy.Controller) error {
var basePath string
for c.Next() {
if c.NextArg() {
basePath = c.Val()
}
if c.NextArg() {
restserver.Config.Path = c.Val()
}
if c.NextArg() {
return c.ArgErr()
}
}
if basePath == "" {
basePath = "/"
}
cfg := httpserver.GetConfig(c)
mid := func(next httpserver.Handler) httpserver.Handler {
return ResticHandler{
Next: next,
BasePath: basePath,
RestServerMux: restserver.NewMux(),
}
}
cfg.AddMiddleware(mid)
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.