caddyserver/caddy · error
making folder for CA database: %v
Error message
making folder for CA database: %v
What it means
Returned by openDatabase when os.MkdirAll cannot create the ACME server's database folder under the app data dir ($AppDataDir/acme_server/<key>). This is an environment error — the process lacks permission, the path exists as a file, or the disk is full/read-only. It occurs inside a sync.OnceVec/databasePool LoadOrNew, so it surfaces as the provisioning error for acme_server.
Source
Thrown at modules/caddypki/acmeserver/acmeserver.go:285
}
}
if err != nil {
if c := ash.logger.Check(zapcore.ErrorLevel, "closing CA database"); c != nil {
c.Write(zap.String("db_key", key), zap.Error(err))
}
}
return err
}
func (ash Handler) openDatabase() (*db.AuthDB, error) {
key := ash.getDatabaseKey()
database, loaded, err := databasePool.LoadOrNew(key, func() (caddy.Destructor, error) {
dbFolder := filepath.Join(caddy.AppDataDir(), "acme_server", key)
dbPath := filepath.Join(dbFolder, "db")
err := os.MkdirAll(dbFolder, 0o755)
if err != nil {
return nil, fmt.Errorf("making folder for CA database: %v", err)
}
dbConfig := &db.Config{
Type: "bbolt",
DataSource: dbPath,
}
database, err := db.New(dbConfig)
return databaseCloser{&database}, err
})
if loaded {
if c := ash.logger.Check(zapcore.DebugLevel, "loaded preexisting CA database"); c != nil {
c.Write(zap.String("db_key", key))
}
}
return database.(databaseCloser).DB, err
}View on GitHub (pinned to 50e54ee279)
Solutions
- Check the exact path in the wrapped error and run `ls -ld` on each parent — fix ownership with chown to the user running Caddy
- Make sure no path component is a file: `rm` it if it blocks the directory
- Give the volume write access (docker: not :ro; k8s: remove readOnly: true) and confirm disk space with `df -h`
- If using a custom data dir, set XDG_DATA_HOME consistently across restarts so the same folder is reused
Example fix
# before sudo caddy run --config Caddyfile # data dir created as root systemctl start caddy # runs as caddy user # after sudo chown -R caddy:caddy ~/.local/share/caddy systemctl start caddy
Defensive patterns
Strategy: validation
Validate before calling
// Verify the data dir is creatable/writable before enabling acme_server:
func checkDataDir() error {
dir := filepath.Join(caddy.AppDataDir(), "acme_server")
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("cannot create %s: %w", dir, err)
}
return nil
} Prevention
- Own the data dir: run Caddy as the same user that created ~/.local/share/caddy
- In containers, mount the data dir writable and size it adequately
- Add a readiness probe that touches a file under the data dir
When it happens
Trigger: Caddy runs as an unprivileged user but XDG_DATA_HOME/~/.local/share/caddy is owned by root; the path component `acme_server` exists as a regular file; container with a read-only or full volume at the data dir; SELinux/AppArmor denying writes.
Common situations: systemd unit with DynamicUser or wrong User= after data was created by root during initial testing; Kubernetes emptyDir mounted read-only by mistake; Docker volume with wrong uid ownership (`chown 1000:1000` needed).
Related errors
- configuring ACME DB: %v
- loading trusted root CA's PEM file: %s: %v
- checking if default Caddyfile exists: %v
- reading default Caddyfile: %v
- reading environment file: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/f538866b3c4b1b13.
Report an issue: GitHub.