# skip it and install from npm or docker

npm install -g traefik-jam

yarn global add traefik-jam

pnpm add -g traefik-jam

# or

npx traefik-jam ./data/acme.json example.net github.com

# or

docker run --rm -it \
    -v $PWD/data/acme.json:/acme.json \
    -v $PWD/certs:/opt/app/certs \
    jojobyte/traefik-jam -- ./data/acme.json example.net github.com
tl;dr

Traefik & Let's Encrypt are a great and easy solution to generate SSL/TLS certificates automatically for websites and API endpoints, however to re-use the generated certificates within those endpoints it becomes a bit more tricky.

The top search engine results to resolve this issue are mostly Python scripts. But sometimes Node.js is just easier to work with, especially if you're already using it.

So, here is a little script to export the certificates in acme.json to individual PEM files.

#!/usr/bin/env node

import fs from 'node:fs'
import path from 'node:path'
import url from 'node:url'


/**
 * Read certificates from acme.json with optional filter
 *
 * @example
 *   // all certs in file
 *   exportCerts('./acme.json')
 *
 *   // only certs for github.com in file
 *   exportCerts('./acme.json', 'github.com')
 *
 *   // save certs to `certificates/` dir
 *   exportCerts('./acme.json', null, 'certificates/')
 *
 * @param {string} file path to acme.json
 * @param {string} [search=null] for this domain
 * @param {string} [outputDir='certs/'] output directory for certificates
 *
 * @void
 */
export async function exportCerts(
  file,
  search = null,
  outputDir = 'certs/'
) {
  console.info('export traefik certs for domain:', search)

  let data = JSON.parse((
      await fs.promises.readFile(
          file === '.' ? `${file}/acme.json` : file
      )
  ).toString()).Certificates

  if (!data) {
    return
  }

  if (search !== null) {
    data = data.filter(v => v.Domain.Main.includes(search))
  }

  data.forEach(async ({ Certificate, Key, Domain }) => {
    let d = Domain.Main.replace('*.', '_.')

    const [cf] = await save(`${d}.crt`, Certificate, outputDir)
    const [kf] = await save(`${d}.key`, Key, outputDir)

    console.info(`saved ${Domain.Main}`, [cf, kf])
  })
}

/**
 * Save file
 *
 * @example
 *   let [filepath, dir] = save('./foobar.txt', 'foo', 'data/')
 *   // filepath === './data/foobar.txt'
 *   // dir === './data'
 *
 * @param {string} file Name of file to save
 * @param {string} data Data to save to file
 * @param {string} [outputDir='certs/'] Directory to output files
 *
 * @returns {[string,string]} File path and output directory
 */
export async function save(file, data, outputDir = 'certs/') {
  const fp = path.join(outputDir, file)

  fs.mkdirSync(outputDir, { recursive: true })

  await fs.createWriteStream(fp).write(
    Buffer.from(data, 'base64').toString()
  )

  return [fp, outputDir]
}

/**
 * Filter based on domains from Array | CLI Args
 *
 * @example
 *   cmd('./acme.json', ['foo','bar'])
 *   // e.g. given `traefik-jam ./acme.json foo bar`
 *   // targetDomains === ['foo', 'bar']
 *
 * @param {string} acmeFile Path to acme.json file
 * @param {string[]} targetDomains Array of domain strings to find
 *
 * @void
 */
export function cmd(
  acmeFile = process.argv[2] || './data/acme.json',
  targetDomains = process.argv.slice(3) || [],
) {
  if (targetDomains?.length > 0) {
    targetDomains.forEach(domain => exportCerts(acmeFile, domain))
  } else {
    exportCerts(acmeFile)
  }
}

export default exportCerts

if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
  cmd()
}
File: exportCerts.mjs

Just provide the exportCerts function an acme.json file and it will handle base64 decoding and saving the certificates to PEM (.key/.crt) files.

Here's a few usage examples:

# Convert all certificates in `data/acme.json`

node exportCerts.mjs

# or with optional domain search arguments

node exportCerts.mjs example.com thisonedoesntexist.net

# or, thanks to the shebang `#!/usr/bin/env node` at the top of the file

./exportCerts.mjs github.com example.net
Shell / CLI Example
GitHub - jojobyte/traefikjam: A tiny (zero dependency) Node.js CLI utility to convert Traefik Let’s Encrypt certificates from acme.json to PEM files
A tiny (zero dependency) Node.js CLI utility to convert Traefik Let's Encrypt certificates from acme.json to PEM files - GitHub - jojobyte/traefikjam: A tiny (zero dependency) Node.js CLI utili...
GitHubjojobyte
traefikjam
A tiny (zero dependency) Node.js CLI utility to convert Traefik Let’s Encrypt certificates from acme.json to PEM files. Latest version: 0.0.1, last published: 25 minutes ago. Start using traefikjam in your project by running `npm i traefikjam`. There are no other projects in the npm registry using t…
npm
Docker Hub
Docker Hub: jojobyte/traefikjam