26c31fded6b3bde82cc79078ccc6a525f0162e31
mifi.holdings — Landing Page
Static landing site for mifi.holdings (and www). Plain HTML/CSS, no framework; served by nginx in Docker behind Traefik, with CI/CD via Woodpecker and deployment via Portainer.
Quick reference
| What | Where |
|---|---|
| Site | mifi.holdings, www.mifi.holdings (HTTPS) |
| Runtime | nginx (Alpine) in Docker |
| Reverse proxy / TLS | Traefik (Let's Encrypt) |
| CI/CD | Woodpecker (ci → build → deploy) |
| Registry | git.mifi.dev/mifi-holdings/landing |
| Package manager | pnpm |
Architecture
┌─────────────────┐
│ Traefik │ (routing, TLS, websecure)
└────────┬────────┘
│
┌────────▼────────┐
│ Docker container │ mifi-holdings-landing
│ nginx:alpine │ port 80
│ /usr/share/ │
│ nginx/html ← │ static files from image
└─────────────────┘
- Build: Docker image =
nginx:alpine+ projectnginx/conf.d/+src/copied into/usr/share/nginx/html. - Run: Single service on external network
marina-net; Traefik routesmifi.holdingsandwww.mifi.holdingsto this container (HTTPS,security-prison@filemiddleware).
Repo structure
.
├── src/ # Static site (served as-is)
│ ├── index.html
│ └── css/
│ └── style.css
├── nginx/
│ └── conf.d/
│ └── default.conf # nginx server config (cache rules, SPA fallback)
├── .woodpecker/
│ ├── ci.yml # Lint + format check (PR + push to main)
│ ├── build.yml # Build image, push to registry (main)
│ └── deploy.yml # Trigger Portainer redeploy (main)
├── docker-compose.yml # Service + Traefik labels for production
├── Dockerfile # nginx + config + src
├── package.json # pnpm scripts: format, lint, docker build/push
└── README.md
Tech stack
- Frontend: Static HTML + CSS only (no JS build step).
- Server: nginx (Alpine) in Docker.
- Tooling: pnpm (format with Prettier, lint with yamllint for
.woodpecker/*.ymlanddocker-compose.yml). - Deployment: Docker image → Gitea registry → Portainer stack redeploy.
Local development
- Dependencies:
pnpm install(only devDependencies: Prettier, yaml-lint). - Format:
pnpm format/pnpm format:check. - Lint:
pnpm lint(yamllint on Woodpecker and docker-compose YAML). - Run locally (Docker):
- Build:
pnpm docker:build(ordocker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .). - Run: use
docker-compose uponly on a host that hasmarina-netand Traefik; otherwise run the image with a port map and openhttp://localhost:<port>.
- Build:
There is no dev server in this repo; edit src/ and refresh the browser or rebuild the image to test.
Docker
- Dockerfile: Copies
nginx/conf.d/andsrc/into annginx:alpineimage. No multi-stage build; the image is the final runtime. - Image: Tagged as
git.mifi.dev/mifi-holdings/landing:latest(and:<commit-sha>in CI). - Local build/push:
pnpm docker:build,pnpm docker:push(requires login togit.mifi.dev).
CI/CD (Woodpecker)
Three pipelines:
-
ci (
.woodpecker/ci.yml)- When: Every PR and every push to
main. - Steps: Install deps → Prettier format check → yamllint (Woodpecker + docker-compose). Mattermost notifications on success/failure.
- When: Every PR and every push to
-
build (
.woodpecker/build.yml)- When: Push/tag/manual on
main(and deployment to production); depends_on: ci. - Steps: Build Docker image (linux/amd64, up to 3 retries) → push
:latestand:<CI_COMMIT_SHA>togit.mifi.dev/mifi-holdings/landing. Mattermost notifications.
- When: Push/tag/manual on
-
deploy (
.woodpecker/deploy.yml)- When: Same as build (main / production deploy); depends_on: ci.
- Steps: Call Portainer webhook to redeploy the stack. Mattermost notifications.
Secrets used: gitea_registry_username, gitea_package_token, portainer_webhook_url, mattermost_* (bot token, channel IDs, API URL).
Deployment (production)
- Orchestration: Stack defined in
docker-compose.yml, deployed via Portainer (webhook triggered by Woodpecker deploy pipeline). - Network: Container joins external network
marina-net(shared with Traefik). - Traefik:
- Hosts:
mifi.holdings,www.mifi.holdings. - Entrypoint:
websecure(HTTPS). - TLS: Let's Encrypt (
tls.certresolver=letsencrypt). - Middleware:
security-prison@file. - Backend: this service, port 80.
- Hosts:
- Healthcheck:
wget --spider -q http://localhost/every 20s (timeout 3s, 3 retries).
To deploy manually: pull the latest image and redeploy the stack in Portainer, or trigger the Portainer webhook (e.g. same URL as in portainer_webhook_url).
nginx behavior
- Root:
/usr/share/nginx/html(contents ofsrc/). - HTML:
Cache-Control: public, no-cacheso updates are visible quickly. - JS/CSS: Long cache,
immutablefor hashed/versioned assets. - Images/fonts: Cached (30d / 1y).
- SPA-style fallback:
/tries$uri,$uri/, thenindex.html, then 404.
Summary
- What it is: Static landing for mifi.holdings.
- How it runs: nginx in Docker, fronted by Traefik on
marina-net. - How it’s updated: Push to
main→ Woodpecker runs ci, build (image + push), deploy (Portainer webhook); Mattermost reports status.
Description
The landing page for the (www.)mifi.holdings domain. Because the root of my digital empire needs a page.
https://mifi.holdings
Languages
JavaScript
40.6%
HTML
39%
CSS
19.3%
Dockerfile
1.1%