feat(backends+domains): HTTP-Protokoll-Flags — force_http1 + disable_h3

Backend: force_http1 (bool, default false) — zwingt HAProxy auf der
Backend-Verbindung zu HTTP/1.1 statt h2,http/1.1 zu verhandeln.
Nötig für Legacy-Apps die kein h2 sprechen.

Domain: disable_h3 (bool, default false) — unterdrückt Alt-Svc-
Response-Header für diese Domain. Browser erhalten keinen h3/QUIC-
Hinweis und bleiben auf h2/http1.1.

Migration 0027, Model+Service+HAProxy-Template+UI+i18n.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-22 07:18:48 +02:00
parent 6445e162a6
commit 8293783fe6
11 changed files with 78 additions and 24 deletions

View File

@@ -20,13 +20,13 @@ interface Backend {
id: number; name: string; scheme: string
health_check_path?: string | null
lb_algorithm: 'roundrobin' | 'leastconn' | 'source'
websocket: boolean; active: boolean
websocket: boolean; force_http1: boolean; active: boolean
}
interface BackendFormValues {
name: string; scheme: 'http' | 'https'
health_check_path?: string
lb_algorithm: 'roundrobin' | 'leastconn' | 'source'
websocket: boolean; active: boolean
websocket: boolean; force_http1: boolean; active: boolean
domain_ids?: number[]
}
interface BackendServer {
@@ -157,6 +157,7 @@ export default function BackendDetailPage() {
health_check_path: backend.health_check_path ?? undefined,
lb_algorithm: backend.lb_algorithm,
websocket: backend.websocket,
force_http1: backend.force_http1,
active: backend.active,
domain_ids: attached.map(d => d.id),
}}
@@ -184,6 +185,10 @@ export default function BackendDetailPage() {
extra={t('backends.websocketHint')}>
<Switch />
</Form.Item>
<Form.Item label={t('backends.forceHttp1')} name="force_http1" valuePropName="checked"
extra={t('backends.forceHttp1Hint')}>
<Switch />
</Form.Item>
<Form.Item label={t('backends.active')} name="active" valuePropName="checked">
<Switch />
</Form.Item>

View File

@@ -27,6 +27,7 @@ interface Domain {
maintenance_mode: boolean; maintenance_message?: string | null
www_redirect: '' | 'to-naked' | 'to-www'
rate_limit_rps: number; max_body_kb: number
disable_h3: boolean
notes?: string | null
}
@@ -39,6 +40,7 @@ interface DomainFormValues {
maintenance_mode: boolean; maintenance_message?: string
www_redirect: '' | 'to-naked' | 'to-www'
rate_limit_rps: number; max_body_kb: number
disable_h3: boolean
notes?: string
}
@@ -164,6 +166,7 @@ export default function DomainDetailPage() {
www_redirect: domain.www_redirect ?? '',
rate_limit_rps: domain.rate_limit_rps ?? 0,
max_body_kb: domain.max_body_kb ?? 0,
disable_h3: domain.disable_h3 ?? false,
notes: domain.notes ?? '',
}}
onFinish={(v) => update.mutate(v)}
@@ -244,6 +247,11 @@ export default function DomainDetailPage() {
<InputNumber min={0} step={64} style={{ width: '100%' }} addonAfter="KiB" />
</Form.Item>
<Form.Item label={t('domains.disableH3')} name="disable_h3" valuePropName="checked"
extra={t('domains.disableH3Hint')}>
<Switch />
</Form.Item>
<Form.Item label={t('domains.notes')} name="notes">
<Input.TextArea rows={2} />
</Form.Item>