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

  1. Check the exact path in the wrapped error and run `ls -ld` on each parent — fix ownership with chown to the user running Caddy
  2. Make sure no path component is a file: `rm` it if it blocks the directory
  3. Give the volume write access (docker: not :ro; k8s: remove readOnly: true) and confirm disk space with `df -h`
  4. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/f538866b3c4b1b13. Report an issue: GitHub.