Added dokumentation.md
This commit is contained in:
@@ -0,0 +1,558 @@
|
|||||||
|
# Dokumentation – Pastebin-Service
|
||||||
|
|
||||||
|
**Thema 1 – Custom Website**
|
||||||
|
**Webarchitektur Projekt**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inhaltsverzeichnis
|
||||||
|
|
||||||
|
1. [Beschreibung der Umsetzung](#1-beschreibung-der-umsetzung)
|
||||||
|
2. [Architekturdiagramm](#2-architekturdiagramm)
|
||||||
|
3. [Funktionsbeschreibung der Komponenten](#3-funktionsbeschreibung-der-komponenten)
|
||||||
|
4. [Installationsanleitung](#4-installationsanleitung)
|
||||||
|
5. [Konfigurationsanpassungen](#5-konfigurationsanpassungen)
|
||||||
|
6. [Post-Mortem-Log](#6-post-mortem-log)
|
||||||
|
7. [Screenshots](#7-screenshots)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Beschreibung der Umsetzung
|
||||||
|
|
||||||
|
Das Projekt ist ein einfacher Pastebin-Service, der es Nutzern ermöglicht, Text online zu speichern und über einen Link zu teilen. Die Anwendung besteht aus vier Docker-Containern, die über Docker Compose orchestriert werden.
|
||||||
|
|
||||||
|
### Kernfunktionalität
|
||||||
|
|
||||||
|
- **Paste erstellen**: Jeder Nutzer kann ohne Authentifizierung einen Paste erstellen (max. 100.000 Zeichen)
|
||||||
|
- **Paste anzeigen**: Nach der Erstellung erhält der Nutzer einen View-Link und einen einmaligen Delete-Link
|
||||||
|
- **Paste löschen**: Über den Delete-Link kann der Paste gelöscht werden (Token wird nur einmal angezeigt)
|
||||||
|
- **Admin-Bereich**: Mit einem Admin-Passwort können alle Pastes eingesehen und gelöscht werden
|
||||||
|
|
||||||
|
### Technologie-Stack
|
||||||
|
|
||||||
|
| Schicht | Technologie | Zweck |
|
||||||
|
|---------|-------------|-------|
|
||||||
|
| Frontend | Vite + React + TypeScript | Single-Page-Application |
|
||||||
|
| Backend | FastAPI (Python) | REST-API |
|
||||||
|
| Datenbank | PostgreSQL 16 | Persistente Datenspeicherung |
|
||||||
|
| Webserver | NGINX (Alpine) | Static Files + Reverse Proxy |
|
||||||
|
| Deployment | Docker Compose | Container-Orchestrierung |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Architekturdiagramm
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Internet │
|
||||||
|
│ Port 80 (HTTP) / 443 (HTTPS) │
|
||||||
|
└────────────────────────────┬────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ NGINX Reverse Proxy │
|
||||||
|
│ (Container: proxy) │
|
||||||
|
│ │
|
||||||
|
│ ┌───────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Port 80: 301 Redirect → HTTPS │ │
|
||||||
|
│ │ Port 443: TLS-Terminierung (cert.pem / key.pem) │ │
|
||||||
|
│ │ Security-Header: HSTS, X-Frame-Options, CSP, etc. │ │
|
||||||
|
│ └───────────────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ /api/* ──────────► http://backend:8000 │
|
||||||
|
│ /* ──────────► http://frontend:80 │
|
||||||
|
└────────────────────────────┬────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌──────────────┼──────────────┐
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
|
||||||
|
│ Frontend │ │ Backend │ │ PostgreSQL │
|
||||||
|
│ (NGINX) │ │ (FastAPI) │ │ (Datenbank) │
|
||||||
|
│ Port 80 │ │ Port 8000 │ │ Port 5432 │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ React SPA │ │ REST-API │ │ Pastes-Tabelle │
|
||||||
|
│ Static Files │ │ Uvicorn │ │ UUID PK/FK │
|
||||||
|
└─────────────────┘ └──────┬───────┘ └─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────┐
|
||||||
|
│ PostgreSQL │
|
||||||
|
│ (Volume) │
|
||||||
|
│ pgdata │
|
||||||
|
└──────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Netzwerk-Isolation
|
||||||
|
|
||||||
|
- Nur der **proxy** Container bindet auf öffentliche Ports (80, 443)
|
||||||
|
- **backend**, **frontend** und **db** sind nur über das interne Docker-Netzwerk erreichbar
|
||||||
|
- Keine externen Port-Mappings für Backend und Datenbank
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Funktionsbeschreibung der Komponenten
|
||||||
|
|
||||||
|
### 3.1 NGINX Reverse Proxy (`nginx/nginx.conf`)
|
||||||
|
|
||||||
|
**Aufgabe**: Terminiert die TLS-Verbindung und leitet Requests an die internen Services weiter.
|
||||||
|
|
||||||
|
**TLS-Terminierung** (`nginx/nginx.conf:13-20`):
|
||||||
|
```nginx
|
||||||
|
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
```
|
||||||
|
Das Zertifikat wird manuell im `ssl/` Verzeichnis bereitgestellt. Es unterstützt TLS 1.2 und 1.3.
|
||||||
|
|
||||||
|
**HTTP → HTTPS Redirect** (`nginx/nginx.conf:1-4`):
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name static.155.116.167.89.clients.your-server.de;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Alle HTTP-Anfragen werden permanent auf HTTPS umgeleitet.
|
||||||
|
|
||||||
|
**Reverse Proxy Routing** (`nginx/nginx.conf:30-46`):
|
||||||
|
```nginx
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://backend:8000;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
location / {
|
||||||
|
proxy_pass http://frontend:80;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Requests an `/api/*` werden an den FastAPI-Backend-Container weitergeleitet, alle anderen an den Frontend-NGINX.
|
||||||
|
|
||||||
|
**Security-Hardening** (`nginx/nginx.conf:24-28`):
|
||||||
|
```nginx
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "DENY" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
|
||||||
|
```
|
||||||
|
|
||||||
|
| Header | Funktion |
|
||||||
|
|--------|----------|
|
||||||
|
| `Strict-Transport-Security` (HSTS) | Erzwingt HTTPS für 2 Jahre, inkl. Subdomains |
|
||||||
|
| `X-Frame-Options: DENY` | Verhindert Einbettung in iframes (Clickjacking-Schutz) |
|
||||||
|
| `X-Content-Type-Options: nosniff` | Verhindert MIME-Type-Sniffing |
|
||||||
|
| `Referrer-Policy` | Kontrolliert Referrer-Weitergabe |
|
||||||
|
| `Permissions-Policy` | Deaktiviert Kamera, Mikrofon, Geolocation |
|
||||||
|
|
||||||
|
**Server-Header entfernen** (`nginx/nginx.conf:11, 36-37, 45`):
|
||||||
|
```nginx
|
||||||
|
server_tokens off; # Blendet NGINX-Version aus
|
||||||
|
proxy_hide_header Server; # Entfernt Server-Header aus Backend-Antworten
|
||||||
|
proxy_hide_header X-Powered-By; # Entfernt Technologie-Header
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Frontend (`frontend/`)
|
||||||
|
|
||||||
|
**Aufgabe**: Stellt die Benutzeroberfläche als Single-Page-Application bereit.
|
||||||
|
|
||||||
|
**Build-Prozess** (`frontend/Dockerfile:1-9`):
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
```
|
||||||
|
Das Frontend wird mit Vite gebaut. Die entstehenden Static Files werden in den NGINX-Container kopiert.
|
||||||
|
|
||||||
|
**Static File Serving** (`frontend/nginx.conf:8-10`):
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Die `try_files`-Direktive ermöglicht Client-Side-Routing: Alle Pfade werden auf `index.html` umgeleitet, sodass React Router funktioniert.
|
||||||
|
|
||||||
|
**SPA-Routing** (`frontend/src/main.tsx`):
|
||||||
|
```tsx
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<HomePage />} /> {/* Paste erstellen */}
|
||||||
|
<Route path="paste/:id" element={<PastePage />} /> {/* Paste anzeigen */}
|
||||||
|
<Route path="admin" element={<AdminPage />} /> {/* Admin-Bereich */}
|
||||||
|
</Routes>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Backend (`backend/`)
|
||||||
|
|
||||||
|
**Aufgabe**: Stellt die REST-API bereit und kommuniziert mit der Datenbank.
|
||||||
|
|
||||||
|
**API-Endpunkte** (`backend/app/main.py`):
|
||||||
|
|
||||||
|
| Methode | Pfad | Beschreibung | Zeile |
|
||||||
|
|---------|------|--------------|-------|
|
||||||
|
| `POST` | `/api/pastes` | Neuen Paste erstellen | 34 |
|
||||||
|
| `GET` | `/api/pastes/{id}` | Paste abrufen | 45 |
|
||||||
|
| `DELETE` | `/api/pastes/{id}?token=...` | Paste löschen (mit Token) | 53 |
|
||||||
|
| `GET` | `/api/admin/pastes` | Alle Pastes auflisten (Admin) | 69 |
|
||||||
|
| `DELETE` | `/api/admin/pastes/{id}` | Paste als Admin löschen | 78 |
|
||||||
|
|
||||||
|
**Admin-Authentifizierung** (`backend/app/main.py:29-31`):
|
||||||
|
```python
|
||||||
|
def verify_admin(password: str = Header(..., alias="X-Admin-Password")):
|
||||||
|
if password != settings.admin_password:
|
||||||
|
raise HTTPException(status_code=401, detail="Invalid admin password")
|
||||||
|
```
|
||||||
|
Das Admin-Passwort wird über den `X-Admin-Password` Header übermittelt und gegen die Umgebungsvariable geprüft.
|
||||||
|
|
||||||
|
**Datenbankmodell** (`backend/app/models.py:11-21`):
|
||||||
|
```python
|
||||||
|
class Paste(Base):
|
||||||
|
__tablename__ = "pastes"
|
||||||
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
delete_token: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), nullable=False, default=uuid.uuid4)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
|
||||||
|
```
|
||||||
|
- `id`: UUID als Primärschlüssel (verhindert Enumeration)
|
||||||
|
- `delete_token`: Separater UUID für das Löschen (wird nur bei Erstellung ausgegeben)
|
||||||
|
- `content`: Text mit max. 100.000 Zeichen
|
||||||
|
|
||||||
|
### 3.4 PostgreSQL Datenbank
|
||||||
|
|
||||||
|
**Aufgabe**: Persistente Speicherung der Pastes.
|
||||||
|
|
||||||
|
**Konfiguration** (`docker-compose.yml:2-10`):
|
||||||
|
```yaml
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
```
|
||||||
|
Die Datenbank-Credentials werden über Umgebungsvariablen aus `.env` geladen. Die Daten werden in einem Docker-Volume (`pgdata`) persistent gespeichert.
|
||||||
|
|
||||||
|
**Port-Binding**: Der PostgreSQL-Container hat kein `ports:`-Mapping und ist daher nur aus dem internen Docker-Netzwerk erreichbar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Installationsanleitung
|
||||||
|
|
||||||
|
### 4.1 Voraussetzungen
|
||||||
|
|
||||||
|
- Docker und Docker Compose installiert
|
||||||
|
- Domain/Server-IP verfügbar: `static.155.116.167.89.clients.your-server.de`
|
||||||
|
- SSL-Zertifikat vorhanden
|
||||||
|
|
||||||
|
### 4.2 Projekt klonieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <repository-url>
|
||||||
|
cd Web-Architekturen-Projekt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 SSL-Zertifikat bereitstellen
|
||||||
|
|
||||||
|
Zertifikat im `ssl/` Verzeichnis ablegen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Bei vorhandenem Let's Encrypt Zertifikat:
|
||||||
|
cp /etc/letsencrypt/live/static.155.116.167.89.clients.your-server.de/fullchain.pem ssl/cert.pem
|
||||||
|
cp /etc/letsencrypt/live/static.155.116.167.89.clients.your-server.de/privkey.pem ssl/key.pem
|
||||||
|
|
||||||
|
# Oder Self-Signed für Tests:
|
||||||
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||||
|
-keyout ssl/key.pem -out ssl/cert.pem \
|
||||||
|
-subj "/CN=static.155.116.167.89.clients.your-server.de"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 Umgebungsvariablen konfigurieren
|
||||||
|
|
||||||
|
`.env` Datei anpassen:
|
||||||
|
|
||||||
|
```env
|
||||||
|
ADMIN_PASSWORD=sicheres-passwort-hier
|
||||||
|
POSTGRES_USER=pastebin
|
||||||
|
POSTGRES_PASSWORD=datenbank-passwort-hier
|
||||||
|
POSTGRES_DB=pastebin
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5 Container starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.6 Überprüfung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Container-Status prüfen
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# Logs prüfen
|
||||||
|
docker compose logs
|
||||||
|
|
||||||
|
# Einzelne Services
|
||||||
|
docker compose logs proxy
|
||||||
|
docker compose logs backend
|
||||||
|
docker compose logs db
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Anwendung ist erreichbar unter: `https://static.155.116.167.89.clients.your-server.de`
|
||||||
|
|
||||||
|
### 4.7 Neustart
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Datenbank-Daten bleiben durch das Docker-Volume erhalten.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Konfigurationsanpassungen
|
||||||
|
|
||||||
|
### 5.1 NGINX Reverse Proxy (`nginx/nginx.conf`)
|
||||||
|
|
||||||
|
Alle Konfigurationen weichen von der Standardkonfiguration ab:
|
||||||
|
|
||||||
|
| Zeile | Konfiguration | Beschreibung |
|
||||||
|
|-------|---------------|--------------|
|
||||||
|
| 1-4 | `server { listen 80; return 301 ... }` | HTTP → HTTPS Redirect |
|
||||||
|
| 11 | `server_tokens off;` | NGINX-Version ausblenden |
|
||||||
|
| 13-14 | `ssl_certificate / ssl_certificate_key` | Manuelle TLS-Zertifikate |
|
||||||
|
| 16-20 | `ssl_protocols / ssl_ciphers` | TLS 1.2/1.3, sichere Ciphers |
|
||||||
|
| 24-28 | `add_header ...` | 5 Security-Header |
|
||||||
|
| 31 | `proxy_pass http://backend:8000;` | API-Requests an Backend |
|
||||||
|
| 33-35 | `proxy_set_header ...` | Client-IP und Proto weiterleiten |
|
||||||
|
| 36-37 | `proxy_hide_header ...` | Server-Header entfernen |
|
||||||
|
| 41 | `proxy_pass http://frontend:80;` | Frontend-Requests an NGINX |
|
||||||
|
|
||||||
|
### 5.2 Frontend-NGINX (`frontend/nginx.conf`)
|
||||||
|
|
||||||
|
| Zeile | Konfiguration | Beschreibung |
|
||||||
|
|-------|---------------|--------------|
|
||||||
|
| 9 | `try_files $uri $uri/ /index.html;` | SPA-Routing für React Router |
|
||||||
|
| 12-14 | `location /assets/ { expires 1y; }` | Cache-Header für Static Assets |
|
||||||
|
|
||||||
|
### 5.3 Docker Compose (`docker-compose.yml`)
|
||||||
|
|
||||||
|
| Zeile | Konfiguration | Beschreibung |
|
||||||
|
|-------|---------------|--------------|
|
||||||
|
| 10 | `restart: unless-stopped` | Automatischer Neustart |
|
||||||
|
| 28-29 | `ports: "80:80", "443:443"` | Nur Proxy bindet auf öffentliche Ports |
|
||||||
|
| 31-33 | `volumes: ./nginx, ./ssl` | Config und Zertifikate mounten |
|
||||||
|
|
||||||
|
### 5.4 Backend-Dockerfile (`backend/Dockerfile`)
|
||||||
|
|
||||||
|
| Zeile | Konfiguration | Beschreibung |
|
||||||
|
|-------|---------------|--------------|
|
||||||
|
| 1 | `FROM python:3.12-slim` | Schlankes Python-Image |
|
||||||
|
| 6 | `pip install --no-cache-dir` | Keine Paket-Cache im Image |
|
||||||
|
| 10 | `CMD ["uvicorn", ...]` | FastAPI mit Uvicorn starten |
|
||||||
|
|
||||||
|
### 5.5 Frontend-Dockerfile (`frontend/Dockerfile`)
|
||||||
|
|
||||||
|
| Zeile | Konfiguration | Beschreibung |
|
||||||
|
|-------|---------------|--------------|
|
||||||
|
| 1-9 | Multi-Stage Build | Node-Build → NGINX-Image |
|
||||||
|
| 11 | `FROM nginx:alpine` | Schlankes NGINX-Image für Produktion |
|
||||||
|
| 14 | `COPY --from=build /app/dist` | Nur Build-Artefakte kopieren |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Post-Mortem-Log
|
||||||
|
|
||||||
|
### Problem: Backend konnte keine Verbindung zur Datenbank herstellen
|
||||||
|
|
||||||
|
**Symptom**: Nach dem Start mit `docker compose up` zeigte der Backend-Container folgende Fehlermeldung:
|
||||||
|
|
||||||
|
```
|
||||||
|
sqlalchemy.exc.OperationalError: (asyncpg.exceptions.ConnectionDoesNotExistError)
|
||||||
|
connection to server at "db", port 5432 failed
|
||||||
|
```
|
||||||
|
|
||||||
|
**Analyse**:
|
||||||
|
|
||||||
|
1. **Container-Status geprüft**:
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
Der `db`-Container war im Status "starting", der `backend`-Container bereits im Status "running".
|
||||||
|
|
||||||
|
2. **Logs der Datenbank geprüft**:
|
||||||
|
```bash
|
||||||
|
docker compose logs db
|
||||||
|
```
|
||||||
|
Die Datenbank war noch dabei, die Initialisierung durchzuführen.
|
||||||
|
|
||||||
|
3. **Ursache identifiziert**: Der `depends_on` Eintrag im `docker-compose.yml` wartet nur, bis der Container gestartet ist, nicht bis die Datenbank tatsächlich bereit ist, Verbindungen anzunehmen.
|
||||||
|
|
||||||
|
**Lösung**:
|
||||||
|
|
||||||
|
Die `lifespan`-Funktion in `backend/app/main.py` wurde implementiert, die beim Start der Anwendung die Datenbank-Tabellen erstellt:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
async with engine.begin() as conn:
|
||||||
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
yield
|
||||||
|
```
|
||||||
|
|
||||||
|
Zusätzlich wurde ein `restart: unless-stopped` Policy für alle Container konfiguriert, sodass der Backend-Container bei einem fehlgeschlagenen Start automatisch neu gestartet wird und es erneut versucht, sobald die Datenbank bereit ist.
|
||||||
|
|
||||||
|
**Verifikation**:
|
||||||
|
```bash
|
||||||
|
docker compose logs backend
|
||||||
|
# Erfolgreiche Ausgabe: "INFO: Uvicorn running on http://0.0.0.0:8000"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Screenshots
|
||||||
|
|
||||||
|
> **Hinweis**: Die folgenden Screenshots müssen nach der Deployment-Manual erstellt werden.
|
||||||
|
|
||||||
|
### 7.1 Container-Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
*Erwartete Ausgabe:*
|
||||||
|
```
|
||||||
|
NAME STATUS PORTS
|
||||||
|
proxy Up 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
|
||||||
|
frontend Up 80/tcp
|
||||||
|
backend Up 8000/tcp
|
||||||
|
db Up 5432/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 HTTPS-Verbindung testen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -I https://static.155.116.167.89.clients.your-server.de
|
||||||
|
```
|
||||||
|
|
||||||
|
*Erwartete Ausgabe (Auszug):*
|
||||||
|
```
|
||||||
|
HTTP/2 200
|
||||||
|
strict-transport-security: max-age=63072000; includeSubDomains
|
||||||
|
x-frame-options: DENY
|
||||||
|
x-content-type-options: nosniff
|
||||||
|
referrer-policy: strict-origin-when-cross-origin
|
||||||
|
permissions-policy: geolocation=(), camera=(), microphone=()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 HTTP → HTTPS Redirect testen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -I http://static.155.116.167.89.clients.your-server.de
|
||||||
|
```
|
||||||
|
|
||||||
|
*Erwartete Ausgabe:*
|
||||||
|
```
|
||||||
|
HTTP/1.1 301 Moved Permanently
|
||||||
|
Location: https://static.155.116.167.89.clients.your-server.de/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4 API-Endpoint testen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Paste erstellen
|
||||||
|
curl -X POST https://static.155.116.167.89.clients.your-server.de/api/pastes \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"content": "Test Paste"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
*Erwartete Ausgabe:*
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||||
|
"delete_token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||||
|
"created_at": "2026-01-01T12:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.5 Paste abrufen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Paste anzeigen (ID aus vorheriger Antwort einsetzen)
|
||||||
|
curl https://static.155.116.167.89.clients.your-server.de/api/pastes/<ID>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.6 Admin-Authentifizierung testen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ohne Passwort (sollte 401 liefern)
|
||||||
|
curl https://static.155.116.167.89.clients.your-server.de/api/admin/pastes
|
||||||
|
|
||||||
|
# Mit Passwort
|
||||||
|
curl -H "X-Admin-Password: <ADMIN_PASSWORD>" \
|
||||||
|
https://static.155.116.167.89.clients.your-server.de/api/admin/pastes
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.7 Server-Header prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sI https://static.155.116.167.89.clients.your-server.de | grep -i server
|
||||||
|
```
|
||||||
|
|
||||||
|
*Erwartete Ausgabe: Keine `Server`-Zeile vorhanden (Header wurde entfernt)*
|
||||||
|
|
||||||
|
### 7.8 Frontend-Oberfläche
|
||||||
|
|
||||||
|
*Screenshot der Startseite unter `https://static.155.116.167.89.clients.your-server.de`*
|
||||||
|
|
||||||
|
*Screenshot der Paste-Ansicht mit View-Link und Delete-Link*
|
||||||
|
|
||||||
|
*Screenshot des Admin-Bereichs unter `/admin`*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Anhang: Dateistruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
├── docker-compose.yml # Container-Orchestrierung
|
||||||
|
├── .env # Umgebungsvariablen (nicht im Repo)
|
||||||
|
├── .gitignore
|
||||||
|
├── dokumentation.md # Diese Dokumentation
|
||||||
|
├── nginx/
|
||||||
|
│ └── nginx.conf # Reverse-Proxy-Konfiguration
|
||||||
|
├── ssl/
|
||||||
|
│ ├── cert.pem # Öffentliches Zertifikat
|
||||||
|
│ ├── key.pem # Privater Schlüssel
|
||||||
|
│ └── README.md # Anleitung für Zertifikat
|
||||||
|
├── backend/
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ ├── requirements.txt
|
||||||
|
│ └── app/
|
||||||
|
│ ├── main.py # FastAPI-Anwendung
|
||||||
|
│ ├── models.py # SQLAlchemy-Modelle
|
||||||
|
│ ├── schemas.py # Pydantic-Schemas
|
||||||
|
│ ├── database.py # Datenbankverbindung
|
||||||
|
│ └── config.py # Konfiguration
|
||||||
|
└── frontend/
|
||||||
|
├── Dockerfile
|
||||||
|
├── nginx.conf # Frontend-NGINX-Konfiguration
|
||||||
|
├── package.json
|
||||||
|
├── vite.config.ts
|
||||||
|
├── tsconfig.json
|
||||||
|
├── index.html
|
||||||
|
└── src/
|
||||||
|
├── main.tsx # React-Einstiegspunkt
|
||||||
|
├── App.tsx # Layout
|
||||||
|
├── api/client.ts # API-Funktionen
|
||||||
|
└── pages/
|
||||||
|
├── HomePage.tsx # Paste erstellen
|
||||||
|
├── PastePage.tsx # Paste anzeigen
|
||||||
|
└── AdminPage.tsx # Admin-Bereich
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user