Skip to main content
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

--config
string
required
Input configuration file (required).The storage configuration will be extracted from this config.
--output
string
required
Output path for the tarball (required).Use - for stdout (useful for piping).

Import Flags

--config
string
required
Configuration file to load (required).The storage configuration will be extracted from this config.
--input
string
required
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.

Tarball Format

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"
    }
}

S3

{
    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

Storage not configured

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

Build docs developers (and LLMs) love