Skip to content

Add MIT license and enable Let's Encrypt certificate services#5

Merged
CodeLifterIO merged 1 commit into
mainfrom
add-license-and-enable-letsencrypt
Jun 14, 2026
Merged

Add MIT license and enable Let's Encrypt certificate services#5
CodeLifterIO merged 1 commit into
mainfrom
add-license-and-enable-letsencrypt

Conversation

@CodeLifterIO

Copy link
Copy Markdown
Contributor

Summary

Two product-repo cleanup items, plus a follow-up requested in the same session.

1. MIT LICENSE

  • Add LICENSE (MIT, © 2026 CodeLifter LLC) so the open-source / MIT claim is true.
  • Update the README license section (was "Private - All rights reserved").

2. Enable Let's Encrypt certificate services

The cert services existed only as .disabled files and were incomplete — they never served the ACME challenge, so validation would always have failed. This makes them actually work:

  • Rename CertificateService and CertificateRenewalBackgroundService from .disabled; register in DI (Program.cs).
  • Add IAcmeChallengeStore (singleton) and map GET /.well-known/acme-challenge/{token} so HTTP-01 validation can succeed.
  • Poll the authorization (not the order) for validation, and clean up the published challenge in a finally.
  • Trigger issuance on save (immediate feedback) and broaden the background service to cover initial issuance, not just renewal (new hosts have a null expiry and were previously skipped).
  • Default to the Let's Encrypt staging directory for safe testing; set LetsEncrypt__UseProduction=true to go live. Documented in .env.example.

3. Remove Cloudflare Tunnel from the home-hosting guide

Per request to drop Cloudflare Tunnels project-wide. The code was already Tunnel-free; the only reference was a CGNAT workaround sentence in StageZero-Home-Hosting-Guide.docx, now reworded to a non-CGNAT IP / VPS alternative. (The Cloudflare DNS provider — the app's core feature — is unrelated and untouched.)

Testing

  • StageZero and StageZero.ReverseProxy build clean (the pre-existing solution-wide build break from the missing Lifted.BlazorAuth.AspNetIdentity project is unrelated).
  • App boots; the renewal background service runs its first pass without error and the ACME endpoint responds over HTTP (404 for an unknown token).

Notes for reviewers

  • For real issuance in production, the proxied domain must reach this app over HTTP on /.well-known/acme-challenge/ — verify the ingress path passes it through.
  • DatabaseProxyConfigProvider.cs.disabled (the third disabled file) is intentionally left disabled — it's the YARP routing provider, a separate concern that needs full YARP integration.

🤖 Generated with Claude Code

- Add MIT LICENSE (CodeLifter LLC) and update README license section,
  replacing "Private - All rights reserved".

- Enable the previously-disabled Let's Encrypt certificate services:
  - Rename CertificateService and CertificateRenewalBackgroundService
    from .disabled and register them in DI.
  - Add IAcmeChallengeStore + map GET /.well-known/acme-challenge/{token}
    so HTTP-01 validation can actually succeed (the original code never
    served the challenge response).
  - Poll the authorization (not the order) for validation success, and
    clean up the published challenge afterward.
  - Trigger issuance on save and broaden the background service to cover
    initial issuance, not just renewal.
  - Default to the Let's Encrypt staging directory; LetsEncrypt__UseProduction
    opts into production. Documented in .env.example.

- Remove the Cloudflare Tunnel recommendation from the home-hosting guide
  (CGNAT workaround now points to a non-CGNAT IP or VPS instead).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@augmentcode

augmentcode Bot commented Jun 14, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: This PR makes the repository license explicit and enables functional Let's Encrypt/ACME certificate issuance for reverse-proxy hosts.

Changes:

  • Added an MIT LICENSE file and updated the README to reference it
  • Documented a LetsEncrypt__UseProduction setting in .env.example and defaulted issuance to the staging directory for safer testing
  • Enabled certificate issuance/renewal services by re-enabling CertificateService and CertificateRenewalBackgroundService
  • Added an in-memory IAcmeChallengeStore and mapped GET /.well-known/acme-challenge/{token} for HTTP-01 validation
  • Updated issuance flow to poll challenge status, clean up the published challenge in a finally, and trigger issuance immediately after saving a proxy host

Technical Notes: Issuance requires the public domain to reach the app over HTTP at /.well-known/acme-challenge/; the background service handles periodic retries/renewals.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. No suggestions at this time.

Comment augment review to trigger a new review at any time.

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread .env.example
LetsEncrypt__UseProduction=false

# Example project with real SMTP data
# StageZero No newline at end of file

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.env.example:57: The diff indicates this file may be missing a trailing newline ("\ No newline at end of file"), which can cause noisy diffs in future edits. Consider ensuring the file ends with a newline.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread StageZero/Program.cs
// during certificate issuance; we serve the key authorization published by
// CertificateService. Must remain reachable over plain HTTP (Let's Encrypt
// follows the 301 from UseHttpsRedirection, but the route itself is anonymous).
app.MapGet("/.well-known/acme-challenge/{token}", (string token, IAcmeChallengeStore store) =>

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StageZero/Program.cs:380: Since HTTP-01 validation can hit this endpoint multiple times from different vantage points, consider explicitly preventing caching of challenge responses (e.g., via response headers) to avoid any intermediary serving stale content. This is especially relevant if the app is deployed behind a CDN/reverse-proxy that might cache 200 responses by default.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

// Publish the challenge response so /.well-known/acme-challenge/{token}
// can serve it when Let's Encrypt validates the domain.
challengeToken = httpChallenge.Token;
_challengeStore.AddChallenge(challengeToken, keyAuthz);

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StageZero.ReverseProxy/Services/CertificateService.cs:84: proxyHost.DomainName is later used to construct cert/key file paths, so any unexpected characters (path separators, .., etc.) could allow writing outside the intended certificates directory. Consider validating/sanitizing DomainName before using it in any filesystem path now that this service is enabled.

Severity: high

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

// Publish the challenge response so /.well-known/acme-challenge/{token}
// can serve it when Let's Encrypt validates the domain.
challengeToken = httpChallenge.Token;
_challengeStore.AddChallenge(challengeToken, keyAuthz);

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StageZero.ReverseProxy/Services/CertificateService.cs:84: This issuance flow writes a private key to disk; relying on default file permissions can be risky if the host/umask is permissive. Consider ensuring the .key file is created with restrictive permissions since it contains TLS private key material.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

// within the 30-day renewal window.
var pendingHosts = await _dbContext.Set<ProxyHost>()
.Where(p => p.UseLetsEncrypt
&& (p.SslCertificateExpiry == null || p.SslCertificateExpiry < expiringDate))

@augmentcode augmentcode Bot Jun 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StageZero.ReverseProxy/Services/CertificateService.cs:188: RenewExpiringCertificatesAsync() will select hosts with UseLetsEncrypt even if LetsEncryptEmail is missing, which will cause repeated failed attempts and misleading "not enabled" logs. Consider filtering out incomplete Let's Encrypt configurations (or logging a more specific message) to avoid noisy retries.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@CodeLifterIO CodeLifterIO merged commit 4480cc3 into main Jun 14, 2026
3 checks passed
@CodeLifterIO CodeLifterIO deleted the add-license-and-enable-letsencrypt branch June 14, 2026 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant