Migration from an existing LetsEncrypt setup

I saw Migrating to Caddy with existing LetsEncrypt certs which is already closed without a real solution for me. I would really like to re-use existing keys to not bother clients. is that possible? isnt it just a copy of the existing certs, keys, … into the right place? i did not find any documentation about how caddy stores certs, so i could not figure out where to copy them.

this seems to be the structure:

./
β”œβ”€β”€ acme/
β”‚   β”œβ”€β”€ acme-staging-v02.api.letsencrypt.org-directory/
β”‚   β”‚   β”œβ”€β”€ challenge_tokens/
β”‚   β”‚   └── users/
β”‚   β”‚       └── default/
β”‚   β”‚           β”œβ”€β”€ default.json
β”‚   β”‚           └── default.key
β”‚   └── acme-v02.api.letsencrypt.org-directory/
β”‚       β”œβ”€β”€ challenge_tokens/
β”‚       └── users/
β”‚           └── default/
β”‚               β”œβ”€β”€ default.json
β”‚               └── default.key
β”œβ”€β”€ certificates/
β”‚   └── acme-v02.api.letsencrypt.org-directory/
β”‚       └── <domain>/
β”‚           β”œβ”€β”€ <domain>.crt
β”‚           β”œβ”€β”€ <domain>.json
β”‚           └── <domain>.key
β”œβ”€β”€ instance.uuid
β”œβ”€β”€ last_clean.json
└── locks/

problem might be to create the correct .json files. i assume caddy cant produce those from existing files.

Correct, not without some help, since where it gets the certs from could be anything, so I don’t think we can simply infer this information:

{
        "sans": [
                "caddyserver.com"
        ],
        "issuer_data": {
                "url": "https://acme-v02.api.letsencrypt.org/acme/cert/0511c4442ef72e3dfc960207473148a06a47",
                "ca": "https://acme-v02.api.letsencrypt.org/directory",
                "account": "https://acme-v02.api.letsencrypt.org/acme/acct/12345",
                "renewal_info": {
                        "suggestedWindow": {
                                "start": "2026-04-14T22:08:49Z",
                                "end": "2026-04-16T17:19:39Z"
                        },
                        "_uniqueIdentifier": "jw0TovYuftFDcDMYOF1YjiNykco.ARRERC73Lm38lgIHRzFIoGo2",
                        "_retryAfter": "2026-03-25T17:33:06.204182485Z",
                        "_selectedTime": "2026-04-15T15:34:24Z"
                }
        }
}

A custom script would probably have to fill this in.

It’s not all strictly required but I’m not sure what the behavioral guarantees would be with some information missing or incorrect.

We could explore β€œadopting” existing certs+keys without a metadata file, but this would probably require a Business-tier sponsorship or higher to sufficiently test and support.

1 Like

Why would that matter to clients? Unless you’re developing somekind of app that specifically does key pinning, this won’t matter. All that’s important is that the private key is secret and proven to be under control of the entity controlling the domain, which is what ACME automation proves.

Cert issuance takes seconds at most, so you’re best off just spinning up Caddy and letting it issue a cert at startup and not worry about migrating anything.

1 Like

i consider it a bad habit for a server to change its key with no good reason. a client should always do pinning in that regards and warn the user. but that may be a personal attitude most people wont follow…