Skip to content

Cloud and externally operated services

Lifecycle: Current dependency reference. Last verified where stated: 2026-07-17.

Service Purpose Local dependency Owner/status
Cloudflare DNS Public DNS and DNS-01 certificate challenges Caddy on CT 103 and ovps-me Account/billing owner unverified; operational use verified
Cloudflare Tunnel Selected public ingress Host cloudflared and remote tunnel config Active configuration is remotely managed; origin cleanup remains open
Let's Encrypt Public TLS certificates Caddy DNS-01 Active
Google Workspace OIDC Administrative/application sign-in Caddy security, Forgejo, Headplane as configured Client ownership and recovery contacts unverified
Google Sheets/Gmail mail merge Spreadsheet-driven personalized Gmail sending Bound Google Apps Script and Gmail draft templates Current; implementation owner unverified
Starlink WAN connectivity OPNsense WAN Active; billing/support owner unverified
Forgejo Git and Actions control plane CT 101 Current
Headscale VPS Tailnet control plane ovps-me Current; version v0.29.1

Operational rules

  • Keep billing, recovery contacts, API tokens, OAuth secrets, and recovery codes in the approved password manager.
  • Use scoped Cloudflare API tokens.
  • Do not infer remotely managed tunnel ingress from local files; validate selected non-secret origin metadata through the service/logs.
  • Record domain renewal, certificate failure, and account recovery owners.
  • Test one certificate issuance and one OIDC flow after relevant changes.

Google Sheets/Gmail mail merge

As of 2026-08-26, the Google Sheets/Gmail mail-merge workflow is a spreadsheet-bound Google Apps Script contained entirely in Code.gs. No additional HTML file or custom HTML interface is required.

The script sends personalized messages from a Gmail draft. The existing spreadsheet-to-template variable mapping is unchanged: placeholders such as {{Column Name}} continue to map exactly to matching spreadsheet column headers. Existing Gmail draft lookup, personalization, attachments, inline images, recipient processing, and Email Sent status behavior remain in place.

Before sending, the script retrieves the verified Gmail aliases configured for the currently authenticated sender by calling GmailApp.getAliases(). The sender sees a numbered list of sender identities:

  • Option 0 uses the sender's default Gmail address.
  • Options 1, 2, and so on correspond to the aliases returned for that Gmail account.
  • The sender selects an identity by entering its associated number.

The script validates that the submitted value is a whole number within the displayed range. Cancelling the alias prompt cancels the mail merge before any messages are sent. If the account has no configured aliases, the script informs the user and uses the default Gmail address.

When an alias is selected, it is passed through the from property of the GmailApp.sendEmail() options object. When the default address is selected, the from property is omitted and Gmail uses the account's normal sender identity. Alias addresses are not hardcoded in the script, and users do not type email addresses manually. Only aliases already configured and verified in Gmail under Settings > Accounts and Import > Send mail as can be used.

CC and BCC functionality was considered but is not part of this change. Standard CC/BCC would deliver a copy of every personalized message to those addresses, so that requirement was intentionally excluded from the current implementation.

Operational use:

  1. Configure and verify any required aliases in Gmail.
  2. Open the spreadsheet and select Mail Merge > Send Emails.
  3. Enter the exact Gmail draft subject.
  4. Enter the number associated with the required sender identity.
  5. Confirm that the spreadsheet contains the expected Recipient and Email Sent columns.
  6. Ensure template placeholders exactly match spreadsheet header names.

Limitations:

  • Available aliases depend on the Gmail account executing the script.
  • Google Workspace administrator policies may restrict aliases or script authorization.
  • Sending remains subject to Gmail and Apps Script quotas.
  • Selecting an alias changes the envelope/display sender but does not alter mail-merge variable mapping.
  • The script must be run from an editable copy of the spreadsheet with permission to edit its bound Apps Script project.

Current gaps

  • Named owner and recovery path for Cloudflare, domain registration, Google OAuth clients, Starlink, and the VPS provider.
  • Canonical list of Cloudflare Tunnel hostnames and current origins.
  • Removal date for legacy proxy.kh3group.com compatibility.

Troubleshooting

Symptom Diagnosis Remedy
Public DNS wrong Query authoritative DNS Correct provider record in approved change
DNS-01 fails Token scope, zone lookup, resolver policy Restore scoped token/working resolver configuration
Tunnel 502/TLS error Check remote origin metadata and ingress Caddy Point origin to current Caddy/service target
OIDC callback error Compare exact route/callback/claims Correct provider and application together

Official references