Add README with CA install guides, add /ca.crt download endpoint

- Detailed CA import instructions for Chrome, Firefox, Android,
  iOS/iPadOS, macOS, Windows, Linux
- /ca.crt endpoint for easy browser download (no auth required)
- Download button in WebUI header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-09 15:51:39 +02:00
parent cf97de7e63
commit 5a8770e973
3 changed files with 255 additions and 2 deletions

240
README.md Normal file
View File

@ -0,0 +1,240 @@
# HTTPS Reverse Proxy mit selbstsigniertem 100-Jahre-Zertifikat
Ein Docker-basierter HTTPS Reverse Proxy mit eigener CA (Certificate Authority), konfigurierbarer WebUI und REST API.
## Features
- Selbstsigniertes SSL-Zertifikat mit eigener CA (100 Jahre gueltig)
- WebUI zur Verwaltung von Proxy-Zielen
- REST API fuer automatisierte Konfiguration
- Domain-basiertes und IP/Port-basiertes Routing
- Host Network Mode (keine Port-Freigabe noetig)
- Alle Einstellungen ueber `.env` konfigurierbar
- CA-Download direkt ueber den Browser (`https://<ip>:8443/ca.crt`)
## Schnellstart
### 1. Konfiguration anpassen
```bash
cp .env.example .env
nano .env
```
Einstellungen in der `.env`:
| Variable | Beschreibung | Standard |
|---|---|---|
| `CERT_COUNTRY` | Land (2-Buchstaben-Code) | `DE` |
| `CERT_STATE` | Bundesland | `Bavaria` |
| `CERT_CITY` | Stadt | `Munich` |
| `CERT_ORG` | Organisation | `MyOrganization` |
| `CERT_OU` | Abteilung | `IT` |
| `CERT_CN` | Common Name | `proxy.local` |
| `CERT_DAYS` | Zertifikat-Gueltigkeit in Tagen | `36500` (~100 Jahre) |
| `WEBUI_PORT` | Port der WebUI | `8443` |
| `WEBUI_USERNAME` | Login-Benutzername | `admin` |
| `WEBUI_PASSWORD` | Login-Passwort | `admin123` |
### 2. Container starten
```bash
docker compose up -d --build
```
### 3. WebUI oeffnen
```
https://<server-ip>:8443
```
Login mit den Zugangsdaten aus der `.env`.
## CA-Zertifikat installieren
Damit Browser und Geraete dem selbstsignierten Zertifikat vertrauen, muss die CA installiert werden.
### CA-Zertifikat herunterladen
Die CA kann direkt ueber den Browser heruntergeladen werden:
```
https://<server-ip>:8443/ca.crt
```
Alternativ liegt die Datei im Projektverzeichnis unter `certs/ca.crt`.
---
### Google Chrome (Desktop)
1. `chrome://settings/security` oeffnen
2. Auf **Zertifikate verwalten** klicken
3. Reiter **Zertifizierungsstellen** waehlen
4. **Importieren** klicken
5. Die heruntergeladene `ca.crt` auswaehlen
6. Haken bei **Diesem Zertifikat zur Identifizierung von Websites vertrauen** setzen
7. Mit **OK** bestaetigen
8. Browser neu starten
### Mozilla Firefox (Desktop)
1. `about:preferences#privacy` oeffnen
2. Runterscrollen zu **Zertifikate**
3. Auf **Zertifikate anzeigen...** klicken
4. Reiter **Zertifizierungsstellen** waehlen
5. **Importieren...** klicken
6. Die heruntergeladene `ca.crt` auswaehlen
7. Haken bei **Dieser CA vertrauen, um Websites zu identifizieren** setzen
8. Mit **OK** bestaetigen
### Android
1. `https://<server-ip>:8443/ca.crt` im Browser oeffnen
2. Die Datei wird heruntergeladen
3. **Einstellungen** > **Sicherheit** > **Verschluesselung und Anmeldedaten** oeffnen
4. **CA-Zertifikat installieren** waehlen
5. Die heruntergeladene `ca.crt` auswaehlen
6. Bei Aufforderung den Geraete-PIN/Passwort eingeben
7. Dem Zertifikat einen Namen geben und mit **OK** bestaetigen
> **Hinweis:** Der genaue Pfad variiert je nach Android-Version und Hersteller. Suche in den Einstellungen nach "Zertifikat" falls der Pfad abweicht.
### iPhone / iPad (iOS / iPadOS)
1. `https://<server-ip>:8443/ca.crt` in **Safari** oeffnen (nicht Chrome!)
2. Es erscheint die Meldung **Profil geladen** -- auf **Schliessen** tippen
3. **Einstellungen** oeffnen
4. Oben erscheint **Profil geladen** -- darauf tippen
5. Auf **Installieren** tippen und den Geraete-Code eingeben
6. Nochmals **Installieren** bestaetigen
7. Danach: **Einstellungen** > **Allgemein** > **Info** > **Zertifikatsvertrauenseinstellungen**
8. Den Schalter neben dem CA-Zertifikat **aktivieren**
9. Mit **Weiter** bestaetigen
> **Wichtig:** Schritt 7-9 wird oft vergessen! Ohne die Vertrauenseinstellung unter "Info" ist das Zertifikat zwar installiert, aber nicht aktiv.
### macOS
1. `https://<server-ip>:8443/ca.crt` im Browser oeffnen und herunterladen
2. Doppelklick auf die `ca.crt` -- die **Schluesselbuendverwaltung** oeffnet sich
3. Das Zertifikat wird unter **Anmeldung** hinzugefuegt
4. Doppelklick auf das importierte Zertifikat
5. **Vertrauen** aufklappen
6. **Bei Verwendung dieses Zertifikats** auf **Immer vertrauen** setzen
7. Fenster schliessen und mit Admin-Passwort bestaetigen
### Windows
1. `https://<server-ip>:8443/ca.crt` im Browser oeffnen und herunterladen
2. Doppelklick auf die `ca.crt`
3. Auf **Zertifikat installieren...** klicken
4. **Lokaler Computer** waehlen (fuer alle Benutzer) oder **Aktueller Benutzer**
5. **Alle Zertifikate in folgendem Speicher speichern** waehlen
6. **Durchsuchen** > **Vertrauenswuerdige Stammzertifizierungsstellen** waehlen
7. Mit **OK** / **Weiter** / **Fertig stellen** abschliessen
8. Browser neu starten
### Linux
```bash
# Debian/Ubuntu
sudo cp ca.crt /usr/local/share/ca-certificates/proxy-ca.crt
sudo update-ca-certificates
# RHEL/CentOS/Fedora
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/proxy-ca.crt
sudo update-ca-trust
# Arch Linux
sudo cp ca.crt /etc/ca-certificates/trust-source/anchors/proxy-ca.crt
sudo trust extract-compat
```
> **Hinweis:** Firefox unter Linux verwendet einen eigenen Zertifikatsspeicher. Die CA muss dort separat importiert werden (siehe Firefox-Anleitung oben).
## API-Nutzung
Alle API-Endpunkte erfordern HTTP Basic Auth.
### Alle Ziele auflisten
```bash
curl -k -u admin:admin123 https://localhost:8443/api/targets
```
### Neues Ziel hinzufuegen
```bash
curl -k -u admin:admin123 -X POST https://localhost:8443/api/targets \
-H "Content-Type: application/json" \
-d '{
"name": "mein-webserver",
"target_host": "192.168.1.50",
"target_port": 80,
"target_scheme": "http",
"listen_port": 9443,
"domains": [
{"domain": "app.example.local", "port": 443}
]
}'
```
### Ziel aktualisieren
```bash
curl -k -u admin:admin123 -X PUT https://localhost:8443/api/targets/0 \
-H "Content-Type: application/json" \
-d '{"name": "updated", "target_host": "10.0.0.5", "target_port": 3000, "enabled": true}'
```
### Ziel loeschen
```bash
curl -k -u admin:admin123 -X DELETE https://localhost:8443/api/targets/0
```
### Nginx neu laden
```bash
curl -k -u admin:admin123 -X POST https://localhost:8443/api/reload
```
## Verzeichnisstruktur
```
.
├── .env # Konfiguration (nicht im Git)
├── .env.example # Konfigurationsvorlage
├── Dockerfile
├── docker-compose.yml
├── app/
│ ├── app.py # Flask App (WebUI + API)
│ ├── requirements.txt
│ └── templates/
│ └── index.html
├── certs/ # Generierte Zertifikate (nicht im Git)
│ ├── ca.crt # CA-Zertifikat
│ ├── ca.key # CA Private Key
│ ├── server.crt # Server-Zertifikat
│ ├── server.key # Server Private Key
│ └── generate-certs.sh # Generierungsskript
├── data/ # Proxy-Konfiguration (nicht im Git)
│ └── proxy_config.json
└── nginx/
├── nginx.conf
└── entrypoint.sh
```
## Zertifikate neu generieren
Falls die Zertifikate neu generiert werden sollen (z.B. nach Aenderung der `.env`):
```bash
rm -f certs/ca.* certs/server.*
docker compose up -d --build
```
## Lizenz
MIT

View File

@ -4,7 +4,7 @@ import subprocess
from functools import wraps from functools import wraps
from pathlib import Path from pathlib import Path
from flask import Flask, jsonify, redirect, render_template, request, url_for from flask import Flask, jsonify, redirect, render_template, request, send_file, url_for
app = Flask(__name__) app = Flask(__name__)
@ -154,6 +154,16 @@ def index():
return render_template("index.html", config=config) return render_template("index.html", config=config)
@app.route("/ca.crt")
def download_ca():
"""Download CA certificate - no auth required so devices can easily fetch it."""
ca_path = "/certs/ca.crt"
if not os.path.exists(ca_path):
return "CA certificate not found", 404
return send_file(ca_path, as_attachment=True, download_name="ca.crt",
mimetype="application/x-x509-ca-cert")
@app.route("/target/add", methods=["POST"]) @app.route("/target/add", methods=["POST"])
@check_auth @check_auth
def add_target(): def add_target():

View File

@ -197,8 +197,11 @@
<body> <body>
<div class="header"> <div class="header">
<h1>HTTPS Reverse Proxy</h1> <h1>HTTPS Reverse Proxy</h1>
<div style="display:flex;align-items:center;gap:15px;">
<a href="/ca.crt" class="btn btn-sm btn-primary" style="text-decoration:none;">CA-Zertifikat herunterladen</a>
<span class="badge">Self-Signed SSL - 100 Jahre</span> <span class="badge">Self-Signed SSL - 100 Jahre</span>
</div> </div>
</div>
<div class="container"> <div class="container">
<!-- Add new target --> <!-- Add new target -->