A Docker-based web application for creating TLS/SSL Certificate Signing Requests (CSR) with a clean, modern UI. No OpenSSL knowledge required.
- CSR & Private Key Generation – Create private key and CSR in one step
- Standard Certificates – Single domain certificates
- Multi-Domain (SAN) – Multiple domains in a single certificate
- Wildcard Certificates –
*.domain.comfor all subdomains - Windows Export Formats – Export as
PFX,P12,CER(DER/PEM), andP7B - Chain Support – Optional intermediate/chain certificate upload for PFX/P12/P7B
- Encrypted Key Support – Optional private key password input during export
- CSR / Certificate Inspector – View contents of CSR and certificate files
- Inspector Drag & Drop – Drop
.pem/.csr/.crt/.cerfiles directly into the inspector - One-Click Reset – Reset CSR generation form and results to defaults after download
- Built-in Format Guide – In-app help for IIS/RDP/MMC/Java use-cases
- Key Size Selection – 2048 or 4096 bit
- Dark Mode – Easy on the eyes
- Security First – Private keys are never stored on the server
| Component | Technology |
|---|---|
| Backend | Python 3.12, Flask |
| Cryptography | Python cryptography library |
| WSGI Server | Gunicorn |
| Frontend | Vanilla HTML / CSS / JS |
| Container | Docker |
git clone https://github.com/nycon/csrgen.git
cd csrgen
docker compose up -d --buildOpen http://localhost:8443 in your browser.
If your system does not support docker compose yet, use:
docker-compose up -d --buildcd /Users/$USER/git/csrgen
docker compose up -d --build
open http://localhost:8443Install Docker Desktop for macOS:
- Download from https://www.docker.com/products/docker-desktop/
- Open the
.dmgfile and drag Docker to Applications - Launch Docker Desktop and wait until it shows "Docker is running"
Alternatively, install via Homebrew:
brew install --cask dockergit clone https://github.com/nycon/csrgen.git
cd csrgen
docker compose up -dOpen http://localhost:8443 in your browser.
docker compose downPort 5000 already in use:
macOS Monterey+ uses port 5000 for AirPlay Receiver. CSRgen already uses port 8443 to avoid this. If port 8443 is also in use, change it in docker-compose.yml:
ports:
- "9090:5000" # change 9090 to any free portunknown shorthand flag: 'd' in -d or docker: unknown command: docker compose:
Your Docker CLI does not expose the Compose subcommand correctly.
Use the standalone command instead:
docker-compose up -d --build
docker-compose down-
Install Docker Desktop for Windows:
- Download from https://www.docker.com/products/docker-desktop/
- Run the installer and follow the prompts
- Ensure WSL 2 backend is selected during installation (recommended)
- Restart your computer if prompted
-
Enable WSL 2 (if not already): Open PowerShell as Administrator:
wsl --installRestart your computer after installation.
-
Verify Docker is running:
docker --version docker compose version
Open PowerShell or Windows Terminal:
git clone https://github.com/nycon/csrgen.git
cd csrgen
docker compose up -dOpen http://localhost:8443 in your browser.
docker compose downDocker Desktop can be configured to start on login:
- Open Docker Desktop → Settings → General → Start Docker Desktop when you sign in
The container will restart automatically thanks to restart: unless-stopped.
This guide covers a full production deployment on a Linux server with:
- Docker & Docker Compose
- Nginx reverse proxy
- Free SSL/TLS certificate via Let's Encrypt
- Automatic certificate renewal
- Firewall configuration
Tested on: Ubuntu 22.04 / 24.04 LTS, Debian 12, Rocky Linux 9
# Update system
sudo apt update && sudo apt upgrade -y # Debian/Ubuntu
# sudo dnf update -y # Rocky/RHEL
# Install required packages
sudo apt install -y ca-certificates curl gnupg git# Add Docker's official GPG key and repository
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Add your user to the docker group (log out and back in after this)
sudo usermod -aG docker $USERVerify installation:
docker --version
docker compose versioncd /opt
sudo git clone https://github.com/nycon/csrgen.git
sudo chown -R $USER:$USER /opt/csrgen
cd /opt/csrgen
docker compose up -dVerify the container is running:
docker compose ps
curl -s http://localhost:8443 | head -5sudo apt install -y nginxCreate the Nginx site configuration:
sudo tee /etc/nginx/sites-available/csrgen <<'EOF'
server {
listen 80;
server_name csrgen.example.com; # <-- Replace with your domain
# Redirect HTTP to HTTPS (enabled after SSL setup)
location / {
return 301 https://$host$request_uri;
}
# Let's Encrypt challenge
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
server {
listen 443 ssl http2;
server_name csrgen.example.com; # <-- Replace with your domain
# SSL certificates (will be created in step 5)
ssl_certificate /etc/letsencrypt/live/csrgen.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/csrgen.example.com/privkey.pem;
# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Upload limit for P12 conversion
client_max_body_size 5M;
location / {
proxy_pass http://127.0.0.1:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOFEnable the site:
sudo ln -sf /etc/nginx/sites-available/csrgen /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/defaultFor the initial SSL setup, temporarily comment out the server block listening on 443 so Nginx can start:
sudo nginx -t
sudo systemctl enable nginx
sudo systemctl start nginxInstall Certbot:
sudo apt install -y certbot python3-certbot-nginxObtain the certificate (replace csrgen.example.com with your domain):
sudo certbot --nginx -d csrgen.example.com --non-interactive --agree-tos -m your@email.comCertbot will automatically configure Nginx with the certificate. Verify:
sudo nginx -t
sudo systemctl reload nginxNow uncomment the full HTTPS server block if it was commented out, and reload:
sudo nginx -t && sudo systemctl reload nginxCertbot installs a systemd timer automatically. Verify:
sudo systemctl status certbot.timerTest renewal:
sudo certbot renew --dry-runsudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP (for Let's Encrypt redirect)
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
sudo ufw statussudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all# Check container status
docker compose -f /opt/csrgen/docker-compose.yml ps
# Check Nginx status
sudo systemctl status nginx
# Test HTTPS
curl -I https://csrgen.example.comVisit https://csrgen.example.com in your browser. You should see a valid SSL certificate and the CSRgen interface.
cd /opt/csrgen # or wherever you cloned the repo
git pull
docker compose up -d --buildEdit docker-compose.yml:
ports:
- "YOUR_PORT:5000"Then restart:
docker compose up -d| Format | Includes Private Key | Typical Use |
|---|---|---|
PFX (.pfx) |
Yes | Windows IIS, RDP, MMC import |
P12 (.p12) |
Yes | PKCS#12 compatible systems |
CER (.cer, DER) |
No | Public cert in binary format |
CER (.cer, PEM) |
No | Public cert in text format |
P7B (.p7b) |
No | Certificate + chain transfer |
Notes:
- For
PFX/P12, upload a private key. - For encrypted private keys, fill in Key Password.
- For complete trust chains, upload Chain / Intermediate certificate.
| Variable | Default | Description |
|---|---|---|
PYTHONUNBUFFERED |
1 |
Ensures real-time log output |
- No storage – Private keys are generated in memory and sent directly to the browser. No files are ever written to disk.
- Read-only filesystem – The container runs with a read-only root filesystem.
- Non-root – The application runs as an unprivileged user inside the container.
- No new privileges – The container cannot gain additional privileges.
- Upload limit – File uploads are limited to 5 MB.
python3 -m venv venv
source venv/bin/activate # Linux/macOS
# .\venv\Scripts\activate # Windows PowerShell
pip install -r requirements.txt
python app.pyThe development server starts at http://localhost:5000.
csrgen/
├── app.py # Flask backend (CSR generation, P12, inspect)
├── templates/
│ └── index.html # Main HTML template
├── static/
│ ├── css/
│ │ └── style.css # Styles with dark mode support
│ └── js/
│ └── app.js # Frontend logic
├── Dockerfile # Container image definition
├── docker-compose.yml # Docker Compose configuration
├── requirements.txt # Python dependencies
└── README.md
MIT