| name | infra-as-code |
| description | Manage ArtStroy's Docker Compose configuration, Hetzner server provisioning, environment variable management, and infrastructure-as-code practices. Used by DevOps Engineer for all infrastructure changes. |
Infrastructure as Code
ArtStroy's production infrastructure is a single Hetzner VPS running Docker Compose. Keep it simple, reproducible, and documented.
Infrastructure Overview
Hetzner Cloud VPS (Frankfurt region)
└── Docker Compose stack
├── nginx (reverse proxy, SSL termination)
├── app (Astro SSG static files served via nginx)
└── (optional: future services)
Current docker-compose.yml location: /srv/artstroy/docker-compose.yml on the server, and D:/QA_A/artstroy/docker-compose.yml in the repo.
Docker Compose Practices
Rule: the docker-compose.yml in the repo IS the production config. No manual config changes on the server — always commit first, deploy second.
services:
nginx:
image: nginx:alpine
volumes:
- ./dist:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
- "443:443"
restart: unless-stopped
Never hardcode secrets in docker-compose.yml. Use environment variable references:
environment:
- API_KEY=${API_KEY}
Environment Variable Management
Source of truth hierarchy:
- GitHub Actions secrets → used by deploy pipeline (
SSH_DEPLOY_KEY, SERVER_HOST, SERVER_USER)
.env file on the server at /srv/artstroy/.env → used by Docker Compose at runtime
.paperclip.yaml inputs.env → declares which env vars agents need (does not store values)
The .env on the server is NOT in git. It must be provisioned manually the first time and updated via the secrets-management skill when values rotate.
To verify env vars are correctly set on the server:
ssh ${SERVER_USER}@${SERVER_HOST} "cat /srv/artstroy/.env | grep -v '=' | head -20"
Hetzner Server Provisioning
If provisioning a new server (disaster recovery or migration):
- Create new Hetzner Cloud VPS (CX21 or larger; Frankfurt region for EU latency)
- Configure DNS to point
artstroy.net and www.artstroy.net to new IP
- Install Docker and Docker Compose V2
- Install Bun:
curl -fsSL https://bun.sh/install | bash
- Clone repo:
git clone https://github.com/AZANIR/artstroy /srv/artstroy
- Copy
.env file from secure storage (not from git)
- Configure SSH authorized keys for the deploy key
- Test deploy:
cd /srv/artstroy && bun run build && docker compose up -d
- Verify:
curl -I https://artstroy.net
nginx Configuration
nginx serves the static Astro output and handles SSL. Key requirements:
- SSL certificates via Let's Encrypt (certbot) — renewal cron must be active
- Proper HSTS header (see
security-headers-check skill for exact values)
- Gzip compression enabled for HTML/CSS/JS/JSON
- Cache headers for static assets (images, fonts) — long TTL
- Cache headers for HTML — short TTL or no-cache (content updates should be immediate)
Infrastructure Change Protocol
Before making any infrastructure change:
- Document the change in
docs/project_notes/decisions.md (if architectural)
- Test in a local Docker environment if possible
- Create a
ci/{description} branch, commit the change to the repo
- Create PR for CTO review
- After merge and successful deploy, verify the change is live
- If rollback is needed: revert commit → PR → merge → deploy