Skip to content

Infrastructure

Infrastructure Standards

CI/CD Platform

Woodpecker CI — self-hosted on the tools VPS (Tailscale IP 100.81.122.65; no public subdomain confirmed in repo) Container registry — Gitea at gitea.level147.net Deployment — Docker Compose on target hosts via Woodpecker deploy agents


Woodpecker Agent Taxonomy

Naming convention

{role}-{location}-{backend}
SegmentValuesNotes
rolebuild, deployWhat the agent does
locationworkstation, web, toolsWhich physical host
backenddocker, localWoodpecker backend type

Current agents

WOODPECKER_HOSTNAMEHostBackendPurpose
build-workstation-dockernerdstation (Windows workstation)dockerBuilds container images via Docker Desktop
build-workstation-localnerdstation (Windows workstation)localBare-metal tasks (GPU, native tools) — future
deploy-web-dockerweb serverdockerRuns docker compose deploys via Docker socket

Agent labels

Labels are how pipelines target agents. Use labels not hostnames in .woodpecker/*.yml.

# Build step
when:
- event: push
branch: develop
agent:
labels:
type: build
# Deploy step
agent:
labels:
type: deploy
host: web

Standard label keys:

KeyValuesPurpose
typebuild, deployPrimary role
hostweb, tools, workstationTarget host

Volume requirement

Every agent compose must mount a named volume at /etc/woodpecker to persist the registration token. Without it, the agent re-registers as a new identity on every restart, creating ghost entries.

volumes:
- woodpecker-agent-config:/etc/woodpecker
volumes:
woodpecker-agent-config:

Image pinning

Always pin agent image to the same major version as the server. Never use :next in compose files — use the explicit semver tag (e.g. v3.14.1).


Environment Naming

NameBranchImage tagPurpose
stagingdevelop:stagingAuto-deploy on push; integration testing
prodmain:prodManual gate via PR to main

Never use production, development, or dev as environment names — these cause confusion with develop branch.


Docker Image Naming

gitea.level147.net/{owner}/{project}:{env}

Examples:

  • gitea.level147.net/shaun/better:staging
  • gitea.level147.net/shaun/level147-web:prod

Rules:

  • All lowercase, hyphens not underscores
  • Project name matches the Gitea repository name
  • Tag is always the environment name (staging or prod), never a commit hash in the tag field (Woodpecker metadata provides traceability)

Docker Compose Conventions

Service / container naming

Service name = container name = human-readable role.

services:
app: # not "better" or "web"
container_name: better-staging # explicit, matches image name pattern
worker:
container_name: better-worker-staging
redis:
container_name: better-redis

Volume naming

{service}-{purpose}

Examples: woodpecker-agent-config, postgres-data, redis-data

Network naming

NetworkPurpose
proxy-netTraefik-proxied services (external: true on consumer stacks)
app-netInternal service-to-service within a project

Pipeline File Structure

.woodpecker/
├── verify.yml # lint, test, type-check (no external side effects)
├── build.yml # docker build + push (depends_on: verify)
└── deploy.yml # docker compose pull + up (depends_on: build)

depends_on between pipeline files eliminates race conditions. The verify → build → deploy chain is mandatory — never merge build and deploy into one file.


Secrets Management

All secrets injected via Woodpecker repo secrets, never hardcoded in .woodpecker/*.yml.

Standard secret names across projects:

SecretPurpose
GITEA_TOKENRegistry push/pull (PAT with write:package)
DEPLOY_HOSTSSH/socket target for deploy agent

Build-time env vars passed via --build-arg must be declared in both the pipeline and the Dockerfile ARG block.


Host Inventory

HostnameRoleLAN IPTailscale IP
toolsCI server, Gitea, Portainer10.240.0.171100.81.122.65
webApp hosting, deploy agent10.240.0.68100.101.148.89
nerdstationWorkstation, build agent100.75.13.119

Internal services should use LAN IPs where possible. Tailscale IPs are used for cross-network access (e.g. workstation → tools gRPC). Never hardcode Tailscale IPs in production service configs — they change on device re-enrolment.

v0.1.0 · d0d7a20 · 2026-06-26