# Ticket 10.8 — Onboarding HTTP Server for TLS Bootstrap

**Phase**: 10 — Feature Parity Enhancements
**Priority**: Low
**Depends on**: None

## Description

When TLS/HTTPS is active, serve a plain HTTP server on port+1 specifically for CA certificate download and the setup wizard. This solves the chicken-and-egg problem: a user connecting to the relay for the first time on a new device can't visit the HTTPS setup page because their browser doesn't trust the self-signed certificate yet.

claude-relay runs a secondary HTTP server that serves:

- The CA root certificate download endpoint (`/ca/download`)
- A setup/onboarding page with instructions for installing the certificate
- A redirect to the main HTTPS server for all other routes

conduit already had an `onboarding.ts` module (ticket 2.6) but it was removed during the Svelte migration (S8.10). This ticket re-introduces the concept as a lightweight HTTP-only server for TLS bootstrap, integrated with the daemon.

## Acceptance Criteria

### AC1: HTTP server starts on port+1 when TLS is enabled
```gherkin
Given the relay is configured with TLS/HTTPS on port 4080
When the relay starts
Then a plain HTTP server starts listening on port 4081
  And the HTTP server accepts connections without TLS
  And the HTTPS server continues to operate on port 4080
```

### AC2: CA certificate download endpoint
```gherkin
Given the HTTP onboarding server is running on port 4081
When a client sends GET /ca/download
Then the server responds with 200 and Content-Type "application/x-x509-ca-cert"
  And the response body contains the PEM-encoded CA root certificate
  And the Content-Disposition header suggests a filename (e.g., "conduit-ca.crt")
```

### AC3: Setup page with certificate installation instructions
```gherkin
Given the HTTP onboarding server is running on port 4081
When a client sends GET / or GET /setup
Then the server responds with an HTML page
  And the page contains instructions for installing the CA certificate on iOS, Android, macOS, and Windows
  And the page contains a download link pointing to /ca/download
  And the page detects the client's platform and highlights the relevant instructions
```

### AC4: Non-setup routes redirect to HTTPS
```gherkin
Given the HTTP onboarding server is running on port 4081
When a client sends GET /api/sessions or any path not matching /ca/* or /setup
Then the server responds with 301 Moved Permanently
  And the Location header points to the equivalent HTTPS URL on the main server port
```

### AC5: No authentication required on HTTP server
```gherkin
Given the relay has PIN authentication enabled
When a client accesses the HTTP onboarding server on port 4081
Then the /ca/download endpoint responds without requiring a PIN
  And the /setup page renders without requiring a PIN
  And this allows first-time device setup before the user can access the authenticated HTTPS server
```

### AC6: HTTP server binds to same interfaces
```gherkin
Given the relay is configured to bind to 0.0.0.0 (all interfaces)
When the HTTP onboarding server starts
Then it also binds to 0.0.0.0
  And it is accessible from other devices on the local network
```

### AC7: QR code points to HTTP setup page
```gherkin
Given the relay is running with TLS enabled on port 4080
When the relay displays or generates a QR code for device setup
Then the QR code URL points to http://<host>:4081/setup (HTTP, not HTTPS)
  And scanning the QR code on a new device opens the setup page without certificate errors
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| HTTP server starts on port+1 when TLS enabled | Unit | When TLS config is present, `createOnboardingServer()` returns an HTTP server listening on configured port + 1; when TLS is disabled, no onboarding server is created |
| CA certificate download endpoint | Unit | GET /ca/download returns 200 with correct Content-Type, Content-Disposition header, and valid PEM certificate body |
| Setup page rendering with instructions | Unit | GET /setup returns 200 with HTML containing platform-specific installation instructions and a link to /ca/download |
| Non-setup routes redirect to HTTPS | Unit | GET /api/sessions returns 301 with Location header pointing to the HTTPS equivalent URL on the main port |
| No auth required on HTTP server | Unit | Requests to /ca/download and /setup succeed without PIN header or cookie; middleware stack does not include auth checks |

## Reference

- claude-relay onboarding HTTP: `../claude-relay/lib/server.js` (HTTP + HTTPS dual server, onboarding on port+1)
- Removed onboarding module: `conduit/src/lib/onboarding.ts` (deleted in S8.10)
- TLS management: `conduit/src/lib/tls.ts`
- Daemon: `conduit/src/lib/daemon.ts`
