No description
Find a file
2026-08-11 17:30:50 +02:00
css style: restore profile card outline 2026-08-11 17:30:50 +02:00
deploy security: harden static site deployment 2026-08-11 17:16:48 +02:00
img chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
js chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
.dockerignore chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
.editorconfig chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
.env.example chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
.gitattributes chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
.gitignore chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
404.html security: harden static site deployment 2026-08-11 17:16:48 +02:00
docker-compose.yml security: harden static site deployment 2026-08-11 17:16:48 +02:00
Dockerfile security: harden static site deployment 2026-08-11 17:16:48 +02:00
favicon.ico chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
icon.png chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
icon.svg chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
index.html style: restore profile card outline 2026-08-11 17:30:50 +02:00
LICENSE.txt chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
package-lock.json chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
package.json chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
README.md chore: prepare homepage repository for publishing 2026-08-11 17:25:11 +02:00
robots.txt chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
site.webmanifest chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
webpack.common.js chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
webpack.config.dev.js chore: capture homepage baseline 2026-08-11 16:26:50 +02:00
webpack.config.prod.js chore: capture homepage baseline 2026-08-11 16:26:50 +02:00

FIW Labs Homepage

The source for fiwlabs.dev, the personal portfolio of Alex (Fi3w0). It presents systems and desktop projects including TideWM, Scorium, Flux, Moonlit Shell, and the FIW Minecraft tooling collection.

The site is intentionally framework-light: semantic HTML, hand-written CSS, and vanilla JavaScript are compiled into a static production bundle. There is no analytics, telemetry, backend, database, or runtime dependency on third-party fonts, icons, or scripts.

Highlights

  • Responsive editorial interface with accessible navigation and reduced-motion support.
  • Interactive liquid ASCII artwork with graceful text fallbacks.
  • Self-contained assets and strict browser security headers.
  • Reproducible Webpack production build.
  • Unprivileged, read-only Nginx container designed to sit behind Traefik.

Technology

Area Choice
Interface HTML, CSS, vanilla JavaScript
Build Node.js 24, Webpack 5
Runtime Unprivileged Nginx on port 8080
Deployment Docker Compose and Traefik
Privacy No analytics or third-party runtime requests

Local development

Requirements: Node.js 24 and npm.

npm ci
npm start

Create the production bundle with:

npm run build

Webpack writes the static site to dist/.

Production deployment

The Compose stack expects an existing external Docker network shared with Traefik. Copy the example environment file and adjust it for the target host:

cp .env.example .env
docker network create proxy
docker compose config
docker compose up --build -d

The network only needs to be created once. If Traefik already owns it, skip that command.

Variable Default Purpose
DOMAIN fiwlabs.dev Traefik host rule
TRAEFIK_NETWORK proxy Shared external network
TRAEFIK_HTTPS_ENTRYPOINT websecure HTTPS entrypoint
TRAEFIK_CERT_RESOLVER porkbun Configured certificate resolver
IMAGE_NAME fiws-page Local/container registry image name
IMAGE_TAG latest Image tag to deploy

Check the deployment with:

docker compose ps
docker compose logs --tail=100 fiws-page

Docker monitors /healthz inside the container. The service is exposed only to the shared Docker network; it does not publish a host port.

Security posture

The production container runs as an unprivileged user with a read-only filesystem, all Linux capabilities dropped, privilege escalation disabled, and bounded CPU, memory, process, temporary-storage, and log usage. Nginx serves only static files and applies CSP, HSTS, referrer, permissions, framing, and content-type protections.

Keep secrets out of the frontend and out of Docker build arguments. Everything delivered to a browser is public by definition.

Repository layout

css/                 Site styles
deploy/nginx.conf    Static server and security headers
img/                 Optimized project artwork
js/app.js            Interaction and visual effects
Dockerfile           Multi-stage production image
docker-compose.yml   Traefik-connected runtime
webpack.*.js         Development and production builds

License

The website source is available under the MIT License. Product names, screenshots, logos, and third-party marks retain their respective rights.