Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

134 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Web at Speed Website

Static site hosting for webatspeed.de, managed with AWS CDK in infra/.

  • AWS S3, CloudFront, Route 53, ACM, SES
  • One stack, WebAtSpeedStack (eu-central-1)
  • The us-east-1 wildcard certificate is referenced by ARN rather than managed — CloudFormation cannot adopt an ACM certificate, so the stack owns its DNS validation record instead

Domains

Domain Content Behaviour
www.webatspeed.de Corporate Website (current) serves the site
webatspeed.de Corporate Website (current) redirects to www
micro.webatspeed.de Corporate Website (2023) serves an archived site
legacy.webatspeed.de Corporate Website (2015) serves another archived site
easypeasy.webatspeed.de Basic Japanese Training serves the Angular app
japan.webatspeed.de Basic Japanese Training redirects to easypeasy
hanashite.webatspeed.de Japanese Listening Comprehension set up separately (see repo)

Site content

Page content is tracked in git under site/. Each directory is named for the bucket it belongs to:

site/www/        -> www.webatspeed.de        the landing page
site/micro/      -> micro.webatspeed.de      the previous site, archived
site/legacy/     -> legacy.webatspeed.de
site/easypeasy/  -> easypeasy.webatspeed.de

site/www is the only one that is not a plain S3 mirror — it is a project with a build step, described under Building site/www.

To re-pull from S3 if the buckets have drifted from the repo:

aws s3 sync s3://www.webatspeed.de site/www
aws s3 sync s3://micro.webatspeed.de site/micro
aws s3 sync s3://legacy.webatspeed.de site/legacy
aws s3 sync s3://easypeasy.webatspeed.de site/easypeasy

Deployment

There is no CI/CD. Edit the files under site/, then publish by hand. Every command below needs AWS credentials for the webatspeed account (ambient credentials via a working profile — same as Infrastructure below).

site/www is the only site with a build step. site/www/deploy.sh (npm run deploy from site/www, after npm install once) does the whole thing in one command: build, then sync only the deployable entries — the four HTML files, imprint/, privacy/, favicon.ico, site.webmanifest and assets/ (including assets/vendor/, assets/theme.js and assets/contact.js, which are hand-maintained rather than built) — then invalidate. src/, package*.json, node_modules/ and the READMEs stay out of the bucket, which is why this site's sync needs --exclude filters and no other site does:

cd site/www
npm install                     # once
npm run deploy

Equivalent to, run from the repo root:

cd site/www && npm run build && cd ..
aws s3 sync site/www s3://www.webatspeed.de --delete \
  --exclude 'src/*' --exclude 'node_modules/*' \
  --exclude 'package.json' --exclude 'package-lock.json' --exclude 'README.md' --exclude 'deploy.sh'
aws cloudfront create-invalidation --distribution-id E1I3JETEJR7M6F --paths '/*'

The other sites are plain mirrors — no build, no excludes:

aws s3 sync site/legacy s3://legacy.webatspeed.de --delete
aws cloudfront create-invalidation --distribution-id E3TWTVZQRYIGX0 --paths '/*'
aws s3 sync site/easypeasy s3://easypeasy.webatspeed.de --delete
aws cloudfront create-invalidation --distribution-id E3AG8LU1RIZKGP --paths '/*'

Notes:

  • --delete removes remote files that no longer exist locally. Run without it first if unsure.
  • Without an invalidation, CloudFront keeps serving the old copy for up to 24 hours (default_ttl 86400).
  • The webatspeed.de and japan.webatspeed.de buckets are intentionally empty — they only hold a redirect configuration, so nothing is synced to them.
  • hanashite.webatspeed.de is a separate stack and repo — see the link in the Domains table — and is not deployed from here.

Developing site/www

The landing page is four static pages — index.html, imprint.html, privacy.html and 404.html, plus folder copies of the two legal pages — built from Tailwind 4 + daisyUI 5. Nothing runs at runtime beyond ~50 lines of inline vanilla JS and assets/theme.js; the build only turns src/app.css into assets/app.css. Fonts and icon fonts are self-hosted, so the pages contact no third-party host. Verified on node v26.3.0 / npm 11.16.0.

Daily loop, two terminals (after npm install in site/www, if not done already):

npm run watch                   # rebuilds assets/app.css on save
python3 -m http.server 8000     # any static server works

Two things to know before editing:

  • Never edit assets/app.css. It is generated and overwritten on every build. All CSS changes belong in src/app.css. It is committed anyway, because there is no CI and the deploy is a plain s3 sync of whatever is in the working tree.
  • Rebuild after markup changes, not just CSS changes. Tailwind scans the four HTML files through @source and only emits the classes it actually finds there. Add a class to a div without rebuilding and it silently does nothing. npm run watch covers this; the risk is editing HTML with no watcher running. A new HTML page needs its own @source line in src/app.css or every class unique to it is dropped.

The legal pages are German, as required of a German company, and carry noindex. Both reuse the landing page's footer verbatim, so the Legal column stays identical across the site. Each page also carries its own copy of the font-boot snippet: app.css sets body{opacity:0} and only reveals it once JS adds html.boot-done, so a page without that script never appears.

Dark mode follows the operating system until the visitor touches the toggle; from then on their choice is stored under the localStorage key was-theme and survives navigation and later visits. assets/theme.js holds all of that logic — the CSS side is still the single #was-theme checkbox. privacy.html names that key explicitly, so changing it means changing the privacy page too.

Nothing on these pages is fetched from a third-party host: Font Awesome is vendored under assets/vendor/ with its fonts in assets/fonts/, Source Sans 3 is declared in src/app.css, and the brand logos in the tech-stack tiles are inlined <svg> markup (sourced from Simple Icons, CC0-licensed) rather than an icon font or image. Adding any external <link>, <script> or webfont invalidates a claim the privacy page makes.

site/www/README.md covers the rest: the two deliberate token systems, the manual-only dark mode, the stylesheet-relative @font-face URL, adding images, and the screenshot-diff procedure.

Infrastructure

cd infra
npm install
npx cdk diff
npx cdk deploy

Domains and the certificate id live in infra/lib/config.ts. The AWS account is not committed — it comes from the ambient credentials via CDK_DEFAULT_ACCOUNT, which the CDK CLI sets for you, so the commands above need no extra setup beyond a working profile. Running the app outside the CDK CLI needs AWS_ACCOUNT_ID instead; an unresolved account fails loudly rather than synthesizing an environment-agnostic stack.

The buckets, hosted zone, certificate, distributions and SES identity all carry DeletionPolicy: Retain. cdk destroy therefore removes the stack but leaves the infrastructure — deliberate, because the hosted zone is shared with the hanashite stack and the bucket names are the domain names.

About

Web at Speed website

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages