Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b3b61e2
Initial plan
Copilot Mar 30, 2026
f61acd9
feat: certificate manager web app with PHP backend and React frontend
Copilot Mar 30, 2026
d861f2d
0.0.3 - some changes
Mar 30, 2026
c0ae056
feat: add path existence and writability validation when creating/edi…
Copilot Mar 30, 2026
037b56c
feat: default to email verification and auto-derive webmaster@ from e…
Copilot Mar 30, 2026
a62f667
feat: IMAP auto-verification of ZeroSSL email challenges
Copilot Mar 30, 2026
22874ae
0.0.4 - some chagnes
Mar 30, 2026
0ffc785
fix: trust-provider.com IMAP patterns and ZeroSSL per-domain email va…
Copilot Mar 30, 2026
2cc929f
fix: use flat validation_email for challenges endpoint (fixes missing…
Copilot Mar 30, 2026
9b5bdbc
0.0.5 - Some fixes
Mar 30, 2026
3d511f0
fix: send flat validation_email to challenges endpoint, remove debug …
Copilot Mar 30, 2026
cfddfa2
0.0.6 - Some changes
Mar 30, 2026
867cd39
feat: add inbox preview panel — show verification links and DCV codes…
Copilot Mar 31, 2026
1ef566e
feat: replace copy buttons with single Open Verification button that …
Copilot Mar 31, 2026
dde2cbf
fix: extract DCV code from email HTML body div, not just URL query param
Copilot Mar 31, 2026
21426d7
0.0.7 - Changes regex
Mar 31, 2026
e1aa62d
feat: delete inbox emails after reading and add Resend Email button
Copilot Mar 31, 2026
7fb1e7a
feat: single combined cert file, file path for cert_path, SSH/sudo re…
Copilot Mar 31, 2026
06cde98
0.0.8 - Some changes
Mar 31, 2026
6fa4bb1
fix: replace hardcoded /bin/sshpass with dynamic binary discovery and…
Copilot Mar 31, 2026
265010e
fix: add UserKnownHostsFile=/dev/null and LogLevel=ERROR to SSH optio…
Copilot Mar 31, 2026
0fe2720
feat: add split-files checkbox for separate cert, CA bundle and priva…
Copilot Apr 27, 2026
84b7a81
feat: split files mode writes fullchain (cert+CA) + key separately
Copilot Apr 27, 2026
7a31514
refactor: address code review — simplify key_path check; remove caPat…
Copilot Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 100 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,102 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default tseslint.config({
extends: [
// Remove ...tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,
],
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```
# CertManager

A web application for managing SSL/TLS certificates via the [ZeroSSL](https://zerossl.com) API.

![CertManager Dashboard](https://github.com/user-attachments/assets/81ea4bcd-fa49-436c-9b65-381bcb4cce5a)

## Features

- **Service Management** – Create and manage services, each associated with one or more domains and a certificate path.
- **Automatic Certificate Issuance** – Generates a CSR, requests a 90-day certificate from ZeroSSL, handles domain verification (HTTP file or email), downloads the certificate, and installs it automatically.
- **One-click Renewal** – Before expiry, click *Renew* to replace the old certificate with a fresh one.
- **Automatic Restart** – After installation, the configured restart command is executed on the server (e.g. `systemctl restart nginx`).
- **Dashboard** – Overview of all services with certificate status, expiry countdown, and quick-action links.
- **Settings** – Store your ZeroSSL API key securely in the backend.

## Architecture

| Layer | Technology |
|-------|-----------|
| Frontend | React 19 + TypeScript + Vite |
| Backend API | PHP (local JSON storage) |
| Certificate Authority | ZeroSSL REST API v2 |

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default tseslint.config({
plugins: {
// Add the react-x and react-dom plugins
'react-x': reactX,
'react-dom': reactDom,
},
rules: {
// other rules...
// Enable its recommended typescript rules
...reactX.configs['recommended-typescript'].rules,
...reactDom.configs.recommended.rules,
},
})
### Directory Structure

```
├── backend/ # PHP backend
│ ├── api/
│ │ ├── services.php # Services CRUD API
│ │ ├── cert.php # Certificate operations (request/verify/install/renew)
│ │ └── settings.php # ZeroSSL API key management
│ ├── lib/
│ │ ├── Services.php # JSON-backed service store
│ │ ├── ZeroSSL.php # ZeroSSL REST API client
│ │ └── CertManager.php # CSR generation, cert installation, command execution
│ └── data/
│ ├── services.json # Services data store
│ └── settings.json # App settings (ZeroSSL API key)
└── src/ # React frontend
├── screens/
│ ├── home/ # Dashboard
│ ├── services/ # Services list, form, and detail (cert workflow)
│ └── settings/ # ZeroSSL API key configuration
├── components/ # Layout, Modal, StatusBadge, DomainsInput
├── api/ # TypeScript API wrappers
└── types/ # TypeScript types
```

## Getting Started

### Prerequisites

- **PHP 8.0+** with `openssl` and `curl` extensions enabled
- **Node.js 18+**
- A free [ZeroSSL account](https://app.zerossl.com/signup) and API access key

### Development Setup

1. **Install frontend dependencies:**
```bash
npm install
```

2. **Start the PHP backend** (in a separate terminal):
```bash
php -S localhost:8000 -t backend/
```

3. **Start the frontend dev server:**
```bash
npm run dev
```
The Vite dev server proxies all `/api/*` requests to the PHP backend at `http://localhost:8000`.

4. Open [http://localhost:5173](http://localhost:5173) and go to **Settings** to add your ZeroSSL API key.

### Production Deployment

1. Build the frontend:
```bash
npm run build
```

2. Configure your web server (Apache/Nginx) to:
- Serve the `dist/` directory for all non-API requests
- Proxy `/api/*` to the PHP backend (or place the `backend/` directory under your document root and configure `mod_rewrite`/`try_files`)

3. Ensure the PHP process has write access to `backend/data/` and the certificate directories.

## Certificate Workflow

1. **Create a Service** – Set the service name, domains, certificate directory path, verification method, and restart command.
2. **Request Certificate** – CertManager generates a private key and CSR, then calls ZeroSSL to initiate the certificate request.
3. **Verify Domain** – For HTTP verification, the validation file is automatically created in your webroot. For email, ZeroSSL sends a verification link.
4. **Install** – Once issued, downloads the certificate, creates `fullchain.pem` (cert + CA bundle) and `privkey.key`, places them at the configured path, and executes the restart command.
5. **Renew** – When notified by ZeroSSL that a certificate is expiring, click *Renew* to issue a fresh certificate and reinstall automatically.

## Security Notes

- The ZeroSSL API key is stored in `backend/data/settings.json` — ensure this file is not web-accessible.
- The PHP backend uses `exec()` to run restart commands; only deploy on trusted infrastructure.
- Private keys are stored in `backend/data/services.json` in the interim; restrict access to this file (`chmod 600`).
5 changes: 5 additions & 0 deletions backend/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Loading