- Replace rsync deployment with Docker-based deployment - Container runs nginx on port 3000, proxied by host nginx - Add architecture documentation - Add home directory cleanup script - No more direct /var/www writes Co-Authored-By: Paperclip <noreply@paperclip.ing>
4.0 KiB
4.0 KiB
Hatch.surf Architecture
Overview
Hatch.surf is the landing page and brand site for El Foundation. It consists of:
- Static frontend (site/) — HTML/CSS/JS served via nginx
- Go backend (cmd/hatch) — API server for future dynamic features
Deployment Architecture
Current State (Deprecated)
GitHub Push → GitHub Actions → rsync → /var/www/hatch.surf → nginx (host)
Problems:
- Direct filesystem deployment — no isolation
- Host-dependent — can't reproduce locally
- Secrets (SSH keys) required for rsync
New Architecture
GitHub Push → GitHub Actions → Build Docker Image → SCP to Server → Docker Run → nginx reverse proxy
Benefits:
- Containerized — isolated from host
- Reproducible — same image in dev/prod
- No host filesystem dependency
- Easy rollback — just change image tag
Docker Setup
Frontend (site/)
Dockerfile:
FROM nginx:alpine
RUN rm -rf /usr/share/nginx/html/*
COPY . /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
docker-compose.yml:
services:
hatch-homepage:
build: .
ports:
- "127.0.0.1:3000:80"
volumes:
- .:/usr/share/nginx/html:ro
restart: unless-stopped
Backend (cmd/hatch)
Dockerfile:
FROM golang:1.25-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . ./
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /bin/hatch ./cmd/hatch
FROM scratch
COPY --from=build /bin/hatch /bin/hatch
EXPOSE 8080
ENTRYPOINT ["/bin/hatch"]
docker-compose.yml:
services:
hatch:
build: .
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
volumes:
- hatch-data:/data
environment:
- HATCH_PORT=8080
- HATCH_DB_PATH=/data/hatch.db
- HATCH_BASE_URL=${HATCH_BASE_URL:-http://localhost}
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
environment:
- HATCH_HOSTNAME=${HATCH_HOSTNAME:-localhost}
profiles:
- with-caddy
volumes:
hatch-data:
caddy-data:
caddy-config:
Deployment Flow
GitHub Actions (deploy-site.yml)
- Build —
docker build -t hatch-homepage:latest ./site - Save —
docker save hatch-homepage:latest | gzip > hatch-homepage.tar.gz - SCP — Copy tarball to server
- Load —
docker load < /tmp/hatch-homepage.tar.gz - Run —
docker run -d --name hatch-homepage ...
Server Configuration
Nginx reverse proxy (host nginx):
server {
listen 80;
server_name hatch.surf;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name hatch.surf;
ssl_certificate /etc/letsencrypt/live/hatch.surf/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hatch.surf/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Secrets Management
- DEPLOY_HOST — Server IP/hostname
- DEPLOY_USER — SSH user (nara)
- DEPLOY_KEY — SSH private key (stored in GitHub Secrets)
No secrets in repo. All deployment credentials in GitHub Secrets.
Rollback Procedure
If deployment fails:
# On server
docker stop hatch-homepage
docker rm hatch-homepage
docker run -d --name hatch-homepage --restart unless-stopped -p 127.0.0.1:3000:80 hatch-homepage:previous-tag
Future Improvements
- Container registry — Push images to GitHub Container Registry (ghcr.io)
- Health checks — Add HEALTHCHECK to Dockerfile
- Monitoring — Add Prometheus metrics endpoint
- CDN — Serve static assets via Cloudflare/CloudFront
- SSL automation — Certbot in container or Caddy auto-SSL