feat: add Caddy reverse proxy for landscaping-assistant.app (#434) #442

Merged
ldraney merged 1 commit from 434-caddy-landscaping-assistant-app into main 2026-06-16 01:05:45 +00:00
Owner

Summary

  • Adds Caddy reverse proxy site blocks for landscaping-assistant.app to the Hetzner edge-proxy Caddyfile template
  • Follows the identical pattern established by palinks.app in PR #439
  • Enables public HTTPS ingress for landscaping-assistant.app once DNS is pointed to the edge VPS

Changes

  • salt/states/caddy/Caddyfile.j2: Added two site blocks — landscaping-assistant.app with reverse_proxy to landscaping-assistant.tail5b443a.ts.net:443 (TLS server name validated), and www.landscaping-assistant.app with permanent redirect to the apex domain

Test Plan

  • Existing palinks.app site blocks are unchanged in the diff
  • After merge and highstate, confirm Caddy reloads without error on the edge-proxy
  • Verify curl -I https://landscaping-assistant.app returns a valid response (once DNS is pointed)
  • Verify curl -I https://www.landscaping-assistant.app returns a 301 redirect to the apex domain

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • Feature flag needed? No — infrastructure config change, no user-visible workflow
  • Closes #434
  • ldraney/pal-e-platform #434 — Configure Caddy reverse proxy for landscaping-assistant.app on edge-proxy
## Summary - Adds Caddy reverse proxy site blocks for landscaping-assistant.app to the Hetzner edge-proxy Caddyfile template - Follows the identical pattern established by palinks.app in PR #439 - Enables public HTTPS ingress for landscaping-assistant.app once DNS is pointed to the edge VPS ## Changes - `salt/states/caddy/Caddyfile.j2`: Added two site blocks — `landscaping-assistant.app` with reverse_proxy to `landscaping-assistant.tail5b443a.ts.net:443` (TLS server name validated), and `www.landscaping-assistant.app` with permanent redirect to the apex domain ## Test Plan - [x] Existing palinks.app site blocks are unchanged in the diff - [ ] After merge and highstate, confirm Caddy reloads without error on the edge-proxy - [ ] Verify `curl -I https://landscaping-assistant.app` returns a valid response (once DNS is pointed) - [ ] Verify `curl -I https://www.landscaping-assistant.app` returns a 301 redirect to the apex domain ## Review Checklist - [ ] Passed automated review-fix loop - [ ] No secrets committed - [ ] No unnecessary file changes - [ ] Commit messages are descriptive - [ ] Feature flag needed? No — infrastructure config change, no user-visible workflow ## Related Notes - Closes #434 - `ldraney/pal-e-platform #434` — Configure Caddy reverse proxy for landscaping-assistant.app on edge-proxy
feat: add Caddy reverse proxy for landscaping-assistant.app (#434)
All checks were successful
ci/woodpecker/push/terraform Pipeline was successful
ci/woodpecker/pr/terraform Pipeline was successful
aabf464a67
Add site blocks for landscaping-assistant.app to the edge-proxy
Caddyfile template, mirroring the established palinks.app pattern:
reverse_proxy to the Tailscale hostname with TLS server name
validation, plus www-to-apex redirect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

PR #442 Review

DOMAIN REVIEW

Tech stack: Salt/Caddy (infrastructure configuration -- Jinja2 template for Caddy reverse proxy)

Architecture context: The Hetzner edge-proxy (178.156.129.142) runs Caddy as a TLS-terminating reverse proxy. Public domains hit this VPS, Caddy obtains ACME certificates automatically, and reverse-proxies upstream to Tailscale hostnames on port 443 with explicit tls_server_name for certificate validation. Salt manages the Caddyfile via a Jinja2 template rendered during highstate.

Pattern analysis: The diff adds two hardcoded site blocks for landscaping-assistant.app -- one reverse proxy block and one www-to-apex redirect. The pattern mirrors the original palinks.app blocks from PR #439. The Caddy configuration itself is correct:

  • HTTPS upstream on port 443 with tls_server_name matching the Tailscale FQDN -- good, prevents certificate mismatch
  • Permanent redirect for www subdomain preserves URI path -- correct
  • Comment header is clear and consistent with the palinks.app section

BLOCKERS

1. Stale base branch -- PR will conflict with or regress pillarized Caddyfile (BLOCKER)

PR #441 (f7dad45) was merged to main AFTER this branch was created. That PR converted the Caddyfile.j2 from hardcoded site blocks to a data-driven Jinja2 loop over pillar['caddy']['sites']. The current main-branch Caddyfile.j2 looks like this:

{%- set sites = salt['pillar.get']('caddy:sites', {}) %}
{%- for site_id, site in sites.items() %}
# --- {{ site.domain }} ---
{{ site.domain }} {
    reverse_proxy {{ site.proxy_target }}:443 {
        transport http {
            tls_server_name {{ site.proxy_target }}
        }
    }
}
{%- if site.get('www_redirect', false) %}
www.{{ site.domain }} {
    redir https://{{ site.domain }}{uri} permanent
}
{%- endif %}
{%- endfor %}

This PR adds hardcoded blocks below the {%- endfor %} tag (or worse, conflicts entirely). The correct approach post-#441 is to add a pillar entry for the landscaping-assistant site, not to edit the template. The pillar entry would be:

caddy:
  sites:
    landscaping:
      domain: landscaping-assistant.app
      proxy_target: landscaping-assistant.tail5b443a.ts.net
      www_redirect: true

The init.sls comment block already documents this exact pillar structure with landscaping-assistant as an example. This PR should be rebased onto current main and reworked to add pillar data instead of template hardcoding.

2. Upstream hostname discrepancy (potential BLOCKER -- needs verification)

The PR uses landscaping-assistant.tail5b443a.ts.net as the upstream target. However, the pillar example already documented in init.sls on main uses landscaping.tail5b443a.ts.net (without -assistant). One of these is wrong. The actual Tailscale machine name must be verified before merge to avoid a broken upstream.

NITS

  1. The PR body says "Follows the identical pattern established by palinks.app in PR #439" -- this is true of the original pattern, but that pattern was superseded by #441's pillarization. The PR body should reference the current approach.

  2. No test plan entry for validating the Jinja2 template renders correctly (e.g., salt-call state.show_sls caddy or caddy validate). Post-pillarization, the test plan should include verifying the rendered output includes both sites.

SOP COMPLIANCE

  • PR body has Summary, Changes, Test Plan, Related sections
  • No secrets committed (Tailscale hostname is not a secret -- it is only reachable within the tailnet)
  • No unnecessary file changes (single file, on-target for issue #434)
  • Commit message is descriptive and references issue number
  • Changes are incompatible with current main -- base branch is stale

PROCESS OBSERVATIONS

  • Change failure risk: HIGH. Merging this PR would either fail due to merge conflict (best case) or silently regress the Caddyfile from data-driven to a hybrid of loop-generated + hardcoded blocks (worst case). The pillarization in #441 was explicitly designed to make adding new domains a pillar-only change.
  • Correct remediation: Close this PR. Rebase the branch onto current main. Add pillar data for landscaping-assistant.app instead of editing the template. Verify the correct Tailscale hostname. Open a new PR.
  • Dependency chain awareness: This is part of the three-wave custom domain chain (Terraform DNS -> Caddy -> app config). The Caddy wave must land cleanly for the chain to complete.

VERDICT: NOT APPROVED

The PR is based on a stale branch and adds hardcoded site blocks to a template that has since been pillarized (PR #441). Merging would regress or conflict with the current data-driven architecture. The fix is straightforward: rebase onto main and add a pillar entry instead of editing the template. The upstream hostname (landscaping-assistant vs landscaping) must also be verified against the actual Tailscale machine name.

## PR #442 Review ### DOMAIN REVIEW **Tech stack:** Salt/Caddy (infrastructure configuration -- Jinja2 template for Caddy reverse proxy) **Architecture context:** The Hetzner edge-proxy (178.156.129.142) runs Caddy as a TLS-terminating reverse proxy. Public domains hit this VPS, Caddy obtains ACME certificates automatically, and reverse-proxies upstream to Tailscale hostnames on port 443 with explicit `tls_server_name` for certificate validation. Salt manages the Caddyfile via a Jinja2 template rendered during highstate. **Pattern analysis:** The diff adds two hardcoded site blocks for `landscaping-assistant.app` -- one reverse proxy block and one www-to-apex redirect. The pattern mirrors the original palinks.app blocks from PR #439. The Caddy configuration itself is correct: - HTTPS upstream on port 443 with `tls_server_name` matching the Tailscale FQDN -- good, prevents certificate mismatch - Permanent redirect for www subdomain preserves URI path -- correct - Comment header is clear and consistent with the palinks.app section ### BLOCKERS **1. Stale base branch -- PR will conflict with or regress pillarized Caddyfile (BLOCKER)** PR #441 (`f7dad45`) was merged to main AFTER this branch was created. That PR converted the Caddyfile.j2 from hardcoded site blocks to a **data-driven Jinja2 loop** over `pillar['caddy']['sites']`. The current main-branch Caddyfile.j2 looks like this: ```jinja2 {%- set sites = salt['pillar.get']('caddy:sites', {}) %} {%- for site_id, site in sites.items() %} # --- {{ site.domain }} --- {{ site.domain }} { reverse_proxy {{ site.proxy_target }}:443 { transport http { tls_server_name {{ site.proxy_target }} } } } {%- if site.get('www_redirect', false) %} www.{{ site.domain }} { redir https://{{ site.domain }}{uri} permanent } {%- endif %} {%- endfor %} ``` This PR adds hardcoded blocks below the `{%- endfor %}` tag (or worse, conflicts entirely). The correct approach post-#441 is to **add a pillar entry** for the landscaping-assistant site, not to edit the template. The pillar entry would be: ```yaml caddy: sites: landscaping: domain: landscaping-assistant.app proxy_target: landscaping-assistant.tail5b443a.ts.net www_redirect: true ``` The `init.sls` comment block already documents this exact pillar structure with landscaping-assistant as an example. This PR should be rebased onto current main and reworked to add pillar data instead of template hardcoding. **2. Upstream hostname discrepancy (potential BLOCKER -- needs verification)** The PR uses `landscaping-assistant.tail5b443a.ts.net` as the upstream target. However, the pillar example already documented in `init.sls` on main uses `landscaping.tail5b443a.ts.net` (without `-assistant`). One of these is wrong. The actual Tailscale machine name must be verified before merge to avoid a broken upstream. ### NITS 1. The PR body says "Follows the identical pattern established by palinks.app in PR #439" -- this is true of the *original* pattern, but that pattern was superseded by #441's pillarization. The PR body should reference the current approach. 2. No test plan entry for validating the Jinja2 template renders correctly (e.g., `salt-call state.show_sls caddy` or `caddy validate`). Post-pillarization, the test plan should include verifying the rendered output includes both sites. ### SOP COMPLIANCE - [x] PR body has Summary, Changes, Test Plan, Related sections - [x] No secrets committed (Tailscale hostname is not a secret -- it is only reachable within the tailnet) - [x] No unnecessary file changes (single file, on-target for issue #434) - [x] Commit message is descriptive and references issue number - [ ] **Changes are incompatible with current main** -- base branch is stale ### PROCESS OBSERVATIONS - **Change failure risk: HIGH.** Merging this PR would either fail due to merge conflict (best case) or silently regress the Caddyfile from data-driven to a hybrid of loop-generated + hardcoded blocks (worst case). The pillarization in #441 was explicitly designed to make adding new domains a pillar-only change. - **Correct remediation:** Close this PR. Rebase the branch onto current main. Add pillar data for `landscaping-assistant.app` instead of editing the template. Verify the correct Tailscale hostname. Open a new PR. - **Dependency chain awareness:** This is part of the three-wave custom domain chain (Terraform DNS -> Caddy -> app config). The Caddy wave must land cleanly for the chain to complete. ### VERDICT: NOT APPROVED The PR is based on a stale branch and adds hardcoded site blocks to a template that has since been pillarized (PR #441). Merging would regress or conflict with the current data-driven architecture. The fix is straightforward: rebase onto main and add a pillar entry instead of editing the template. The upstream hostname (`landscaping-assistant` vs `landscaping`) must also be verified against the actual Tailscale machine name.
ldraney force-pushed 434-caddy-landscaping-assistant-app from aabf464a67
All checks were successful
ci/woodpecker/push/terraform Pipeline was successful
ci/woodpecker/pr/terraform Pipeline was successful
to 26165bfe1f
All checks were successful
ci/woodpecker/push/terraform Pipeline was successful
ci/woodpecker/pr/terraform Pipeline was successful
ci/woodpecker/pull_request_closed/terraform Pipeline was successful
2026-06-16 00:50:23 +00:00
Compare
Author
Owner

Rebased and reworked per QA review. The original commit added static site blocks to Caddyfile.j2, but PR #441 has since merged and pillarized the template. The branch has been rebased onto current main and the approach changed to pillar-only:

Changes in updated commit:

  • salt/pillar/caddy.sls (new) -- pillar data with both palinks.app and landscaping-assistant.app site definitions
  • salt/pillar/top.sls -- assigns caddy pillar to edge-proxy minion
  • salt/states/top.sls -- assigns caddy state to edge-proxy minion
  • Caddyfile.j2 -- no longer touched (template loop from #441 handles it)

Tailscale hostname: Uses landscaping.tail5b443a.ts.net per the documented expected pillar structure in init.sls (line 22), not landscaping-assistant.tail5b443a.ts.net.

**Rebased and reworked** per QA review. The original commit added static site blocks to `Caddyfile.j2`, but PR #441 has since merged and pillarized the template. The branch has been rebased onto current main and the approach changed to pillar-only: **Changes in updated commit:** - `salt/pillar/caddy.sls` (new) -- pillar data with both `palinks.app` and `landscaping-assistant.app` site definitions - `salt/pillar/top.sls` -- assigns caddy pillar to `edge-proxy` minion - `salt/states/top.sls` -- assigns caddy state to `edge-proxy` minion - `Caddyfile.j2` -- no longer touched (template loop from #441 handles it) **Tailscale hostname:** Uses `landscaping.tail5b443a.ts.net` per the documented expected pillar structure in `init.sls` (line 22), not `landscaping-assistant.tail5b443a.ts.net`.
Author
Owner

PR #442 Review (Re-review after rebase onto pillarized template)

DOMAIN REVIEW

Tech stack: Salt (pillar YAML, state top.sls). Reviewed against Salt/IaC domain checklist.

Pillar structure alignment: The new salt/pillar/caddy.sls defines two sites under caddy.sites with keys domain, proxy_target, and www_redirect. This matches exactly what the Caddyfile.j2 template consumes:

{%- set sites = salt['pillar.get']('caddy:sites', {}) %}
{%- for site_id, site in sites.items() %}

Each expected key (site.domain, site.proxy_target, site.get('www_redirect', false)) is present in both pillar entries. No missing keys, no extra unused keys.

Proxy target verification: landscaping.tail5b443a.ts.net matches the hostname documented in salt/states/caddy/init.sls header comment. palinks.tail5b443a.ts.net matches the existing working configuration.

Top.sls wiring: Both salt/pillar/top.sls and salt/states/top.sls add the edge-proxy minion ID targeting the caddy pillar and state respectively. This is the correct two-file pattern -- the state needs pillar data to render, and the state must be assigned to run.

Graceful reload: The init.sls (from PR #441) uses caddy reload --config /etc/caddy/Caddyfile via cmd.run with onchanges, so adding the landscaping site will trigger a graceful reload, not a service restart. Existing palinks.app connections are preserved.

Pillar comments: The header block in caddy.sls clearly documents all keys and their purpose. Good operator UX.

Approach correctness (post-rebase): This is now purely a pillar-data change -- the template and state logic were established in PR #441. Adding a new domain is exactly the workflow the pillarization was designed to enable: add data, not logic. Clean separation.

BLOCKERS

None.

NITS

  1. Stale PR body: The "Changes" section references salt/states/caddy/Caddyfile.j2 edits ("Added two site blocks"), but the actual diff only touches salt/pillar/caddy.sls, salt/pillar/top.sls, and salt/states/top.sls. This is leftover from the pre-rebase approach. The summary should be updated to reflect the pillar-only change.

  2. Extra space in comment alignment: Line 9 of caddy.sls has www_redirect: whether (two spaces before "whether") while other key descriptions use single space. Cosmetic only.

SOP COMPLIANCE

  • PR body has Summary, Changes, Test Plan, Related -- all present
  • PR body Changes section matches actual diff -- stale (see nit #1)
  • No secrets committed -- proxy targets are hostnames, not credentials
  • No unnecessary file changes -- all 3 files are required for the feature
  • Commit messages are descriptive (branch name: 434-caddy-landscaping-assistant-app)
  • Closes parent issue #434

PROCESS OBSERVATIONS

  • Deployment frequency: This is the data-only half of a two-PR pattern (#441 pillarized the template, #442 adds data). Good decomposition -- the risky refactor shipped separately from the feature addition.
  • Change failure risk: Low. The pillar structure is validated by the existing palinks.app entry which is already serving traffic. The landscaping entry follows the identical pattern.
  • Prerequisite awareness: The edge-proxy is noted as not yet a Salt minion (installed via cloud-init). The top.sls entries will take effect once the minion is registered and a highstate is run.

VERDICT: APPROVED

## PR #442 Review (Re-review after rebase onto pillarized template) ### DOMAIN REVIEW **Tech stack:** Salt (pillar YAML, state top.sls). Reviewed against Salt/IaC domain checklist. **Pillar structure alignment:** The new `salt/pillar/caddy.sls` defines two sites under `caddy.sites` with keys `domain`, `proxy_target`, and `www_redirect`. This matches exactly what the Caddyfile.j2 template consumes: ```jinja2 {%- set sites = salt['pillar.get']('caddy:sites', {}) %} {%- for site_id, site in sites.items() %} ``` Each expected key (`site.domain`, `site.proxy_target`, `site.get('www_redirect', false)`) is present in both pillar entries. No missing keys, no extra unused keys. **Proxy target verification:** `landscaping.tail5b443a.ts.net` matches the hostname documented in `salt/states/caddy/init.sls` header comment. `palinks.tail5b443a.ts.net` matches the existing working configuration. **Top.sls wiring:** Both `salt/pillar/top.sls` and `salt/states/top.sls` add the `edge-proxy` minion ID targeting the `caddy` pillar and state respectively. This is the correct two-file pattern -- the state needs pillar data to render, and the state must be assigned to run. **Graceful reload:** The init.sls (from PR #441) uses `caddy reload --config /etc/caddy/Caddyfile` via `cmd.run` with `onchanges`, so adding the landscaping site will trigger a graceful reload, not a service restart. Existing palinks.app connections are preserved. **Pillar comments:** The header block in `caddy.sls` clearly documents all keys and their purpose. Good operator UX. **Approach correctness (post-rebase):** This is now purely a pillar-data change -- the template and state logic were established in PR #441. Adding a new domain is exactly the workflow the pillarization was designed to enable: add data, not logic. Clean separation. ### BLOCKERS None. ### NITS 1. **Stale PR body:** The "Changes" section references `salt/states/caddy/Caddyfile.j2` edits ("Added two site blocks"), but the actual diff only touches `salt/pillar/caddy.sls`, `salt/pillar/top.sls`, and `salt/states/top.sls`. This is leftover from the pre-rebase approach. The summary should be updated to reflect the pillar-only change. 2. **Extra space in comment alignment:** Line 9 of `caddy.sls` has `www_redirect: whether` (two spaces before "whether") while other key descriptions use single space. Cosmetic only. ### SOP COMPLIANCE - [x] PR body has Summary, Changes, Test Plan, Related -- all present - [ ] PR body Changes section matches actual diff -- **stale** (see nit #1) - [x] No secrets committed -- proxy targets are hostnames, not credentials - [x] No unnecessary file changes -- all 3 files are required for the feature - [x] Commit messages are descriptive (branch name: `434-caddy-landscaping-assistant-app`) - [x] Closes parent issue #434 ### PROCESS OBSERVATIONS - Deployment frequency: This is the data-only half of a two-PR pattern (#441 pillarized the template, #442 adds data). Good decomposition -- the risky refactor shipped separately from the feature addition. - Change failure risk: Low. The pillar structure is validated by the existing palinks.app entry which is already serving traffic. The landscaping entry follows the identical pattern. - Prerequisite awareness: The edge-proxy is noted as not yet a Salt minion (installed via cloud-init). The `top.sls` entries will take effect once the minion is registered and a highstate is run. ### VERDICT: APPROVED
Author
Owner

PR #442 Review

DOMAIN REVIEW

Stack: Salt (pillar/state management), Caddy (reverse proxy), Jinja2 templating

This PR completes the pillarization of Caddy site configuration by creating salt/pillar/caddy.sls and wiring it into both pillar/top.sls and states/top.sls for the edge-proxy minion. The change is data-only -- no template or state logic is modified.

Salt compliance:

  • Pillar structure matches what salt/states/caddy/init.sls documents and what Caddyfile.j2 consumes via salt['pillar.get']('caddy:sites', {}) -- keys domain, proxy_target, www_redirect are all present and correctly typed
  • Top file assignments target edge-proxy, which is the correct Hetzner VPS minion for Caddy
  • The pillar file includes both palinks and landscaping sites, so existing palinks.app routing is preserved (not a regression)
  • State ordering in init.sls is correct: file.managed -> service.running -> cmd.run with onchanges

Caddy/TLS verification:

  • proxy_target: landscaping.tail5b443a.ts.net uses the Tailscale MagicDNS hostname. The template appends :443 and sets tls_server_name for upstream certificate validation -- this prevents MITM on the Tailscale link
  • www_redirect: true generates a www.landscaping-assistant.app block with a permanent 301 redirect to the apex domain

Secrets handling:

  • No secrets in the diff. Proxy targets reference Tailscale hostnames (public-facing MagicDNS names), not credentials

BLOCKERS

None.

NITS

  1. PR body describes the wrong file. The ## Changes section says: "salt/states/caddy/Caddyfile.j2: Added two site blocks". The actual diff modifies salt/pillar/caddy.sls (new), salt/pillar/top.sls, and salt/states/top.sls. The Caddyfile.j2 template is untouched. The PR body should accurately describe what changed -- the pillar data and top file wiring, not the template.

  2. Pillar file comment says www_redirect but key is www_redirect. Minor: the comment block at the top of caddy.sls uses the label www_redirect: with a trailing colon which reads slightly like YAML rather than documentation prose. Not a functional issue.

  3. Review checklist item "Passed automated review-fix loop" is unchecked. This is expected if this is the first review pass.

SOP COMPLIANCE

  • PR body has: Summary, Changes, Test Plan, Related -- all present
  • No secrets committed -- proxy targets are Tailscale hostnames, not credentials
  • No unnecessary file changes -- 3 files, all directly related to the task
  • Commit messages are descriptive (branch name 434-caddy-landscaping-assistant-app is clear)
  • PR body ## Changes section is inaccurate -- describes Caddyfile.j2 modification but the actual diff is pillar/top file changes only (nit, not blocking)

PROCESS OBSERVATIONS

  • Change failure risk: Low. This is a data-only change feeding an already-proven template. The palinks.app pattern is identical and was validated in PR #439. The pillarization refactor (PR #441) already converted the template to be data-driven, so this PR just provides the data.
  • Deployment frequency: This completes the Caddy leg of the three-wave custom domain chain (DNS -> Caddy -> app config). Once merged and highstate is run, the edge-proxy will serve landscaping-assistant.app.
  • Validation dependency: The test plan correctly notes that curl validation depends on DNS being pointed first. Post-merge validation should confirm Caddy reload succeeds even before DNS cutover.

VERDICT: APPROVED

## PR #442 Review ### DOMAIN REVIEW **Stack**: Salt (pillar/state management), Caddy (reverse proxy), Jinja2 templating This PR completes the pillarization of Caddy site configuration by creating `salt/pillar/caddy.sls` and wiring it into both `pillar/top.sls` and `states/top.sls` for the `edge-proxy` minion. The change is data-only -- no template or state logic is modified. **Salt compliance**: - Pillar structure matches what `salt/states/caddy/init.sls` documents and what `Caddyfile.j2` consumes via `salt['pillar.get']('caddy:sites', {})` -- keys `domain`, `proxy_target`, `www_redirect` are all present and correctly typed - Top file assignments target `edge-proxy`, which is the correct Hetzner VPS minion for Caddy - The pillar file includes both `palinks` and `landscaping` sites, so existing palinks.app routing is preserved (not a regression) - State ordering in `init.sls` is correct: file.managed -> service.running -> cmd.run with onchanges **Caddy/TLS verification**: - `proxy_target: landscaping.tail5b443a.ts.net` uses the Tailscale MagicDNS hostname. The template appends `:443` and sets `tls_server_name` for upstream certificate validation -- this prevents MITM on the Tailscale link - `www_redirect: true` generates a `www.landscaping-assistant.app` block with a permanent 301 redirect to the apex domain **Secrets handling**: - No secrets in the diff. Proxy targets reference Tailscale hostnames (public-facing MagicDNS names), not credentials ### BLOCKERS None. ### NITS 1. **PR body describes the wrong file**. The `## Changes` section says: "salt/states/caddy/Caddyfile.j2: Added two site blocks". The actual diff modifies `salt/pillar/caddy.sls` (new), `salt/pillar/top.sls`, and `salt/states/top.sls`. The Caddyfile.j2 template is untouched. The PR body should accurately describe what changed -- the pillar data and top file wiring, not the template. 2. **Pillar file comment says `www_redirect` but key is `www_redirect`**. Minor: the comment block at the top of `caddy.sls` uses the label `www_redirect:` with a trailing colon which reads slightly like YAML rather than documentation prose. Not a functional issue. 3. **Review checklist item "Passed automated review-fix loop" is unchecked**. This is expected if this is the first review pass. ### SOP COMPLIANCE - [x] PR body has: Summary, Changes, Test Plan, Related -- all present - [x] No secrets committed -- proxy targets are Tailscale hostnames, not credentials - [x] No unnecessary file changes -- 3 files, all directly related to the task - [x] Commit messages are descriptive (branch name `434-caddy-landscaping-assistant-app` is clear) - [ ] PR body `## Changes` section is inaccurate -- describes Caddyfile.j2 modification but the actual diff is pillar/top file changes only (nit, not blocking) ### PROCESS OBSERVATIONS - **Change failure risk**: Low. This is a data-only change feeding an already-proven template. The palinks.app pattern is identical and was validated in PR #439. The pillarization refactor (PR #441) already converted the template to be data-driven, so this PR just provides the data. - **Deployment frequency**: This completes the Caddy leg of the three-wave custom domain chain (DNS -> Caddy -> app config). Once merged and highstate is run, the edge-proxy will serve landscaping-assistant.app. - **Validation dependency**: The test plan correctly notes that `curl` validation depends on DNS being pointed first. Post-merge validation should confirm Caddy reload succeeds even before DNS cutover. ### VERDICT: APPROVED
ldraney deleted branch 434-caddy-landscaping-assistant-app 2026-06-16 01:05:45 +00:00
Sign in to join this conversation.
No description provided.