Skip to content

Instantly share code, notes, and snippets.

@ergosteur
Created April 23, 2025 01:03
Show Gist options
  • Save ergosteur/34a60e4c3c22a1ee399ee15e19026326 to your computer and use it in GitHub Desktop.
Save ergosteur/34a60e4c3c22a1ee399ee15e19026326 to your computer and use it in GitHub Desktop.
Automated Let’s Encrypt on MikroTik via acme.sh Container

Automated Let’s Encrypt on MikroTik via acme.sh Container

(in 13 lucky steps)


This guide shows how to run acme.sh in a RouterOS container on your USB drive, use Cloudflare DNS‑01, and deploy certs via SSH to RouterOS automatically.

0. Initial Docker Configuration

Configure RouterOS container engine paths:

/container config
set layer-dir=usb1-part1/container-layers/ \
    registry-url=https://registry.hub.docker.com \
    tmpdir=usb1-part1/container-tmp \
    username=yourusername

1. Create Host Directories

Create folders on USB for state and SSH keys:

/file add type=directory name=usb1-part1/container-volumes/acme_sh_data
/file add type=directory name=usb1-part1/container-volumes/ssh_keys

2. Define Container Mounts

Note: src= paths must not start with /.

/container mounts
add name=acme_sh_data dst=/acme.sh src=usb1-part1/container-volumes/acme_sh_data
add name=ssh_keys     dst=/root/.ssh src=usb1-part1/container-volumes/ssh_keys

3. Set Environment Variables

Add Cloudflare and RouterOS deploy‑hook vars:

/container envs
add list=ACME_ENV name=CF_Token           value="0123456789abcdef012345"
add list=ACME_ENV name=CF_Email           value="[email protected]"
add list=ACME_ENV name=ROUTER_OS_USERNAME value="certuser"
add list=ACME_ENV name=ROUTER_OS_HOST     value="10.13.1.1"
add list=ACME_ENV name=ROUTER_OS_PORT     value="22"

4. Configure veth Interface & Bridge

Attach the container to your LAN bridge:

/interface veth add name=veth13.10 address=10.13.1.10/24 gateway=10.13.1.1
/interface bridge port add bridge=bridge-LAN interface=veth13.10

Ensure veth13.10 is in the same bridge as your LAN so it can reach Cloudflare and SSH to RouterOS.


5. Create the acme.sh Container

Add the container, telling it to run in daemon mode:

/container add name=acme_sh \
    remote-image=neilpang/acme.sh:latest \
    hostname=acme_sh interface=veth13.10 \
    mounts=acme_sh_data,ssh_keys \
    envlist=ACME_ENV \
    logging=yes start-on-boot=no \
    root-dir=usb1-part1/container/acme_sh \
    entrypoint="/entrypoint.sh" \
    cmd="daemon"

6. Generate SSH Key Inside Container

/container shell [find hostname="acme_sh"]
# Inside container:
ssh-keygen -t ed25519 -f /root/.ssh/id_rsa -N ""
exit

This creates /root/.ssh/id_rsa (private) and id_rsa.pub (public) in the ssh_keys volume.


7. Set Default CA to Let’s Encrypt

Before issuing any certificates, configure acme.sh in the container to use the official Let’s Encrypt CA:

/container shell [find hostname="acme_sh"]
/entry.sh --set-default-ca --server letsencrypt
exit

8. Create RouterOS User & Import Public Key

# On MikroTik CLI:
/user add name=certuser password="" group=full comment="LE automation user"
/user ssh-keys import user=certuser public-key-file=usb1-part1/container-volumes/ssh_keys/id_rsa.pub

Verify with:

/user ssh-keys print

9. Test SSH From Container

/container shell [find hostname="acme_sh"]
ssh -o StrictHostKeyChecking=no [email protected] 'echo SSH OK'
exit

You should see SSH OK.


10. Issue Initial Certificate

Temporarily update the container command to issue certs for your domains:

/container set acme_sh cmd="--issue --dns dns_cf --keylength 4096 \
  -d lan.example.com \
  -d gw.lan.example.com \
  -d dynamic.example.com \
  -d dynamic.contoso.com \
  --deploy-hook routeros"
/container start acme_sh
/container log show where container=acme_sh

Watch for a successful issuance and deployment.


11. Switch to Auto‑Renew Mode

/container set acme_sh cmd="--cron --deploy-hook routeros"

12. Automate with Scheduler

Create a RouterOS scheduler to run daily at 03:00 and then stop the container:

/system scheduler add name="LE-Renew" start-time=03:00:00 interval=24h \
    on-event="/container start acme_sh; :delay 300; /container stop acme_sh"
  • :delay 300 allows 5 minutes for renewal & deploy.

13. Post‑Deploy Sanity Checks

After an auto‑run, verify on the Router:

/certificate print detail where common-name~"lan.example.com"
/ip service print where name=www-ssl

From a LAN host, test HTTPS:

curl -v https://lan.example.com/ --insecure

Once trusted, drop --insecure.

Notes

  • The --issue command is a one‑time action.
  • Keep volumes organized under container-volumes/.
  • Ensure your SSH keys and ACME data persist on USB.

You now have a fully automated Let’s Encrypt setup running on your MikroTik, using Cloudflare DNS‑01 and a RouterOS container. 🚀

@ergosteur
Copy link
Author

The full initial container setup isn't documented here as I had done it previously, and the documentation is available on the Web. I wanted to document the Let's Encrypt using a Cloudflare DNS-01 challenge in full since I couldn't find a complete working step-by-step guide for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment