Configure Caddy reverse proxy for palinks.app on edge-proxy #425

Closed
opened 2026-06-13 13:39:39 +00:00 by ldraney · 2 comments
Owner

Type

Feature

Lineage

Related to ldraney/pal-e-platform #435 (DNS A record must be set first before Caddy can serve traffic).

Repo

ldraney/pal-e-platform

User Story

As a platform operator
I want Caddy on the edge node to reverse-proxy palinks.app with automatic TLS
So that public traffic reaches the k8s service without manual certificate management

Context

Caddy is installed on the edge-proxy VPS (178.156.129.142) via cloud-init but has no site blocks configured yet. The edge VPS serves as the public ingress point — DNS A records point domains here, and Caddy reverse-proxies traffic over Tailscale to internal k8s services.

Decision: Salt state management (not manual SSH). All Caddy configuration will be managed through Salt states so that changes are reproducible, auditable, and recoverable. Manual SSH edits to /etc/caddy/Caddyfile are explicitly rejected.

The Caddyfile pattern for palinks.app:

  • palinks.app block with reverse_proxy to palinks.tail5b443a.ts.net:443 using tls_server_name transport
  • www.palinks.app block with permanent redirect to palinks.app
  • Caddy handles Let's Encrypt TLS automatically

File Targets

Files the agent should create:

  • salt/states/caddy/init.sls -- Salt state for Caddy package, service, and Caddyfile deployment
  • salt/states/caddy/Caddyfile.j2 -- Jinja2 template for the Caddyfile with palinks.app site blocks

Files the agent should NOT touch:

  • salt/states/cloud-init/ -- Caddy install is handled there already; this ticket only adds site config
  • Any DNS or Terraform files -- DNS is handled by #435

Feature Flag

none

Acceptance Criteria

  • Salt state salt/states/caddy/init.sls applies successfully on edge-proxy
  • curl -I https://palinks.app returns HTTP 200
  • curl -I https://www.palinks.app returns HTTP 301 redirect to https://palinks.app
  • TLS certificate is valid and issued by Let's Encrypt
  • Reverse proxy target is palinks.tail5b443a.ts.net:443 with correct tls_server_name transport

Test Expectations

  • Manual: apply Salt state on edge-proxy, verify Caddy reloads without error
  • Manual: curl -I https://palinks.app returns 200 with valid TLS
  • Manual: curl -I https://www.palinks.app returns 301 to https://palinks.app
  • Run command: salt 'edge-proxy' state.apply caddy

Constraints

  • DNS A record for palinks.app must be set first (pal-e-platform #435) — Caddy cannot obtain a TLS certificate until DNS resolves to the edge VPS
  • Blast radius: The edge VPS (178.156.129.142) is a shared ingress point serving multiple domains. A Caddyfile misconfiguration or syntax error could break routing for ALL domains, not just palinks.app. Test Caddyfile syntax (caddy validate) before reload.
  • Follow existing Salt state patterns in the repo
  • Caddy handles TLS automatically via ACME — do not configure certificates manually

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • pal-e-platform -- project this affects
  • ldraney/pal-e-platform #435 -- DNS A record prerequisite
### Type Feature ### Lineage Related to `ldraney/pal-e-platform #435` (DNS A record must be set first before Caddy can serve traffic). ### Repo `ldraney/pal-e-platform` ### User Story As a platform operator I want Caddy on the edge node to reverse-proxy palinks.app with automatic TLS So that public traffic reaches the k8s service without manual certificate management ### Context Caddy is installed on the edge-proxy VPS (178.156.129.142) via cloud-init but has no site blocks configured yet. The edge VPS serves as the public ingress point — DNS A records point domains here, and Caddy reverse-proxies traffic over Tailscale to internal k8s services. Decision: Salt state management (not manual SSH). All Caddy configuration will be managed through Salt states so that changes are reproducible, auditable, and recoverable. Manual SSH edits to `/etc/caddy/Caddyfile` are explicitly rejected. The Caddyfile pattern for palinks.app: - `palinks.app` block with `reverse_proxy` to `palinks.tail5b443a.ts.net:443` using `tls_server_name` transport - `www.palinks.app` block with permanent redirect to `palinks.app` - Caddy handles Let's Encrypt TLS automatically ### File Targets Files the agent should create: - `salt/states/caddy/init.sls` -- Salt state for Caddy package, service, and Caddyfile deployment - `salt/states/caddy/Caddyfile.j2` -- Jinja2 template for the Caddyfile with palinks.app site blocks Files the agent should NOT touch: - `salt/states/cloud-init/` -- Caddy install is handled there already; this ticket only adds site config - Any DNS or Terraform files -- DNS is handled by `#435` ### Feature Flag none ### Acceptance Criteria - [ ] Salt state `salt/states/caddy/init.sls` applies successfully on edge-proxy - [ ] `curl -I https://palinks.app` returns HTTP 200 - [ ] `curl -I https://www.palinks.app` returns HTTP 301 redirect to `https://palinks.app` - [ ] TLS certificate is valid and issued by Let's Encrypt - [ ] Reverse proxy target is `palinks.tail5b443a.ts.net:443` with correct `tls_server_name` transport ### Test Expectations - [ ] Manual: apply Salt state on edge-proxy, verify Caddy reloads without error - [ ] Manual: `curl -I https://palinks.app` returns 200 with valid TLS - [ ] Manual: `curl -I https://www.palinks.app` returns 301 to `https://palinks.app` - Run command: `salt 'edge-proxy' state.apply caddy` ### Constraints - DNS A record for palinks.app must be set first (`pal-e-platform #435`) — Caddy cannot obtain a TLS certificate until DNS resolves to the edge VPS - **Blast radius:** The edge VPS (178.156.129.142) is a shared ingress point serving multiple domains. A Caddyfile misconfiguration or syntax error could break routing for ALL domains, not just palinks.app. Test Caddyfile syntax (`caddy validate`) before reload. - Follow existing Salt state patterns in the repo - Caddy handles TLS automatically via ACME — do not configure certificates manually ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `pal-e-platform` -- project this affects - `ldraney/pal-e-platform #435` -- DNS A record prerequisite
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1465-2026-06-14

Issue body contains all necessary information but is written as free-form prose instead of following the template-issue-feature structure. Traceability is mostly complete but the backing architecture note is missing.

Issues found:

  • Issue body does not follow template-issue-feature -- needs restructuring into standard sections (Type, Lineage, Repo, User Story, File Targets, Acceptance Criteria, etc.)
  • Option A vs Option B not resolved -- agent needs a single clear path (Option B / Salt state is preferred)
  • Missing file target: salt/states/caddy/Caddyfile.j2 template if Option B is chosen
  • Missing acceptance criterion for Salt state application
  • Missing blast radius warning about other domains on the shared VPS
  • [SCOPE] Missing architecture note arch-pal-e-platform in pal-e-docs
## Scope Review: NEEDS_REFINEMENT Review note: `review-1465-2026-06-14` Issue body contains all necessary information but is written as free-form prose instead of following the `template-issue-feature` structure. Traceability is mostly complete but the backing architecture note is missing. **Issues found:** - Issue body does not follow `template-issue-feature` -- needs restructuring into standard sections (Type, Lineage, Repo, User Story, File Targets, Acceptance Criteria, etc.) - Option A vs Option B not resolved -- agent needs a single clear path (Option B / Salt state is preferred) - Missing file target: `salt/states/caddy/Caddyfile.j2` template if Option B is chosen - Missing acceptance criterion for Salt state application - Missing blast radius warning about other domains on the shared VPS - `[SCOPE]` Missing architecture note `arch-pal-e-platform` in pal-e-docs
Author
Owner

Scope Review: APPROVED

Review note: review-1465-2026-06-14-v2

Re-review after refinement. All 5 [BODY] recommendations from initial review are resolved. Issue now follows full template-issue-feature structure with all 12 required sections present.

Key findings:

  • Template completeness: 12/12 sections present
  • Traceability: story:custom-domain verified on project-palinks, arch:pal-e-platform label present (backing note deferred separately)
  • File targets verified: salt/states/caddy/init.sls and Caddyfile.j2 follow existing firewall/ pattern
  • Dependencies documented: blocked by #435 (DNS), #419 (edge node) already done
  • Blast radius addressed in Constraints section
  • 2 files, 5 AC, 1 repo -- fits single agent pass

Note for implementing agent: Salt minion is not currently installed on edge-proxy (cloud-init only installs Tailscale + Caddy). Bootstrap Salt minion before applying states.

## Scope Review: APPROVED Review note: `review-1465-2026-06-14-v2` Re-review after refinement. All 5 `[BODY]` recommendations from initial review are resolved. Issue now follows full `template-issue-feature` structure with all 12 required sections present. **Key findings:** - Template completeness: 12/12 sections present - Traceability: story:custom-domain verified on project-palinks, arch:pal-e-platform label present (backing note deferred separately) - File targets verified: `salt/states/caddy/init.sls` and `Caddyfile.j2` follow existing `firewall/` pattern - Dependencies documented: blocked by #435 (DNS), #419 (edge node) already done - Blast radius addressed in Constraints section - 2 files, 5 AC, 1 repo -- fits single agent pass **Note for implementing agent:** Salt minion is not currently installed on edge-proxy (cloud-init only installs Tailscale + Caddy). Bootstrap Salt minion before applying states.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/pal-e-platform#425
No description provided.