The caddy storage command provides subcommands for working with Caddy’s storage, allowing you to export and import storage contents like TLS certificates and ACME data.
EXPERIMENTAL: This command may be changed or removed in future versions.
Usage
caddy storage <subcommand> [flags]
Description
Allows exporting and importing Caddy’s storage contents. The storage contains:
- TLS certificates (from ACME or loaded files)
- ACME account data (account keys, registration info)
- ACME challenge data (for DNS and other challenges)
- OCSP staples and other TLS-related data
This is useful for:
- Migrating between storage backends
- Backing up certificates and keys
- Transferring data between servers
- Switching storage configurations
When importing to or exporting from file_system storage (the default), the command should be run as the user that owns the associated root path.
Subcommands
export
Exports storage assets as a tarball.
caddy storage export --config <path> --output <path>
import
Imports storage assets from a tarball.
caddy storage import --config <path> --input <path>
Combining Export and Import
The two commands can be combined in a pipeline to transfer directly from one storage to another:
caddy storage export --config Caddyfile.old --output - | \
caddy storage import --config Caddyfile.new --input -
The - argument refers to stdout and stdin, respectively.
Export Flags
Input configuration file (required).The storage configuration will be extracted from this config.
Output path for the tarball (required).Use - for stdout (useful for piping).
Import Flags
Configuration file to load (required).The storage configuration will be extracted from this config.
Path to tarball to import (required).Use - for stdin (useful for piping).
Examples
Export to file
caddy storage export --config Caddyfile --output backup.tar
Creates backup.tar containing all storage assets.
Import from file
caddy storage import --config Caddyfile --input backup.tar
Restores storage assets from backup.tar.
Export to stdout
caddy storage export --config Caddyfile --output -
Writes tarball to stdout (useful for piping or compression).
Import from stdin
cat backup.tar | caddy storage import --config Caddyfile --input -
Compress backup
caddy storage export --config Caddyfile --output - | gzip > backup.tar.gz
Restore from compressed backup
gunzip -c backup.tar.gz | caddy storage import --config Caddyfile --input -
Transfer between servers
# On source server
caddy storage export --config Caddyfile --output - | \
ssh user@destination 'caddy storage import --config /etc/caddy/Caddyfile --input -'
Migrate storage backends
Old config using file storage:
# Caddyfile.old
{
storage file_system {
root /var/lib/caddy/old
}
}
New config using different storage:
# Caddyfile.new
{
storage file_system {
root /var/lib/caddy/new
}
}
Migrate:
caddy storage export --config Caddyfile.old --output - | \
caddy storage import --config Caddyfile.new --input -
Backup before upgrade
# Create backup
caddy storage export --config /etc/caddy/Caddyfile --output ~/caddy-backup-$(date +%Y%m%d).tar
# Upgrade Caddy
sudo apt update && sudo apt upgrade caddy
# If something goes wrong, restore
# caddy storage import --config /etc/caddy/Caddyfile --input ~/caddy-backup-YYYYMMDD.tar
Exit Codes
0 - Success
1 - Failed startup (invalid config or missing flags)
2 - Failed quit (error during export/import)
What Gets Exported
The export includes all “terminal” keys from the storage:
- Certificates -
certificates/acme/.../*.crt
- Private keys -
certificates/acme/.../*.key
- Account keys -
acme/.../*.json
- OCSP staples - Various cached data
- Locks (if present at export time)
The exact structure depends on your storage backend and ACME usage.
The export creates a standard tar archive:
# List contents
tar -tf backup.tar
# Extract to inspect
mkdir inspect
tar -xf backup.tar -C inspect
ls -R inspect
Example contents:
certificates/acme/acme-v02.api.letsencrypt.org-directory/example.com/example.com.crt
certificates/acme/acme-v02.api.letsencrypt.org-directory/example.com/example.com.key
acme/acme-v02.api.letsencrypt.org-directory/users/...
Storage Backends
Caddy supports different storage backends:
File System (default)
{
storage file_system {
root /var/lib/caddy
}
}
Consul
{
storage consul {
address "localhost:8500"
prefix "caddy"
}
}
Redis
{
storage redis {
address "localhost:6379"
prefix "caddy"
}
}
{
storage s3 {
bucket "my-caddy-storage"
region "us-east-1"
}
}
Migrating Between Storage Types
File System → Consul
# Export from file system
caddy storage export --config Caddyfile.fs --output certs.tar
# Import to Consul
caddy storage import --config Caddyfile.consul --input certs.tar
Consul → File System
caddy storage export --config Caddyfile.consul --output certs.tar
caddy storage import --config Caddyfile.fs --input certs.tar
Caveats
- Keys are removed during export if they’re deleted from storage while export is in progress (warning will be logged)
- Permissions matter for file_system storage - run as the correct user
- Storage must be configured in the config file for both export and import
- Concurrent access during export may lead to inconsistent state
Best Practices
1. Stop Caddy during migration
sudo systemctl stop caddy
caddy storage export --config /etc/caddy/Caddyfile --output backup.tar
# ... change storage config ...
caddy storage import --config /etc/caddy/Caddyfile --input backup.tar
sudo systemctl start caddy
2. Verify backup integrity
# Create backup
caddy storage export --config Caddyfile --output backup.tar
# Verify it's a valid tar
tar -tf backup.tar > /dev/null
if [ $? -eq 0 ]; then
echo "Backup is valid"
fi
3. Regular backups
#!/bin/bash
# backup-caddy-storage.sh
BACKUP_DIR="/backups/caddy"
mkdir -p "$BACKUP_DIR"
caddy storage export \
--config /etc/caddy/Caddyfile \
--output "$BACKUP_DIR/caddy-storage-$(date +%Y%m%d-%H%M%S).tar"
# Keep only last 7 days
find "$BACKUP_DIR" -name 'caddy-storage-*.tar' -mtime +7 -delete
4. Encrypt sensitive backups
# Export and encrypt
caddy storage export --config Caddyfile --output - | \
gpg --encrypt --recipient [email protected] > backup.tar.gpg
# Decrypt and import
gpg --decrypt backup.tar.gpg | \
caddy storage import --config Caddyfile --input -
Troubleshooting
Permission errors
Error: opening output file: permission denied
Run as the correct user or use sudo:
sudo -u caddy caddy storage export --config /etc/caddy/Caddyfile --output backup.tar
If the config doesn’t specify storage, Caddy uses file_system storage with default paths. Make sure your config is complete.
Empty export
If export produces an empty or very small tarball:
- Check that certificates exist in storage
- Verify storage path is correct
- Ensure ACME has issued certificates