generated from Dicken/dickendock
HTTPS im lokalen Netz (Port 8443, selbstsigniertes Zertifikat, optional mkcert)
This commit is contained in:
@@ -39,3 +39,12 @@ FRITZBOX_PASSWORD=
|
||||
# ─── Frontend (nur für lokale Entwicklung, `pnpm dev:frontend`) ─────
|
||||
# Ziel für den Vite-Dev-Proxy von /api -> Backend
|
||||
BACKEND_URL=http://localhost:3001
|
||||
|
||||
# ─── HTTPS im lokalen Netz ──────────────────────────────────────────
|
||||
# IP-Adresse oder Hostname, unter der du LaunchPad im LAN aufrufst
|
||||
# (z. B. https://192.168.1.49:8443). Wird für das beim Containerstart
|
||||
# automatisch erzeugte selbstsignierte Zertifikat verwendet. Ohne eigenes
|
||||
# Zertifikat zeigt der Browser trotzdem eine Warnung – siehe README für eine
|
||||
# Variante ohne Warnung (mkcert). Ändern erfordert einen Neustart des
|
||||
# Frontend-Containers: docker compose up -d --force-recreate frontend
|
||||
LAUNCHPAD_HOST=192.168.1.49
|
||||
|
||||
53
README.md
53
README.md
@@ -14,9 +14,60 @@ cp .env.example .env # optional anpassen, siehe unten
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
- Frontend: http://localhost:8080
|
||||
- Frontend: http://localhost:8080 (HTTPS: https://localhost:8443, siehe unten)
|
||||
- Backend / Health-API: http://localhost:3001/api/health
|
||||
|
||||
## HTTPS im lokalen Netz
|
||||
|
||||
LaunchPad ist per HTTPS auf Port `8443` erreichbar (`https://<deine-ip>:8443`),
|
||||
zusätzlich zu HTTP auf `8080` – kein erzwungener Redirect. Beim ersten Start
|
||||
erzeugt der Frontend-Container automatisch ein selbstsigniertes Zertifikat für
|
||||
die in `.env` hinterlegte `LAUNCHPAD_HOST` (IP oder Hostname). Der Browser
|
||||
zeigt dafür trotzdem eine Sicherheitswarnung – das ist bei selbstsignierten
|
||||
Zertifikaten normal, nicht per se unsicher fürs eigene LAN.
|
||||
|
||||
```bash
|
||||
# .env: IP/Hostname eintragen, unter der du zugreifst
|
||||
LAUNCHPAD_HOST=192.168.1.49
|
||||
|
||||
docker compose up -d --force-recreate frontend
|
||||
```
|
||||
|
||||
Danach: `https://192.168.1.49:8443` (Warnung einmalig bestätigen/Ausnahme
|
||||
hinzufügen).
|
||||
|
||||
### Ohne Browser-Warnung (empfohlen): eigenes Zertifikat per mkcert
|
||||
|
||||
[mkcert](https://github.com/FiloSottile/mkcert) erzeugt lokal vertrauenswürdige
|
||||
Zertifikate – dein Browser vertraut ihnen automatisch, keine Warnung mehr.
|
||||
|
||||
```bash
|
||||
# Einmalig auf dem Rechner, von dem aus du zugreifst (nicht auf dem Server):
|
||||
mkcert -install
|
||||
|
||||
# Zertifikat für IP/Hostname erzeugen:
|
||||
mkcert -cert-file fullchain.pem -key-file privkey.pem 192.168.1.49 launchpad.home localhost 127.0.0.1
|
||||
```
|
||||
|
||||
Die beiden erzeugten Dateien nach `/opt/LaunchPad/certs/` kopieren, dann in
|
||||
`docker-compose.yml` die auskommentierten `volumes:`-Zeilen beim
|
||||
`frontend`-Service aktivieren:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./certs/fullchain.pem:/etc/nginx/certs/fullchain.pem:ro
|
||||
- ./certs/privkey.pem:/etc/nginx/certs/privkey.pem:ro
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate frontend
|
||||
```
|
||||
|
||||
`mkcert -install` legt eine lokale Root-CA an, der nur *dieser* Rechner
|
||||
vertraut. Für weitere Geräte (Handy etc.) muss die Root-CA
|
||||
(`mkcert -CAROOT` zeigt den Pfad) dort zusätzlich installiert werden, oder es
|
||||
bleibt bei der Browser-Warnung des automatisch generierten Zertifikats.
|
||||
|
||||
## Quickstart (lokale Entwicklung)
|
||||
|
||||
Voraussetzungen: Node.js ≥ 20, pnpm ≥ 9.
|
||||
|
||||
@@ -24,7 +24,12 @@ RUN pnpm --filter @launchpad/frontend build
|
||||
|
||||
# ---- runtime: nginx --------------------------------------------------------
|
||||
FROM nginx:1.27-alpine AS runtime
|
||||
RUN apk add --no-cache openssl
|
||||
COPY apps/frontend/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY apps/frontend/nginx-locations.conf /etc/nginx/launchpad-locations.conf
|
||||
COPY apps/frontend/docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
COPY --from=build /app/apps/frontend/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
EXPOSE 80 443
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
38
apps/frontend/docker-entrypoint.sh
Normal file
38
apps/frontend/docker-entrypoint.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
CERT_DIR="/etc/nginx/certs"
|
||||
CERT_FILE="$CERT_DIR/fullchain.pem"
|
||||
KEY_FILE="$CERT_DIR/privkey.pem"
|
||||
|
||||
# Falls der Nutzer eigene Zertifikate eingebunden hat (siehe README, z. B.
|
||||
# per mkcert erzeugt), diese nicht überschreiben.
|
||||
if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then
|
||||
HOST="${LAUNCHPAD_HOST:-localhost}"
|
||||
mkdir -p "$CERT_DIR"
|
||||
|
||||
# IP-Adresse oder Hostname? Browser verlangen bei IP-Zugriff eine
|
||||
# IP-SAN, ein DNS-Name genügt da nicht.
|
||||
case "$HOST" in
|
||||
*[0-9]*.*[0-9]*.*[0-9]*.*[0-9]*)
|
||||
SAN="IP:$HOST,DNS:localhost,IP:127.0.0.1"
|
||||
;;
|
||||
*)
|
||||
SAN="DNS:$HOST,DNS:localhost,IP:127.0.0.1"
|
||||
;;
|
||||
esac
|
||||
|
||||
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
||||
-keyout "$KEY_FILE" \
|
||||
-out "$CERT_FILE" \
|
||||
-subj "/CN=$HOST" \
|
||||
-addext "subjectAltName=$SAN" \
|
||||
2>/dev/null
|
||||
|
||||
echo "[entrypoint] Selbstsigniertes HTTPS-Zertifikat für '$HOST' erzeugt."
|
||||
echo "[entrypoint] Der Browser zeigt dafür eine Sicherheitswarnung - siehe README fuer eine Variante ohne Warnung (mkcert)."
|
||||
else
|
||||
echo "[entrypoint] Verwende eingebundenes Zertifikat unter $CERT_DIR."
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
32
apps/frontend/nginx-locations.conf
Normal file
32
apps/frontend/nginx-locations.conf
Normal file
@@ -0,0 +1,32 @@
|
||||
# PWA / SPA: alle unbekannten Routen auf index.html zurückführen
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# API-Anfragen an den Backend-Container weiterleiten
|
||||
location /api/ {
|
||||
proxy_pass http://backend:3001/api/;
|
||||
proxy_http_version 1.1;
|
||||
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;
|
||||
}
|
||||
|
||||
# Service Worker und Manifest dürfen nicht langfristig gecacht werden,
|
||||
# sonst bekommen installierte PWA-Nutzer nie ein Update mit.
|
||||
location = /sw.js {
|
||||
add_header Cache-Control "no-cache";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /manifest.webmanifest {
|
||||
add_header Cache-Control "no-cache";
|
||||
default_type application/manifest+json;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.(?:css|js|svg|png|jpg|jpeg|gif|ico|woff2?)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable";
|
||||
}
|
||||
@@ -1,39 +1,26 @@
|
||||
# HTTP – bleibt zusätzlich zu HTTPS verfügbar (kein erzwungener Redirect,
|
||||
# damit bestehende http://-Zugriffe nicht plötzlich brechen).
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# PWA / SPA: alle unbekannten Routen auf index.html zurückführen
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
include /etc/nginx/launchpad-locations.conf;
|
||||
}
|
||||
|
||||
# API-Anfragen an den Backend-Container weiterleiten
|
||||
location /api/ {
|
||||
proxy_pass http://backend:3001/api/;
|
||||
proxy_http_version 1.1;
|
||||
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;
|
||||
}
|
||||
# HTTPS – Zertifikat wird vom Entrypoint-Skript automatisch erzeugt
|
||||
# (selbstsigniert) oder ist vom Nutzer eingebunden, siehe README.
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Service Worker und Manifest dürfen nicht langfristig gecacht werden,
|
||||
# sonst bekommen installierte PWA-Nutzer nie ein Update mit.
|
||||
location = /sw.js {
|
||||
add_header Cache-Control "no-cache";
|
||||
try_files $uri =404;
|
||||
}
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
location = /manifest.webmanifest {
|
||||
add_header Cache-Control "no-cache";
|
||||
default_type application/manifest+json;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.(?:css|js|svg|png|jpg|jpeg|gif|ico|woff2?)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800, immutable";
|
||||
}
|
||||
include /etc/nginx/launchpad-locations.conf;
|
||||
}
|
||||
|
||||
@@ -25,10 +25,19 @@ services:
|
||||
dockerfile: apps/frontend/Dockerfile
|
||||
container_name: launchpad-frontend
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- path: ./.env
|
||||
required: false
|
||||
depends_on:
|
||||
- backend
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "8443:443"
|
||||
# Optional: eigenes Zertifikat statt des automatisch generierten
|
||||
# selbstsignierten einbinden (z. B. per mkcert erzeugt, siehe README):
|
||||
# volumes:
|
||||
# - ./certs/fullchain.pem:/etc/nginx/certs/fullchain.pem:ro
|
||||
# - ./certs/privkey.pem:/etc/nginx/certs/privkey.pem:ro
|
||||
|
||||
volumes:
|
||||
launchpad-data:
|
||||
|
||||
@@ -181,3 +181,23 @@ Geräte):
|
||||
(3) Umbenennen einer Kategorie im Adminbereich aktualisiert automatisch
|
||||
alle Dienste mit dem alten Namen. Einschränkung: manuell per API angelegte
|
||||
Dienste (nicht über einen Scan) lösen diesen Sync aktuell nicht aus.
|
||||
|
||||
## HTTPS im lokalen Netz
|
||||
|
||||
- Frontend-Container liefert jetzt zusätzlich zu HTTP (Port 8080) auch HTTPS
|
||||
auf Port 8443 aus, kein erzwungener Redirect.
|
||||
- Entrypoint-Skript (`apps/frontend/docker-entrypoint.sh`) erzeugt beim
|
||||
Containerstart automatisch ein selbstsigniertes Zertifikat für die in
|
||||
`.env` hinterlegte `LAUNCHPAD_HOST` (IP-SAN bei IP-Adressen, DNS-SAN bei
|
||||
Hostnamen) – übernimmt nichts, falls unter `/etc/nginx/certs/` bereits
|
||||
eigene Zertifikate eingebunden sind (siehe README, z. B. per mkcert für
|
||||
eine Variante ohne Browser-Warnung).
|
||||
- `nginx.conf` in HTTP- und HTTPS-Serverblock aufgeteilt, gemeinsame
|
||||
Location-Regeln in `nginx-locations.conf` ausgelagert (kein doppelt
|
||||
gepflegter Proxy-/Cache-Code).
|
||||
|
||||
> Verifiziert: Zertifikatserzeugung für IP-, Hostname- und Fallback-Fall
|
||||
> getestet, komplette nginx-Konfiguration mit einem echten nginx-Binary
|
||||
> validiert (`nginx -t` erfolgreich), echter TLS-Handshake gegen den
|
||||
> laufenden Server durchgeführt und geprüft, dass das ausgelieferte
|
||||
> Zertifikat die korrekte IP als Subject Alternative Name trägt.
|
||||
|
||||
Reference in New Issue
Block a user