https://github.com/unclefi1/step-ca-ui
Self-hosted web UI for Smallstep step-ca β manage your private PKI from a browser
https://github.com/unclefi1/step-ca-ui
certificate-authority docker docker-compose golang pki self-hosted smallstep ssl step-ca tls web-ui
Last synced: 8 days ago
JSON representation
Self-hosted web UI for Smallstep step-ca β manage your private PKI from a browser
- Host: GitHub
- URL: https://github.com/unclefi1/step-ca-ui
- Owner: UncleFi1
- License: gpl-3.0
- Created: 2026-04-17T19:30:09.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-25T19:58:53.000Z (9 days ago)
- Last Synced: 2026-05-25T21:32:09.088Z (9 days ago)
- Topics: certificate-authority, docker, docker-compose, golang, pki, self-hosted, smallstep, ssl, step-ca, tls, web-ui
- Language: HTML
- Homepage:
- Size: 246 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Step-CA UI
**Self-hosted web interface for [Smallstep step-ca](https://smallstep.com/docs/step-ca/) β manage your private PKI from a browser.**
[](https://www.gnu.org/licenses/gpl-3.0)
[](https://go.dev)
[](https://docs.docker.com/compose/)
[](https://github.com/UncleFi1/step-ca-ui/releases/latest)
π¬π§ **English** Β· [π·πΊ Π ΡΡΡΠΊΠΈΠΉ](README.ru.md)
---
> A small-team-friendly web UI on top of `smallstep/step-ca`. No SaaS, no telemetry, no vendor lock-in β runs entirely on your own server in three Docker containers.
## Features
- π **Certificate management** β issue, renew, revoke and import X.509 certificates
- π₯ **Role-based access** β `admin` / `manager` / `viewer`
- β±οΈ **Temporary users** β short-lived guest accounts with automatic expiration *(new in v1.4.0)*
- π
**Custom date picker** β site-themed, no native browser widget *(new in v1.4.0)*
- π **Timezone-aware** β configurable with the `TZ` environment variable
- π¨ **4 themes** β dark, light, blue, auto (follows OS)
- π§ **Admin workspace** β polished admin UI with matching dark, light and blue themes *(new in v1.4.11)*
- π‘οΈ **Built-in security** β CSRF tokens, rate limiting, IP blocking, security log
- π **Provisioner inspection** β list and edit step-ca provisioners
- πΎ **Backup export** β admin UI and CLI backup bundles with manifest checksums *(new in v1.4.9)*
## Quick Start
```bash
git clone https://github.com/UncleFi1/step-ca-ui.git
cd step-ca-ui
sudo ./install.sh
```
The installer can run in Russian or English and supports both clean installs and
safe updates:
```bash
sudo ./install.sh --mode install --lang en
sudo ./install.sh --mode update --lang en
```
Update mode creates a backup first, preserves `.env` and Docker volumes, then
runs `docker compose up -d --build`. It does not run `docker compose down -v`.
That's it. The installer:
1. Detects your OS and installs Docker if needed
2. Auto-detects your server IP (with confirmation)
3. Generates strong passwords for everything
4. Writes `.env` and `credentials.txt` (chmod 600)
5. Builds and starts the containers
6. Prints the URL and admin password
The whole thing takes 2β4 minutes on a fresh VM.
## Requirements
| | Minimum | Recommended | High-load |
|----------------|---------|-------------|-----------|
| **CPU** | 1 vCPU | 2 vCPU | 4+ vCPU |
| **RAM** | 1 GB | 2 GB | 4+ GB |
| **Disk** | 5 GB | 20 GB SSD | 50+ GB NVMe |
| **Network** | 10 Mbit/s | 100 Mbit/s | 1 Gbit/s |
| **Users** | up to 50 | up to 500 | 500+ |
| **Certificates**| up to 500 | up to 10k | 10k+ |
**Software:**
- Linux kernel 4.4+ (Ubuntu 20.04+, Debian 11+, CentOS Stream 9+, Rocky 9+, Alma 9+)
- Docker Engine 20.10+ with Compose plugin v2+
- Open ports: `443/tcp` (HTTPS UI), optionally `9000/tcp` (step-ca API)
> Untested but should work: macOS / Windows via Docker Desktop (development only). \
> **Not supported:** shared hosting without Docker, Raspberry Pi Zero (insufficient RAM).
## Stack
| Layer | Technology |
|--------------|-----------------------------|
| Backend | Go 1.22, [chi](https://github.com/go-chi/chi) router |
| Frontend | Server-rendered HTML + vanilla JS, no build step |
| Database | PostgreSQL 16 |
| CA | [smallstep/step-ca](https://hub.docker.com/r/smallstep/step-ca) |
| Deploy | Docker Compose |
| Container OS | Alpine 3.19 + tzdata |
## Architecture
```
ββββββββββββββ
Browser βββ HTTPS ββββΊβ step-ui β Go web app, port 8443
β (chi) β
ββββ¬ββββββ¬ββββ
β β
SQL ββββββββ ββββββββΊ HTTPS API
β β
ββββΌβββ ββΌβββββββββββ
β pg β β step-ca β port 9000
β 16 β β (PKI) β
βββββββ βββββββββββββ
step-ui exposes :443 β internally redirects to :8443
step-ca exposes :9000 β internal-only by default
```
## Roles
| Role | View | Issue/Import | Revoke | Manage Users |
|---------|------|--------------|--------|--------------|
| viewer | β
| β | β | β |
| manager | β
| β
| β | β |
| admin | β
| β
| β
| β
|
**Temporary users** can have any role; they're auto-blocked when `expires_at` passes (a goroutine checks every minute).
## Security
- β
**CSRF protection** β tokens on every form and server-side checks on POST routes
- β
**Rate limiting** β 5 failed login attempts β 15-minute IP block
- β
**Security headers** β CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, optional HSTS
- β
**Session timeout** β 8 hours, sliding
- β
**Login audit log** β every login attempt is recorded with IP and User-Agent
- β
**Self-signed TLS** β auto-generated on first boot, 10-year validity
- β
**Password hashing** β bcrypt for new/updated passwords, with transparent migration from legacy SHA-256 hashes on next successful login
> π **Production tip:** put step-ui behind a reverse proxy (Caddy/nginx) with a real TLS certificate, restrict access via VPN/Tailscale, and back up the `step-ca-data` volume regularly.
## Configuration
All configuration lives in `.env`. The installer creates this file for you, but you can edit it manually:
```env
HOST_IP=192.168.1.100 # SAN in self-signed cert; step-ca DNS
UI_HTTPS_PORT=443 # external HTTPS port
PROVISIONER=admin # step-ca provisioner identifier
CA_PASSWORD= # step-ca provisioner password
SECRET_KEY= # session/CSRF signing key
SESSION_SECURE=true # secure session cookie over HTTPS
ENABLE_HSTS=false # enable only when using a trusted TLS certificate
POSTGRES_PASSWORD= # database password
TZ=UTC # container timezone
STEPCA_DEFAULT_TLS_CERT_DURATION=8760h
STEPCA_MAX_TLS_CERT_DURATION=87600h
```
After changing `.env`, recreate the containers:
```bash
sudo docker compose up -d --force-recreate
```
## FAQ
How do I change the HTTPS port from 443?
Edit `docker-compose.yml`:
```yaml
services:
step-ui:
ports:
- "8443:8443" # was "443:8443"
```
Then restart: `sudo docker compose up -d --force-recreate step-ui`.
How do I back up and restore the data?
Use the admin UI: `Admin -> Backup -> Download backup bundle`.
CLI export is also supported:
```bash
sudo ./install.sh --mode backup --lang en
```
Backups include PostgreSQL, `step-ca-data`, Step-CA UI data/certs/uploads and
`manifest.json` with SHA-256 checksums. Restore is manual by design; follow
[BACKUP_RESTORE.md](BACKUP_RESTORE.md).
How do I reset the admin password?
```bash
sudo docker compose exec postgres psql -U stepui -d stepui -c \
"UPDATE users SET password_hash = encode(sha256('newpass'::bytea), 'hex') WHERE username='admin';"
```
Then log in with `admin` / `newpass` and change it from the UI.
The legacy SHA-256 reset value is accepted for recovery and is rehashed to bcrypt after login.
The browser warns about a self-signed certificate. How do I use my own?
Replace `step-ui-go/ssl/server.crt` and `server.key` with your own cert + key (e.g. from Let's Encrypt or your internal CA), then restart `step-ui`. Make sure the cert covers your `HOST_IP` or hostname.
Can I run this behind Cloudflare / Caddy / nginx?
Yes. Point your reverse proxy at `step-ui:8443` (HTTPS upstream) or change step-ui to plain HTTP and put TLS termination on the proxy. Set `X-Forwarded-Proto: https` so step-ui generates correct URLs.
How do I update to a new version?
```bash
sudo ./install.sh --mode update --lang en
```
The update mode creates a backup first, keeps existing Docker volumes, optionally checks out a selected tag, and runs migrations automatically on startup. Always check the [release notes](https://github.com/UncleFi1/step-ca-ui/releases) first β major versions may have breaking changes.
## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you'd like to change.
```bash
git clone https://github.com/UncleFi1/step-ca-ui.git
cd step-ca-ui/step-ui-go
go mod download
go run . # requires running postgres + step-ca
```
When submitting:
- Run `gofmt -w .` and `go vet ./...`
- Update relevant tests
- Keep commits focused and descriptive
## Project structure
```
.
βββ docker-compose.yml # 3 services: postgres, step-ca, step-ui
βββ .env.example # configuration template
βββ install.sh # one-shot installer
βββ LICENSE # GPL-3.0
βββ README.md # this file (English)
βββ README.ru.md # Russian translation
βββ step-ui-go/
βββ main.go # entry point, router setup
βββ config/ # env-based config loader
βββ db/ # all SQL queries
βββ handlers/ # HTTP handlers (one file per area)
βββ middleware/ # auth, security headers, CSRF
βββ models/ # data structs
βββ security/ # password hashing, rate limiting, CSRF
βββ templates/ # HTML templates (Go html/template)
βββ static/ # CSS, JS, favicon, images
βββ Dockerfile # multi-stage Alpine build
βββ entrypoint.sh # waits for deps, generates SSL, starts app
```
## License
This project is licensed under the **GNU General Public License v3.0** β see the [LICENSE](LICENSE) file for details.
In short: you can use, modify, and distribute this software, but any derivative work must also be released under GPLv3.