A lightweight, Docker-based Private Certificate Authority (CA) designed for home labs and internal networks. This project uses step-ca to provide secure, automated HTTPS certificates for your internal services (e.g., *.lan, *.internal) without relying on the public internet or external hardware.
- Software-Only: Runs entirely in Docker. No YubiKeys or HSMs required.
- Automated: ACME protocol support for seamless integration with Traefik, Caddy, or Nginx.
- Private: Complete control over your PKI. Keys never leave your network.
- Simple: Easy to bootstrap and backup.
- Web UI: Modern dashboard to download Root CA and view registered domains.
tinyca/
βββ docker-compose.yml # Service definition
βββ nginx/
β βββ conf.d/ # Nginx configuration
β βββ html/ # Web UI (index.html, styles.css, app.js)
βββ secrets/
β βββ password # Password for CA keys (PROTECT THIS FILE)
βββ step-ca-data/ # Persistent storage (Database, Config, Keys)
βββ scripts/
β βββ ensure_acme.sh # Helper to manually enable ACME (legacy)
β βββ init_acme.sh # Automated ACME initialization script
β βββ renew_certs.sh # Script for Nginx auto-renewal
βββ README.md # This documentation
- Docker & Docker Compose installed.
- Linux environment (Ubuntu/Debian/Raspberry Pi) or WSL2 on Windows.
curlandstepCLI (optional but recommended for clients).
CRITICAL: Change the default password before starting.
echo "SangatRahasiaBanget" > secrets/password
chmod 600 secrets/passwordWarning
DO NOT change this file after initialization!
The keys in step-ca-data are encrypted with this password. If you change the text file later without re-encrypting the keys, step-ca will fail to start.
To change the password later, you must manually re-encrypt the keys using the step CLI.
docker compose up -dCheck logs to ensure it initialized successfully:
docker compose logs -fWait for "Serving HTTPS on :9000 ...".
The updated docker-compose.yml includes an acme-init service that automatically attempts to add the ACME provisioner. You can check its logs:
docker compose logs acme-initFungsi dari service acme-init adalah untuk mengotomatiskan konfigurasi agar step-ca bisa berfungsi seperti Let's Encrypt.
Berikut detailnya: Menambahkan Fitur ACME: Secara default, saat baru diinstall, step-ca belum mengaktifkan protokol ACME (protokol yang dipakai oleh Certbot/Traefik). acme-init menjalankan perintah step ca provisioner add acme secara otomatis agar Anda tidak perlu mengetiknya manual.
We have included a Web UI served by Nginx (www.tinyca.lan) that automatically gets a certificate.
- Add
127.0.0.1 www.tinyca.lanto your hosts file. - Visit
https://www.tinyca.lanin your browser.- If you installed the Root CA (see below), it should be Secure!
- You can download the Root CA certificate directly from the UI.
- View all registered domains and their certificate status.
To change the Organization (O), Organizational Unit (OU), or Validity (e.g. 90 days or 365 days):
- Needs to restart the whole stack (to update provisioner config).
- Edit
scripts/renew_certs.sh. - Change the variables at the top of the issuance section:
ORG_NAME="TinyCA" ORG_UNIT="IT-Internal" VALIDITY="2160h" # 90 days. Use "8760h" for 1 year.
- Delete the existing certs (
rm -rf certs-data/*) or wait for renewal. - Restart:
docker compose up -d.
To create a wildcard certificate (e.g., valid for db.tinyca.lan, app.tinyca.lan):
Note: ACME (Certbot) usually requires DNS challenges for wildcards, which is difficult for local .lan domains without a proper DNS server. Use the manual method:
-
Run inside the container (easiest way):
docker exec -it step-ca step ca certificate "*.tinyca.lan" /home/step/wildcard.crt /home/step/wildcard.key --provisioner admin
It will ask for your CA password.
-
Copy the files out:
docker cp step-ca:/home/step/wildcard.crt . docker cp step-ca:/home/step/wildcard.key .
To use certificates on other servers (e.g. 192.168.1.100):
- Install Certbot:
sudo apt install certbot -y
- Request Certificate:
sudo certbot certonly --standalone \ --server https://tinyca.lan:9000/acme/acme/directory \ -d myserver.lan
If you need to change the password in secrets/password, you MUST re-encrypt the private keys. If you don't do this, the CA will not start.
Steps:
-
Stop the CA:
docker compose down
-
Re-encrypt Keys (Run this for both Root and Intermediate keys):
# For Root Key docker run --rm -it -v "${PWD}/secrets:/secrets" smallstep/step-cli step crypto change-pass /secrets/root_ca_key # For Intermediate Key docker run --rm -it -v "${PWD}/secrets:/secrets" smallstep/step-cli step crypto change-pass /secrets/intermediate_ca_key
You will be asked for the OLD password, then the NEW password.
-
Update Password File: Update the
secrets/passwordfile with your NEW password. -
Start CA:
docker compose up -d
Existing certificates (Root CA on clients, issued certs) remain valid.
For your devices (laptops, servers) to trust certificates issued by this CA, you must install the Root CA Certificate.
From any client machine on the network:
# Replace tinyca.lan with your Docker host's IP if DNS isn't set up yet
curl -k https://tinyca.lan:9000/root.crt -o root_ca.crtsudo cp root_ca.crt /usr/local/share/ca-certificates/tinyca.crt
sudo update-ca-certificates- Double-click
root_ca.crt. - Click "Install Certificate".
- Select "Local Machine".
- Place in "Trusted Root Certification Authorities".
- Open Keychain Access.
- Drag
root_ca.crtinto System keychain. - Double-click it, expand Trust, and set "When using this certificate" to Always Trust.
Use this for services like Nginx, Traefik, or any ACME-compatible server.
ACME Directory URL: https://tinyca.lan:9000/acme/acme/directory
# Note: Since this is internal, use --standalone if port 80 is available,
# or ensure 'grafana.lan' resolves to the machine running certbot.
sudo certbot certonly --standalone \
--server https://tinyca.lan:9000/acme/acme/directory \
-d grafana.lanGreat for testing or one-off static services.
# 1. Bootstrap the client (one time)
step ca bootstrap --ca-url https://tinyca.lan:9000 --fingerprint <ROOT_FINGERPRINT>
# 2. Issue Token & Cert
step ca certificate grafana.lan grafana.crt grafana.keyTip: You can find the fingerprint in the docker compose logs startup banner.
This project prioritizes availability and simplicity. Keys are stored on disk (step-ca-data) encrypted by your password (secrets/password).
- Risk: If someone steals your server's hard drive and the password file, they can forge certificates.
- Mitigation:
- Keep the server secure.
- Use a strong password.
Back up the step-ca-data folder regularly. This contains your:
- Root CA Key (Encrypted)
- Intermediate CA Key (Encrypted)
- Database of issued certificates
tar -czvf ca-backup.tar.gz step-ca-data/ secrets/Client says "Certificate signed by unknown authority"
- You missed the "Establishing Trust" step on that client.
ACME fails with connection refused
- Ensure
tinyca.lanresolves to the CA's IP address. - Ensure port 9000 is reachable through firewalls.
- If using
step-cain Docker, ensurenetwork_mode: hostor port 9000 is mapped.
Container crashes on start
- Check permissions of
secrets/password. The container user (UID 1000) must be able to read it. - Check if you changed the password file without re-encrypting the keys.