Skip to content
··9 Min. Lesezeit

Der HTTP/HTTPS-Debugging-Alptraum: Eine 24-stündige Reise durch die Mixed-Content-Hölle

Ich habe 24 Stunden damit verbracht zu debuggen, warum meine React-App weiterhin HTTP-Anfragen von HTTPS-Seiten machte – obwohl mein Code sie konvertierte. Der Schuldige hat mich schockiert.

---

Update (November 2025): STRAŦUM ist jetzt in der Private Alpha live! Die in diesem Beitrag erwähnte 9-Agenten-Marketing-Plattform nimmt frühzeitige Tester auf. Zugang anfragen unter stratum.chandlernguyen.com oder lies die vollständige Launch-Geschichte.

---

Kontext: Die Marketing-Plattform-Reise geht weiter

Erinnerst du dich an den September-Beitrag, in dem ich erzählt habe, dass ich eine 10-Agenten-Marketing-Plattform im Speedrun baue, während ich Nickerchen mache? Vier Wochen später hatte ich 3 funktionierende Agenten und strebte einen Alpha-Launch im Oktober/November an.

Jetzt ist es Ende Oktober. Zeit für ein Fortschritts-Update.

Die guten Nachrichten:

- Die Plattform hat endlich einen Namen: STRAŦUM (Intelligence Over Execution)

- Vollständige Brand Guidelines und Design System (es stellt sich heraus, dass Branding länger dauert als Coding)

- 9 von 10 Agenten gebaut und integriert

- Multi-Tenant-Architektur funktioniert tatsächlich

- Letzter Schritt: Vorbereitung für Pre-Alpha, nur auf Einladung

Der Realitätscheck:

Ich war 10 Tage lang krank, nachdem ich 8 Tage im Urlaub war (das Leben passiert eben). Das hat alles auf Pause gesetzt und meinen Zeitplan verschoben. So viel für den Oktober-Launch, oder?

Aber hier ist das Ding mit der Solo-Entwicklung: Du kontrollierst das Tempo. Kein Druck zu shippen, wenn du nicht bereit bist. Keine Investoren, die dir im Nacken sitzen. Einfach... es richtig machen.

Dieser Blogbeitrag handelt von einem jener "es richtig machen"-Momente, die sich in einen 6-stündigen Debugging-Marathon verwandelt hat. Denn genau als ich nach der Krankheit wieder in Fahrt kam, hatte meine Deployment-Plattform andere Pläne.

Wenn AWS ausfällt, werden Ingenieure kreativ (und bereuen es manchmal)

Hier ist etwas, das man in Coding-Bootcamps nicht lernt: Manchmal verschwindet deine Deployment-Plattform einfach. Nicht wegen etwas, das du falsch gemacht hast, sondern weil AWS einen weitreichenden Ausfall hatte, der Vercel-Deployments weltweit beeinflusste.

So begann mein Montag. Meine Produktions-Site war unten, Vercel zeigte Fehler, und ich hatte genau einen Gedanken: "Ich brauche ein Backup. Schnell."

Enter Cloudflare Pages. Ich hatte Gutes gehört. Tolles CDN, automatische Deployments, einfaches Setup. Was könnte schiefgehen?

Erzähler: Alles. Alles konnte schiefgehen.

Der Wechsel, der zu einfach schien

Die Migration zu Cloudflare Pages war überraschend reibungslos. GitHub-Repo verbunden, Umgebungsvariablen im Dashboard gesetzt, zu main gepusht. Drei Minuten später: deployed.

"Wow", dachte ich. "Das ist fast zu einfach."

Dann öffnete ich die Produktions-Site.

```
Mixed Content: The page at 'https://my-site.com/...' was loaded over HTTPS,
but requested an insecure resource 'http://stratum-api.us-central1.run.app/...'
```

Das sinkende Gefühl, wenn man merkt, dass die Vorfreude verfrüht war? Ja, genau das.

Das Problem: HTTP-Anfragen von einer HTTPS-Seite

Meine React-App machte HTTP-Anfragen an meine Backend-API, während die Seite selbst über HTTPS geladen wurde. Browser blockieren das (zu Recht) als Sicherheitsrisiko. Mixed Content-Fehler. Jeder einzelne API-Aufruf schlug fehl.

"Aber warte", sagte ich mir, "ich habe `ensureHttpsInProduction()` in meinem Code! Es soll HTTP automatisch zu HTTPS konvertieren!"

Ich habe das deployed Bundle überprüft. Die Funktion war da. Die Logik war korrekt. Die Browser-Konsole zeigte, dass die Konvertierung stattfand. Warum kamen also immer noch HTTP-Anfragen durch?

Erster Debugging-Versuch: Die Suche nach Umgebungsvariablen

Vielleicht wurden die Umgebungsvariablen in Cloudflare nicht aufgenommen?

```bash
# Cloudflare Dashboard überprüft
VITE_API_URL=https://stratum-api.us-central1.run.app ✓
VITE_SUPABASE_URL=https://your-project.supabase.co ✓
```

Alles HTTPS. Alles korrekt.

Ich habe einen Rebuild ausgelöst. Gewartet. Deployed. Site geöffnet.

Gleicher Fehler. Immer noch HTTP-Anfragen.

Zweiter Versuch: Der große Re-Import

Vielleicht verwendeten Dateien nicht die zentralisierte `API_BASE_URL`?

Ich habe die nächste Stunde damit verbracht, 24 Dateien zu aktualisieren, damit sie aus `@/lib/api` importieren, anstatt direkt `import.meta.env.VITE_API_URL` zu verwenden. Jede Komponente, die API-Aufrufe machte, wurde behandelt.

```typescript
// Vorher
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/v1/...`);

// Nachher
import \{ API_BASE_URL \} from '@/lib/api';
const response = await fetch(`$\{API_BASE_URL\}/api/v1/...`);
```

Gepusht. Deployed. Gewartet.

Immer noch kaputt.

An diesem Punkt fange ich an, meine Lebensentscheidungen in Frage zu stellen.

Die Wendung: Fehlende Dateien in Git

Aber warte, es wird noch schlimmer.

Während ich untersuchte, warum meine HTTPS-Durchsetzung nicht funktionierte, entdeckte ich etwas Schreckliches. Die `api.ts`-Datei, die `ensureHttpsInProduction()` enthielt, war nicht einmal in meinem Git-Repo.

Auch `authService.ts` nicht. Oder `csvSanitizer.ts`. Drei kritische Frontend-Dateien, einfach... fehlend.

Wie? Die `.gitignore`-Datei hatte folgendes:

```
# Python stuff
lib/
build/
dist/
```

Vernünftig für Python, oder? Außer dass meine Frontend-Utilities in `apps/web/src/lib/` lagen. Das breite `lib/`-Muster ignorierte versehentlich mein gesamtes Frontend-Lib-Verzeichnis!

Das bedeutete:

1. Cloudflare baute aus dem Repo (ohne diese Dateien)

2. Meine lokale Entwicklung hatte diese Dateien (funktionierte lokal gut)

3. Ich hatte KEINE AHNUNG, dass sie nicht getrackt wurden

Der Fix:

```diff
# .gitignore - Vorher
-lib/

# .gitignore - Nachher
+apps/api/lib/  # Python-spezifisch
+!apps/web/src/lib/  # Frontend lib explizit einschließen
```

Die fehlenden Dateien hinzugefügt, committed, gepusht. Jetzt hatte Cloudflare den HTTPS-Durchsetzungscode!

Außer... die HTTP-Fehler gingen weiter.

Dritter Versuch: Build-Zeit-Validierung

An diesem Punkt hinterfrage ich alles. "Weißt du was?", dachte ich. "Wenn das immer wieder passiert, muss ich es VERHINDERN, jemals in die Produktion zu gelangen."

Ich habe ein Vite-Plugin geschrieben, das den Build scheitern lässt, wenn HTTP-URLs in der Produktion erkannt werden:

```typescript
function validateProductionUrls(mode: string) \{
  if (mode !== 'production') return;

  const apiUrl = process.env.VITE_API_URL || '';

  if (apiUrl && apiUrl.trim().startsWith('http://')) {
    if (!apiUrl.includes('localhost') && !apiUrl.includes('127.0.0.1')) {
      throw new Error(
        `❌ HTTPS ENFORCEMENT FAILED

        Environment Variable: VITE_API_URL
        Current Value: ${apiUrl\}

        This will cause Mixed Content errors in production!`
      );
    }
  }
}
```

Genial, oder? Jetzt ist es UNMÖGLICH, mit HTTP-URLs zu deployen.

Erneut deployed. Build bestanden (Umgebungsvariablen waren HTTPS). Site geladen.

Gleicher. Verdammter. Fehler.

Der Geistesblitz: Lokale Dateien wurden deployed

Spät (sehr spät) am Abend hatte ich eine Erkenntnis.

Ich habe das deployed JavaScript-Bundle erneut überprüft. Diesmal wirklich hingeschaut. Die URL darin war:

```javascript
"http://stratum-api.us-central1.run.app"
```

Aber meine Cloudflare-Umgebungsvariablen waren HTTPS. Woher kam also diese HTTP-URL?

Dann fiel es mir ein. Meine lokale `.env.production`-Datei.

```bash
# apps/web/.env.production (LOKALE DATEI)
VITE_API_URL=http://stratum-api.us-central1.run.app
```

Cloudflare Pages hat meine lokale Umgebungsdatei deployed, anstatt die Dashboard-Variablen zu verwenden!

Ich habe `.cloudflare-pages-ignore` überprüft:

```
# Environment files
.env
.env.local
.env.development
.env.test
# .env.production  ← FEHLEND!
```

Facepalm.

Der Fix: Eine Zeile

```diff
# apps/web/.cloudflare-pages-ignore
.env
.env.local
.env.development
.env.test
+.env.production
```

Deployed. Gewartet.

Diesmal ein anderer Fehler! Fortschritt!

```
Access to fetch at 'https://stratum-api.us-central1.run.app/...'
from origin 'https://preview-xyz.stratum-marketing-suite.pages.dev'
has been blocked by CORS policy
```

CORS-Fehler! Wunderschöne, wunderschöne CORS-Fehler! Das bedeutete, HTTPS funktionierte!

Aber warte, es gibt noch mehr: Die Cache-Verschwörung

CORS behoben. Erneut deployed. Meine Custom-Domain geöffnet.

Wieder HTTP-Fehler.

Was?!

Wie sich herausstellte, hat Cloudflares CDN das alte Bundle aggressiv gecacht. Das neue Deployment (mit HTTPS) war auf der Preview-URL live, aber meine Custom-Domain lieferte gecachten Inhalt mit HTTP-URLs.

Cloudflares Cache-Bereinigung erfordert:

1. Die richtigen Zoneneinstellungen finden (nicht im Pages Dashboard)

2. Durch Domain-Einstellungen navigieren (nicht offensichtlich)

3. Cache manuell bereinigen (für jedes Deployment)

Nach stundenlangem Debugging von HTTP/HTTPS-Problemen traf ich eine Entscheidung.

Die Rückkehr zu Vercel: Manchmal ist Langweilig besser

AWS war wieder online. Vercel funktionierte wieder.

Ich habe alles zurück zu Vercel migriert. Warum?

1. Automatische Cache-Invalidierung – Kein manuelles Bereinigen erforderlich

2. Einfachere Handhabung von Umgebungsvariablen – Was du setzt, ist was du bekommst

3. Schnelleres Debugging – Weniger Infrastruktur zum Nachdenken

4. Bewährt – Ich kenne seine Eigenheiten

Das Vercel-Deployment dauerte 3 Minuten. Keine HTTP-Fehler. Keine Cache-Probleme. Es hat einfach... funktioniert.

Was ich gelernt habe (auf die harte Tour)

1. Immer .env.production in Deployment-Plattformen ignorieren

```
# .vercelignore
# .cloudflare-pages-ignore
# .netlify-ignore
.env
.env.local
.env.development
.env.test
.env.production  ← DAS NICHT VERGESSEN
```

2. Breite .gitignore-Muster sind in Monorepos gefährlich

```diff
# ❌ Schlecht – ignoriert Frontend UND Backend lib-Ordner
-lib/
-build/
-dist/

# ✅ Gut – spezifisch für jeden Kontext
+apps/api/lib/      # Python-spezifisch
+apps/api/build/
+apps/api/dist/
+apps/web/dist/     # Nur Vite-Output
```

Immer fragen: "Könnte dieses Muster versehentlich etwas Wichtiges ignorieren?"

In einem Monorepo mit mehreren Sprachen (Python + TypeScript) können breite Muster, die für ein Ökosystem gedacht sind, versehentlich kritische Dateien in einem anderen ignorieren.

3. Build-Zeit-Validierung lohnt sich trotzdem

Auch wenn es das Problem mit der lokalen Datei nicht abgefangen hat, verhindert die Build-Zeit-Validierung zukünftige Fehlkonfigurationen:

```typescript
// vite.config.ts
export default defineConfig((\{ mode \}) => \{
  validateProductionUrls(mode);
  return {
    // ... config
  \};
});
```

4. Multi-Layer-Verteidigung funktioniert

Unsere finale Architektur hat DREI Schichten:

- Build-Zeit: Schlägt fehl, wenn HTTP-URLs erkannt werden

- Laufzeit: Konvertiert HTTP → HTTPS, wenn die Seite über HTTPS geladen wird

- Deployment: Schließt lokale .env-Dateien aus

5. Preview-URLs sind dein Freund

Teste immer zuerst auf der Preview-URL. Wenn das funktioniert, aber deine Custom-Domain nicht, liegt es normalerweise am Caching.

6. Kenne die Eigenheiten deiner Plattform

- Vercel: Einfach, invalidiert Cache automatisch, Umgebungsvariablen "funktionieren einfach"

- Cloudflare Pages: Tolles CDN, aber manuelles Cache-Bereinigen und komplexeres Setup

Der Code, der mich gerettet hat

Hier ist die finale `ensureHttpsInProduction()`-Funktion:

```typescript
function ensureHttpsInProduction(url: string): string \{
  // Nur im Browser-Kontext konvertieren, wenn die Site über HTTPS geladen wird
  if (typeof window !== 'undefined' && window.location.protocol === 'https:') {
    // localhost/127.0.0.1-URLs nicht konvertieren (lokale Entwicklung)
    if (url.startsWith('http://') &&
        !url.includes('localhost') &&
        !url.includes('127.0.0.1')) {
      console.warn('[API] Converting HTTP to HTTPS:', url);
      return url.replace('http://', 'https://');
    \}
  }
  return url;
}
```

Und die Build-Zeit-Validierung in `vite.config.ts`:

```typescript
function validateProductionUrls(mode: string) \{
  if (mode !== 'production') return;

  const apiUrl = process.env.VITE_API_URL || '';

  // Auf HTTP prüfen (sollte HTTPS sein)
  if (apiUrl && apiUrl.trim().startsWith('http://')) {
    if (!apiUrl.includes('localhost') && !apiUrl.includes('127.0.0.1')) {
      throw new Error(`
❌ HTTPS ENFORCEMENT FAILED

Environment Variable: VITE_API_URL
Current Value: ${apiUrl\}

Mixed Content Error Prevention:
Browsers block HTTP requests from HTTPS pages.

Fix: Update environment variables to use HTTPS URLs.
      `);
    }
  }
}
```

Die eigentliche Lektion: Debugging ist Detektivarbeit

Das war kein Coding-Problem. Es war eine Konfigurationsarchäologie-Expedition.

Die eigentlichen Bugs waren:

1. ✅ Breite `.gitignore`-Muster, die kritische Frontend-Dateien ignorierten

2. ✅ Fehlendes `.env.production` in `.cloudflare-pages-ignore`

3. ✅ Aggressives CDN-Caching, das den Fix verdeckte

4. ✅ Annahme über Umgebungsvariablen-Priorität

Die technische Lösung war eine Zeile in einer `.ignore`-Datei.

Das Debugging? Das dauerte 6 Stunden, 14 Deployments und viel zu viel Kaffee.

War es das wert?

Absolut. Hier ist, was ich gewonnen habe:

1. Tiefes Verständnis der Mixed Content-Sicherheitsrichtlinien

2. Build-Zeit-Validierung, die zukünftige Probleme verhindert

3. Multi-Layer HTTPS-Durchsetzung, die plattformunabhängig ist

4. Echte Wertschätzung für Vercels Einfachheit

Und am wichtigsten: eine tolle Debugging-Geschichte zum Teilen. :P

Das Git-Log erzählt die Geschichte

```bash
2033b9a fix: add .env.production to .vercelignore
3555390 docs: migrate deployment documentation from Cloudflare Pages to Vercel
a4edb09 chore: force clean Cloudflare Pages rebuild
590c271 fix: enhance ensureHttpsInProduction logging
15d69c6 chore: force rebuild of UserProfile bundle
a1c345f fix: add .env.production to cloudflare-pages-ignore  ← DER .ENV FIX
635d80d docs: update documentation for Cloudflare Pages migration
edfa611 feat: add build-time HTTPS enforcement
802c1e9 fix: enforce HTTPS for all API calls across frontend
26f6b87 refactor: comprehensive .gitignore audit and cleanup
3758a9c fix: unignore frontend lib directory and add missing files  ← DER GITIGNORE FIX
```

Jeder Commit repräsentiert eine Stunde Debugging in der alten Welt, aber mit Claude Code war mein Tempo dank sei dem Himmel schneller. Eine getestete Hypothese. Eine gelernte Lektion.

Für andere Ingenieure, die mit Mixed Content-Fehlern kämpfen

Falls du das liest, weil du dasselbe Problem debuggst, hier ist deine Checkliste:

1. Überprüfe deine Umgebungsvariablen:

```bash
# Tatsächlich verwendete Werte ausgeben
console.log('API URL:', import.meta.env.VITE_API_URL);
```

2. Überprüfe dein deployed Bundle:

```bash
# Das JavaScript-Bundle herunterladen und durchsuchen
curl https://your-site.com/assets/index-ABC123.js | grep "http://"
```

3. Überprüfe deine Ignore-Dateien:

```bash
# Sicherstellen, dass .env.production ausgeschlossen ist
cat .vercelignore
cat .cloudflare-pages-ignore
cat .netlify-ignore
```

4. Überprüfe deine .gitignore (Monorepos):

```bash
# Sicherstellen, dass kritische Dateien nicht ignoriert werden
git ls-files apps/web/src/lib/  # Sollte api.ts etc. zeigen

# Wenn leer, auf breite Muster prüfen
grep "^lib/" .gitignore          # ❌ Zu breit
grep "^apps/api/lib/" .gitignore # ✅ Spezifisch
```

5. Überprüfe deinen Cache:

```bash
# Zuerst auf der Preview-URL testen
# Wenn Preview funktioniert, aber Produktion nicht = Cache-Problem
```

6. Build-Zeit-Validierung hinzufügen:

```typescript
// Verhindern, dass es jemals wieder passiert
if (mode === 'production' && url.startsWith('http://')) \{
  throw new Error('HTTPS required in production!');
\}
```

Die Migrations-Checkliste, die ich gerne gehabt hätte

Beim Wechsel von Deployment-Plattformen:

- [ ] Alle Umgebungsvariablen von der alten Plattform auflisten

- [ ] Umgebungsvariablen ZUERST in der neuen Plattform einrichten

- [ ] ALLE .env-Dateien zu .ignore hinzufügen (einschließlich .env.production)

- [ ] Verifizieren, dass .gitignore keine kritischen Dateien ignoriert (git ls-files ausführen)

- [ ] Auf der Preview-URL vor der Custom-Domain testen

- [ ] Deployed Bundle auf HTTP-URLs prüfen

- [ ] CORS-Einstellungen verifizieren, wenn das Backend separat ist

- [ ] Plattformspezifische Eigenheiten dokumentieren

Immer noch am Coden, immer noch am Lernen, manchmal immer noch kaputt

Sechs Stunden Debugging für einen Ein-Zeilen-Fix. Das ist Software-Engineering in einer Nussschale.

Der Code, den wir ausliefern, ist wichtig, sicher. Aber die Debugging-Fähigkeiten, die wir entwickeln? Das ist, was uns zu besseren Ingenieuren macht.

Wenn meine Deployment-Plattform das nächste Mal ausfällt (und das wird passieren), werde ich bereit sein. Ich habe:

- ✅ Plattformunabhängige HTTPS-Durchsetzung

- ✅ Build-Zeit-Validierung

- ✅ Besseres Verständnis der Umgebungsvariablen-Priorität

- ✅ Eine Backup-Deployment-Strategie

Und hoffentlich wird dieser Blogbeitrag jemandem einige dieser 6 Stunden ersparen. :)

Hattest du jemals einen "Ein-Zeilen-Fix", den du beschämend lange zu finden gebraucht hast? Ich würde gerne deine Debugging-Detektivgeschichten hören – Elend liebt Gesellschaft!

Viele Grüße,

Chandler

Weiterlesen

Mein Weg
Vernetzen
Sprache
Einstellungen