Skip to content
View lyrcloud's full-sized avatar

Block or report lyrcloud

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
Lyrcloud/README.md

Lyrcloud

The Lyrcloud website (www.lyrcloud.com): a Cloudflare-style multi-page marketing site plus a preview dashboard at /dash/. No dependencies — just Node.js.

Commands

npm run dev
npm run check
npm run build
npm run create:s3
npm run deploy:aws
  • npm run dev starts a local server on port 5173 that rebuilds on every page load.
  • npm run check builds the site, then fails on missing titles or broken internal links.
  • npm run build renders every page into dist/.
  • npm run create:s3 creates the private S3 bucket stack for static site assets.
  • npm run deploy:aws builds the site, creates/updates the AWS stack, syncs dist/ to S3, and invalidates CloudFront.

Project layout

Path What it is
site/layout.mjs Shared header (with the Products mega-menu), footer, and HTML shell
site/products.mjs Product catalog — each entry becomes /products/<slug>/ and a nav item
site/pages.mjs Every page and its route (/pricing/ → dist/pricing/index.html)
src/styles.css Site styles
src/dash.js, src/dash.css Dashboard single-page app (hash routes such as /dash/#/zones/example.com/dns)
src/auth.js Cognito Hosted UI sign-in (Google, GitHub) with PKCE; /callback.html completes it

To add a page, add an entry to the pages array in site/pages.mjs. To add a product, add it to site/products.mjs.

Sign-in and dashboard

Sign-in is real: /login/ and /sign-up/ send visitors to the Cognito Hosted UI (lyrcloud-users pool), which offers Google and GitHub. Cognito only accepts /callback.html as the redirect and /index.html as the logout page (on https://www.lyrcloud.com and http://localhost:5173), so keep those paths. Profile data in Settings comes from the account API (GET /me).

  • Email and password: /sign-up/ and /login/ also have their own forms (src/login.js, src/cognito.js) that call the Cognito API directly: sign up → 6-digit email code (sent by Cognito) → optional mobile number → texted code. Forgot-password works the same way. Run python3 scripts/configure-auth.py (report) then --apply to turn self sign-up and the code emails on in the pool.
  • Mobile numbers: the account API texts the code through Amazon SNS (POST /me/phone, POST /me/phone/verify) and stores only a hash of it. New SNS accounts are in the SMS sandbox with a $1/month spend limit.
  • Emails: the account API sends a welcome email to each new account and lets the super admin email product updates from the admin console (Settings tab), through Amazon SES from no-reply@lyrcloud.com. Each update has a signed unsubscribe link, and people can switch updates off in Account settings. SES needs the lyrcloud.com DKIM records in Cloudflare and production access before it can mail everyone.
  • GitHub: GitHub isn't an OpenID provider, so api/github-bridge/ makes it look like one for Cognito. It runs in the lyrcloud-github-bridge stack, whose secret lyrcloud/github-bridge holds the GitHub OAuth app credentials and signing key. Update it with bash scripts/deploy-github-bridge.sh, and point Cognito at it with configure-auth.py --apply --github-bridge https://3ahe2e3r86.execute-api.us-east-1.amazonaws.com. GITHUB_SIGN_IN_ENABLED in site/pages.mjs shows or hides the button.

The dashboard itself is not backed by a server yet:

  • Real: adding a site scans its existing DNS records over public DNS-over-HTTPS (dns.google), and “Check nameservers” looks up the domain’s live NS records. The Edge Functions preview runs code in an isolated Web Worker in the browser.
  • Preview only: websites, DNS records, functions, and settings are stored in the visitor’s browser (localStorage). Analytics and security events are generated sample data and labeled as such.

Cloud

Customers run container clusters in their own cloud accounts; Lyrcloud builds and manages them, and the provider bills the customer. Dashboard → Cloud; Network page → "Every major cloud, on one map".

  • Regions: src/clouds.js lists the data center regions of AWS, Azure, Google Cloud, Oracle, Alibaba, IBM and DigitalOcean with coordinates (AWS from describe-regions), plus a land mask for the dotted world map (src/cloud-map.js, Natural Earth 1:110m, public domain). Update the lists and CATALOG_DATE together. Only providers with provisioning: true (AWS) can get clusters so far.
  • Connecting AWS: the customer launches the lyrcloud-access stack from a one-click link (template in the public lyrcloud-public-<account> bucket). It creates the LyrcloudAccess role, trusting Lyrcloud's account only with that customer's ExternalId, allowed to manage EKS/ECS/VPC/ELB/logs and IAM roles named lyrcloud-*. Lyrcloud stores no keys; it assumes the role per request.
  • Clusters: Kubernetes (EKS with a managed node group and an access entry for the customer's admin ARN) or serverless (ECS on Fargate). Each is a CloudFormation stack in the customer's chosen region, with a VPC of public subnets and no NAT gateway. Lyrcloud first creates any missing service-linked roles (a brand-new account has none).
  • Services: on serverless clusters, a container image becomes an ECS service behind a public load balancer (its own stack); changing image, size, copies or environment redeploys it with a circuit breaker. On Kubernetes, customers use kubectl.
  • Costs: src/cloud-pricing.js holds sizes and us-east-1 prices, shared by the API and the dashboard's estimates.
  • Backend: api/cloud/ in the lyrcloud-cloud stack (infra/aws/cloud.yml, table lyrcloud-cloud); deploy with bash scripts/deploy-cloud.sh, which also uploads the access-role template. CLOUD_API_BASE in src/auth.js points at it. Verified end to end on 2026-11-05 (serverless cluster + nginx service in us-east-2, then torn down); EKS templates are validated by CloudFormation but weren't run live.

Domains

Lyrcloud resells domains through Route 53 Domains, with its own commission on top, paid with Stripe. The public search and price list are at /domains/ (src/domains.js); buying, transfers, renewals and DNS records are in the dashboard (/dash/#/domains), and prices, payments and sales are in the admin console's Domains tab.

  • Backend: api/domains/ in the lyrcloud-domains stack (infra/aws/domains.yml, table lyrcloud-domains). Deploy with bash scripts/deploy-domains.sh; DOMAINS_API_BASE in src/auth.js points at its API.
  • Money first: checkout holds the name for 35 minutes and opens Stripe Checkout. Only when Stripe's webhook confirms the payment does the API call RegisterDomain/TransferDomain; if the registrar refuses (straight away or later), the payment is refunded automatically. In Stripe test mode paid orders are always refunded and never reach the registrar, so the flow can be tried without buying real domains.
  • Renewals: Route 53 auto-renew is off. A scheduled run every 15 minutes follows registrar operations and, 30 days before expiry, charges the saved card off-session for auto-renewing domains, then calls RenewDomain. Failed charges are retried daily and shown on the domain.
  • Prices: customer price = (Route 53 price + DNS hosting) × (1 + commission %) + flat fee, optionally rounded up to .99, never below cost. DNS hosting (default $6/yr, a Route 53 hosted zone) applies to registrations and their renewals; transfers keep their own DNS. The super admin sets the commission, TLD list and per-TLD overrides in the admin console.
  • Stripe: the super admin pastes a secret key in the admin console; the API checks it, registers its own webhook (/public/stripe/webhook) and keeps both in the lyrcloud/stripe secret.
  • DNS: registered domains get a Route 53 hosted zone; owners edit A, AAAA, CNAME, MX and TXT records in the dashboard, and the domain shows up as an active website.

name.lyr.cloud (built, off until lyr.cloud is registered)

Customers claim name.lyr.cloud in Dashboard → Domains and edit its records (a CNAME at the name itself is allowed). It's free on the plans in subdomainFreePlans (Scale and Enterprise) and subdomainCents a year otherwise (default $4.99), paid through Stripe Checkout and renewed on the saved card like domains; unpaid names are released 7 days after they lapse. It switches on once lyr.cloud has a Route 53 hosted zone: register it (Route 53 makes the zone), then run bash scripts/deploy-domains.sh, which finds the zone and passes SubdomainZone/SubdomainZoneId.

.lyr (preview)

.lyr is Lyrcloud's own extension. It is not an ICANN TLD, so it isn't in the public DNS: .lyr names only resolve on devices whose browser or OS uses Lyrcloud's DNS-over-HTTPS resolver, and public CAs won't issue TLS certificates for them. It isn't for sale; the super admin creates names in Admin console → Domains → .lyr names. /lyr/ explains it and has a lookup tool and setup steps.

  • Resolver: GET|POST /dns-query on the domains API (RFC 8484, api/domains/lyrdns.mjs). It answers .lyr questions from the lyrcloud-domains table (lyr#<name> items), follows CNAMEs, and forwards every other query unchanged to Cloudflare's resolver. Queries aren't logged.
  • Setup for users: a custom secure-DNS address in Chrome/Edge/Brave/Firefox, or public/lyr.mobileconfig on Apple devices. The resolver URL is in three places that must agree: DOMAINS_API_BASE in src/auth.js, LYR_RESOLVER in site/pages.mjs, and public/lyr.mobileconfig.
  • Waitlist: signed-in customers reserve up to three .lyr names for free (POST /domains/lyr-waitlist), first come first served; /lyr/ checks availability. The admin console lists reservations. Nothing is sold.
  • Before selling: a real .lyr needs an ICANN application in a new-gTLD round; until then, sold names would only work for people using Lyrcloud DNS.

Theme

Light by default; dark when the visitor’s OS prefers dark. Colors are tokens on :root in src/styles.css.

AWS hosting

The AWS deployment is defined in infra/aws/static-site.yml. It creates:

  • a bucket policy for the private S3 bucket created by infra/aws/s3-bucket.yml
  • a Lambda@Edge viewer-request function for clean URL rewrites
  • an ACM certificate for lyrcloud.com and www.lyrcloud.com
  • a CloudFront distribution with the S3 bucket as a private origin
  • A/AAAA Route53 alias records for the apex and www

Run it from a machine or CI runner with AWS CLI credentials:

AWS_REGION=us-east-1 npm run create:s3
AWS_REGION=us-east-1 npm run deploy:aws

The first run creates a Route53 public hosted zone from infra/aws/route53-zone.yml, prints the name servers, and stops. Add those name servers at the registrar for lyrcloud.com, then run:

CONFIRM_DELEGATED=1 AWS_REGION=us-east-1 npm run deploy:aws

Optional overrides:

STACK_NAME=lyrcloud-static-site \
DOMAIN_NAME=lyrcloud.com \
SITE_BUCKET_NAME=lyrcloud.com \
HOSTED_ZONE_ID=Z1234567890 \
AWS_REGION=us-east-1 \
npm run deploy:aws

CloudFront requires the ACM certificate and Lambda@Edge function to live in us-east-1, so keep AWS_REGION=us-east-1 unless you also change the architecture.

Popular repositories Loading

  1. Lyrtrip Lyrtrip Public

    TypeScript

  2. Lyrcloud Lyrcloud Public

    JavaScript

  3. Lyrpay Lyrpay Public

    TypeScript

  4. MR-SHIHAB MR-SHIHAB Public

    HTML

  5. Lyrshop Lyrshop Public

    JavaScript

  6. Lyrsoft Lyrsoft Public

    JavaScript