LabCA runs a private ACME certificate authority on your own network
A private Certificate Authority for internal (lab) use, based on the open source ACME Automated Certificate Management Environment implementation from Let's Encrypt (tm).
At a glance
- What is it?
- LabCA packages the Let's Encrypt Boulder engine into a self-contained docker compose stack with a web GUI, so lab networks can issue trusted TLS certificates without a publicly reachable server. The trade-off is a hard dependency on DNS, docker and a machine that is not a Raspberry Pi.
- Who is it for?
- LabCA fits teams that run internal services and want clients to stop seeing self-signed warnings, and it fits developers testing ACME integrations without touching Let's Encrypt rate limits. It does not fit a Raspberry Pi, an IP-only host, or a deployment that needs certificates for public domain names.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 107 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
LabCA turns Boulder into a GUI you can operate from a browser
The problem LabCA addresses is not certificate cryptography, it is certificate distribution inside a closed network. Public HTTPS is cheap because Let's Encrypt will sign anything that can prove control of a domain name, but that proof usually needs a publicly reachable address, which an intranet service cannot offer. Teams running their own PKI by hand get certificates without automation. LabCA sits between those two situations. It is built on the open source ACME implementation from Let's Encrypt, the engine called Boulder, and it ships as one installation with a web interface where ordinary management tasks are done.
That framing matters for the intended reader. This is a homelab and lab tool, aimed at people who want browsers on an internal network to show a trusted lock rather than a self-signed warning, and at developers who need a local ACME server while building an ACME client. It is not a general purpose certificate authority for the public internet, and it does not try to be one. The web GUI sits in front of Boulder, so the underlying protocol and challenge machinery are the upstream ones, while the operational surface is the browser pages LabCA adds on top.
Every LabCA host needs a name in local DNS, not just an IP address
The single most important constraint is stated twice in the documentation, once as a note and once as a startup instruction. The hostname of the LabCA machine must be resolvable in a local DNS, because the Boulder engine needs that name to hand out a certificate for it. Running LabCA on an IP address only is not possible, and the project says plainly that there must be a DNS mapping present.
This is where the ACME model meets an internal network. The HTTP-01 challenge type needs the client and the server to exchange information at a reachable location, and the DNS-01 method exists as an alternative. On a public server that location is the domain itself. In a lab, DNS is what makes the same mechanism work, since the name resolves inside the organisation even though nothing routes to it from the internet.
The practical consequence is that a LabCA deployment has a dependency outside the container stack itself. Name resolution has to exist before the certificate flow can complete, and it has to keep existing for renewal. The documentation also notes a second hardware limit, since LabCA depends on the boulder engine, which cannot run on a Raspberry Pi. That excludes the single-board computers many homelab builds start with, and it means the stack needs a real server or virtual machine.
Starting the stack with docker compose and LABCA_FQDN
Installation assumes docker with the compose plugin. On Ubuntu or Debian machines the documentation suggests installing the docker packages first:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-pluginAfter that the repository is cloned and the compose stack is started from the build directory. The one thing you must do before starting is export LABCA_FQDN with the fully qualified name you will type in the browser:
git clone https://github.com/hakwerk/labca.git
cd labca/build
export LABCA_FQDN=labca.example.com
docker compose up -dThe value you export is the same name your clients will use, and it is the name that must already resolve through DNS. Once the containers run, the setup continues in the browser, and the documentation points to a sequence of screenshots for the wizard. When something goes wrong, the logs are the place to look:
docker compose logs -fAll persistent data lives in docker volumes, which the documentation says you should include in your regular backups. That sentence is easy to skim and expensive to ignore later, since the root and issuer certificates are only as recoverable as whatever you copied off the machine.
The entrypoint.sh error is really a missing environment variable
LabCA ships a diagnostic worth knowing, because the error text points at a file rather than at the cause. After a compose start you may see:
Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "labca/entrypoint.sh": stat labca/entrypoint.sh: no such file or directory: unknownThe message reads like a broken image or a bad volume mapping. It is neither. The documentation explains that the entrypoint path is assembled from configuration, and that this specific error appears when LABCA_FQDN was never exported in the shell that ran the compose command. The fix is to export the variable and start the stack again.
This is a fair summary of how LabCA treats configuration. There is one required variable, and the failure mode for omitting it is an opaque container runtime error rather than a clear message from the application. Any team automating this deployment should set LABCA_FQDN explicitly in the environment of the compose process, in a wrapper script or a service unit, rather than relying on an interactive shell where the export happened to be typed once.
Pinning LABCA_IMAGE_VERSION beats riding the latest tag
By default the compose file starts the latest tagged LabCA docker images, so a plain restart can move you to a different version than the one you tested. The documentation offers two update paths, and the choice between them is the main operational decision you make about upgrades.
The automatic path pulls new latest images, restarting the stack and pruning old ones:
cd build
docker compose down
git pull
docker compose pull
docker compose up -d --remove-orphans
docker image pruneThe same section points at watchtower for automatic image updates and Diun for notifications when new images appear. The controlled path sets LABCA_IMAGE_VERSION to an explicit version number, and the documentation suggests doing that in a .env file placed next to docker-compose.yml.
For a certificate authority, the controlled path is the safer one, because a certificate authority holds keys that clients already trust. A surprise change of image during a restart means new signing behaviour on a component whose old certificates remain valid for some time. Pinning also makes the upgrade cost legible: you choose the moment, you keep the old image available for rollback, and the .env file becomes the record of what ran.
Root and issuer certificates have to leave the server by hand
The setup wizard ends with an instruction that is easy to treat as routine admin: back up the Root and Issuer certificates, because they can be exported from the Certificates tab of the Manage page. The Backup tab can create a backup of the relevant server data, and the documentation notes that backup files should be synchronised to an external location, though it leaves that out of scope.
The reason to care is the trust model. A client trusts LabCA because it trusts the root you hand it, and you hand it out yourself. If that root is lost or rotated without a plan, every certificate issued under it becomes a problem on the machines that already trusted it, and recovery means re-trusting a new root across the estate. Exporting from the Certificates tab early, and storing the export somewhere the LabCA server cannot wipe, is what separates a recoverable incident from a rebuild.
The repository layout also suggests where the operational scripts live, with top-level entries for backup, restore, renew, checkrenew, checkcrl, checkpkimetal, commander and control.sh. Those names describe a tool that expects recurring scheduled work around certificate renewal and expiry, which is another reason to treat the backup step as part of setup rather than as a later cleanup.
Where LabCA is the wrong tool, and what the standalone build changes
LabCA fails on three specific fronts. It cannot run on a Raspberry Pi, because the boulder engine will not. It cannot run on an IP address without a DNS mapping. And it does not serve the public internet case, since the whole point of a local CA is that clients inside the network already trust it.
For a different internal approach, the repository carries a standalone version for step-ca and a legacy mode, each with its own README file at the top level. The Makefile shows how that variant is produced, with a build that sets a standaloneVersion value through linker flags and compiles with a standalone build tag:
LDFLAGS := -ldflags='-w -X "main.standaloneVersion=$(FULLVERSION)" -extldflags "-static"' -tags standaloneSo the same project offers a choice between its Boulder based stack with a built in GUI and a lighter standalone build aimed at step-ca, where the step-ca instance supplies the certificate authority and the LabCA code provides the management interface. The difference in approach is real: the Boulder based stack is the project's own ACME server, while the standalone build points a different engine, step-ca, at the same management problem. Anyone comparing them should check which one the surrounding tooling and documentation assume, because the configuration and the trust bootstrap differ between the two paths.
Maintenance here is modest and recent. The last push was on 2026-07-08, and recent releases include v26.04 on 2026-04-09, v26.03.1 on 2026-03-20 and v26.03 on 2026-03-11. The licence is not one GitHub can classify, and the repository ships it as LICENSE.txt, so anyone considering LabCA for anything beyond a lab should read that file rather than assume an open source grant.
Editorial conclusion
LabCA fits teams that run internal services and want clients to stop seeing self-signed warnings, and it fits developers testing ACME integrations without touching Let's Encrypt rate limits. It does not fit a Raspberry Pi, an IP-only host, or a deployment that needs certificates for public domain names. Before adopting it, confirm that the host resolves in local DNS, that clients will accept a root certificate you distribute yourself, and that your backups capture the root and issuer certificates exported from the Certificates tab before the first renewal cycle.
Frequently asked questions
What is LabCA and who is it for?
LabCA is a private certificate authority for internal and lab use, built on the open source Boulder ACME implementation from Let's Encrypt and shipped with a web GUI for management. It suits homelab and lab networks that want clients to trust internal TLS certificates without a publicly reachable ACME endpoint.
How do I install LabCA and what does it require?
Install docker with the compose plugin, clone the repository, cd into the build directory, export LABCA_FQDN with a fully qualified domain name and run docker compose up -d. The host must resolve in a local DNS, an IP address alone will not do, and the boulder engine cannot run on a Raspberry Pi.
How do I back up and update LabCA?
All data sits in docker volumes that should be part of your regular backups, and the root and issuer certificates can be exported from the Certificates tab of the Manage page. By default the latest image tags are used, and you can pin a specific version with the LABCA_IMAGE_VERSION environment variable in a .env file next to docker-compose.yml.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hakwerk-labca)Was this useful?