Skip to content

Custom Domains for Territories #1958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 79 commits into
base: master
Choose a base branch
from

Conversation

Soxasora
Copy link
Member

@Soxasora Soxasora commented Mar 9, 2025

Description

Closes #1942
Introduces custom domains for territories, featuring one-click sign-in and customizable branding

Additional Context

Several parts are at the core of custom domains functionality.

Middleware

We use the main middleware to handle redirects and rewrites for custom domains.
As usual we run referrerMiddleware to get referral cookies but we pass it on to custom domains

To recognize an allowed custom domain we check req.headers.host and verify it against a cached /api/domains endpoint, if there's a match we'll proceed to the next step: customDomainMiddleware with the referral cookies

This middleware handles various paths differently

/login /signup

The custom domain, callbackUrl, multiAuth flag, gets applied to the path to be later used.

/ or TERRITORY_PATHS

As we got redirected to a path without /~subName we still need to know what territory are we on for paths that requires it, so this step applies a hidden rewrite to /~subName

/~subName

To minimize changes to the codebase, every path that makes us of /~subName gets redirected to a path without it, applying searchParams and running then the / rewrite we just talked about.

Remember the referral cookies we passed at the start? For every redirect or rewrite, we apply those referral cookies, maintaining the usual behavior.
And we apply security headers, too.

Auth Sync

To provide a seamless experience between custom domains and SN, all auth actions gets handled by stacker.news.
During the middleware stage we recognize if we're going to a login or signup page and pass our custom domain.
We can then build a callbackUrl to /api/auth/sync containing the custom domain as final callback.

/api/auth/sync

If the login is successful or we're already logged in, we create a verification token that lasts a minute for the user they want to login with.
We then redirect back to the custom domain we passed via /login /signup, with the token and the callback using the ?type=sync parameter.

a TEST DomainProvider will catch this parameter and will start a next auth signIn
A CredentialsProvider called Sync will verify this token and provide the user object if everything goes smoothly.
We're in!

Setup and Verification UI/UX

On edits, a new collapsed section called advanced pops-up
Here we can submit our custom domain
image

Upon submitting, DNS verification starts automatically and informs the user of the steps they need to follow
image

Entering this part of the page or submitting a domain starts a poll that stops whenever the domain is fully VERIFIED (dnsState and sslState).

And on verified DNS we trigger SSL verification
image

We're all set!
image

DNS and SSL verification

We saw how it appears on the user side, let's dive in the worker that's behind these verifications

NOTE: The verification process has changed from routine worker to a boss.send based approach

verifyDomainDNS

We check both TXT and CNAME records that we asked the user to set, specifically if the domain they provided has a CNAME that points at stacker.news and a TXT with our randomly generated string

Adding to this verification, we use a DNS Resolver set from the ENV or we fallback to CloudFlare's 1.1.1.1, for consistency.

If both records are set correctly, assuming everything goes smoothly, we set dnsState to VERIFIED and go onto the next step.

Issue and verify SSL certificates

If dnsState is VERIFIED, we can start our SSL issuance and verification process.
We contact ACM to issue a domain certificate for the domain the user has provided, eg. forum.pizza.com

If we got a certificateArn from ACM then we can already check its status to see if we got the validation values with it. If so, let's put them in our database so the user can set point a CNAME record to ACM's validation values.

Since we need to wait for the user to complete this step, we continue to check the sslState by contacting ACM.

If ACM declares the domain as valid we can then set sslState to VERIFIED and the user will be notified.
We are all set!

Custom Branding

On full positive domain verification a new section pops up: Custom Branding
This sub-feature gives the possibility to choose colors, logo, text and description of the community, further distinguishing a community powered by SN from SN itself.

TODO: better styling
image

It works by saving these settings to the CustomBranding model which is connected to the Sub model instead of CustomDomain to make it independent from any domain change.

TODO: better way

At the moment, colors are applied via a BrandingProvider that fetches them during SSR.

Navigation and UI

Custom domains won't have the territory picker or informations about the territory they're in, leaving these to SN.
Subject to change

Default branding:
image

This is handled by the DomainProvider, a context that recognizes a custom domain and applies the related subName via SSR and client-side, also gets the changed styles via an SSR fetch to the customBranding model, using the subName that we obtained before.

image

SEO and colors are applied dynamically, overwriting SN's style with the territory owner's choices.

This is a title bars comparison, the difference here is that we don't show the territory name and stacker news, instead we just show the title chosen by the territory owner.
image

TBD

Checklist

Are your changes backwards compatible? Please answer below:
Custom Domains are bolted on top of SN codebase, it shouldn't interfere, at all, with stacker.news usual behavior

On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:
5, iterative testing

For frontend changes: Tested on mobile, light and dark mode? Please answer below:
Yes, remains the SCSS style application that has a slight delay

Did you introduce any new environment variables? If so, call them out explicitly here:
DNS_RESOLVER -> with a fallback to 1.1.1.1 in worker/domainVerification.js
LOCALSTACK_ENDPOINT -> for test atm
DOMAIN_DEBUG -> for custom domain logger, for test atm

MVP Progress

APIs

  • LocalStack ACM (issue certificates for custom domains)

SSL

  • Show validation CNAME to the user
  • Issue SSL certificates via ACM API

Custom branding

  • Color picker
  • Logo upload
  • Form
  • Dynamic branding, custom colors
  • Branding context
  • Branding db model

Territory Edit

  • Poll every 30 seconds for validation status
  • Info with SSL validation CNAME to be set // depends on ACM
  • Info with TXT records to be set
  • every 5 minutes DNS/SSL verification and validation via node:dns and worker
  • Popover respectively for DNS and SSL lastVerified
  • WIP save custom domain in DB via Territory Edit // wip UI
  • show values from customDomain

Domains

  • delete domain after X failed verifications
  • dnsState and sslState to track domain's functionality
  • cached API endpoint for custom domains map
  • custom domain table

Navigation and UI

  • fix layout shifts
  • better isCustomDomain conditional UI
  • fix sorts not being highlighted due to non-expected url // not clean

Middleware

  • consider Referral Cookies, do we want them? // not clean
  • better management of territory paths
  • WIP redirect and rewrite of territories

Auth Sync

  • MultiAuth handling
  • WIP one click login if visiting a custom domain // todo: give an appropriate location for verification
  • switch to verification request
  • redirect to custom domain with main domain's cookies and save them
  • sync auth only if coming from main domain

Take care of

  • check cookies validity across domains
  • check security risks in auth sync
  • custom domains SEO
  • Site title
  • Favicon
  • hard coded 'stacker.news'
  • use boss.send on domain submission to instant verify
  • going back causes isCustomDomain to be lost

After MVP Progress

Wallet Sync

  • Autosync?
  • Device Sync as a placeholder

APIs

  • LocalStack ELBv2 (Load Balancer)
  • LocalStack CloudFront CDN) 

More

  • Consider push notifications being possibly duplicated
  • Consider hiding Footer for custom domains or redirect them to main domain
  • use constants
  • Total cleanup

Take care of

  • don't redirect to SN if not strictly necessary // WIP, searching for paths to be redirected
  • CORS for a.stacker.news and m.stacker.news
  • check for expired or transferred domains
  • test unusual DNS propagation times
  • check payments
  • prevent abuse on setCustomDomain
  • Webmanifest

{sub.customDomain?.status === 'ACTIVE' && (
<div className='text-muted'>
<span>website </span>
<Link className='fw-bold' href={`https://${sub.customDomain.domain}`}>{sub.customDomain.domain}</Link>
Copy link
Member Author

@Soxasora Soxasora Apr 9, 2025

Choose a reason for hiding this comment

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

As discussed, now middleware won't trigger auth sync if coming from stacker.news, but this might be a good place to adopt another strategy: we can redirect to auth sync with redirectUrl to the custom domain.
Might be a lot cleaner than the middleware refer(r)er strategy, if they're already logged in the custom domain it just fails silently

@Soxasora Soxasora marked this pull request as ready for review April 9, 2025 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature new product features that weren't there before territories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow territories to be hosted at custom domains
1 participant