SSL Certificate Management & Private CA
1.5K
Certo is a self-hosted, open-source SSL Certificate Management and Certificate Authority (CA) tool built with Python and Flask.
Designed for internal teams, developers, and DevOps who need a lightweight, private CA they control.
KeyUsage, ExtendedKeyUsage (serverAuth + clientAuth), SubjectKeyIdentifier, AuthorityKeyIdentifierfullchain.pem generated and kept up to date on reissueadmin (full access) and user (SSL management only)data/rootca/, data/ssl/)robots.txt endpoint is served at /robots.txt which disallows all user agents and sets a short crawl delay.X-Robots-Tag: noindex, nofollow header (see app.py).<meta name="robots" content="noindex, nofollow"> tag (see templates/layout.html).robots.txt handler or the @app.after_request hook in app.py, or modify templates/layout.html to remove the meta tag. You can also serve a custom static robots.txt from the static/ directory if preferred.On first startup, if no users exist in the database, a default admin account is created:
| Username | Password |
|---|---|
admin | certo |
Change the password immediately after first login.
No setup required. Just run:
docker-compose up -d
Then open http://<your-host>:8080 in your browser.
A secure SECRET_KEY is automatically generated on first start and persisted in the data volume — sessions survive container restarts.
To use a custom key, create a .env file before starting:
SECRET_KEY=your-long-random-string-here
docker run -d \
-p 8080:8080 \
--name certo \
-v certo_data:/app/data \
bhatol/certo:latest
| Variable | Required | Default | Description |
|---|---|---|---|
SECRET_KEY | No | Auto-generated | Flask session signing key. Auto-created and persisted in the data volume if not set. |
GUNICORN_WORKERS | No | 2 | Number of Gunicorn worker processes |
All data is stored in the certo_data Docker named volume at /app/data — the SQLite database, Root CA files, and SSL certificate files. Back up this volume to preserve your data.
# Backup
docker run --rm -v certo_data:/data -v $(pwd):/backup alpine \
tar czf /backup/certo_data_backup.tar.gz -C /data .
# Restore
docker run --rm -v certo_data:/data -v $(pwd):/backup alpine \
tar xzf /backup/certo_data_backup.tar.gz -C /data
docker-compose pull
docker-compose up -d
Data is in a named volume and is not affected by image updates.
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
python app.py
App runs at http://0.0.0.0:8080.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
.\install.ps1
certo/
├── app.py # Flask app — all routes and logic
├── utils/
│ ├── db.py # SQLite connection and schema init
│ └── precheck.py # Startup checks, cert generation, DB seed
├── templates/ # Jinja2 HTML templates
├── static/ # Bootstrap CSS/JS, favicon (bundled, no CDN)
├── data/ # Runtime data (gitignored, Docker volume)
│ ├── app.db # SQLite database
│ ├── rootca/ # Root CA cert and key files
│ └── ssl/ # SSL cert, key, fullchain, and meta files
├── Dockerfile
├── docker-compose.yml
├── docker-entrypoint.sh # Runs precheck then starts Gunicorn
├── generate_env.sh # Optional: generates .env with a custom SECRET_KEY
└── requirements.txt
Content type
Image
Digest
sha256:b5bf94201…
Size
86.3 MB
Last updated
6 months ago
docker pull bhatol/certo