Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Complete MVP implementation of the Cast GHL Conversation Provider bridge: - Go module setup with chi router and mongo-driver dependencies - Config loading with env var validation and defaults - MongoDB token store with upsert, get, update, delete operations - Cast.ph SMS client with 429 retry logic and typed errors - Phone number normalization (E.164 ↔ Philippine local format) - GHL OAuth 2.0 install/callback/refresh flow - GHL webhook handler with ECDSA signature verification (async dispatch) - GHL API client for message status updates and inbound message stubs - Multi-stage Dockerfile, docker-compose with MongoDB, Woodpecker CI pipeline - Unit tests for phone normalization, Cast client, GHL webhook, and OAuth handlers Co-Authored-By: SideKx <sidekx.ai@sds.dev>
4.3 KiB
4.3 KiB
Task 09: Docker & Deployment
Objective
Finalize Dockerfile, docker-compose, Woodpecker CI, and deployment docs.
Part A: Dockerfile (finalize)
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /cast-ghl-provider ./cmd/server/
FROM alpine:3.19
RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /cast-ghl-provider /cast-ghl-provider
EXPOSE 3002
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://localhost:3002/health || exit 1
CMD ["/cast-ghl-provider"]
Key points:
- Multi-stage build: ~15MB final image
CGO_ENABLED=0for static binary-ldflags="-s -w"strips debug infoca-certificatesfor HTTPS calls to Cast and GHL APIstzdatafor timezone handlingHEALTHCHECKbuilt into the image
Part B: docker-compose.yaml (finalize)
services:
bridge:
build: .
ports:
- "${PORT:-3002}:${PORT:-3002}"
env_file: .env
depends_on:
mongo:
condition: service_started
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
mongo:
image: mongo:7
volumes:
- mongo-data:/data/db
restart: unless-stopped
# NOT exposed to host — only accessible from bridge service
volumes:
mongo-data:
Part C: Woodpecker CI (.woodpecker.yml)
steps:
- name: build
image: golang:1.22-alpine
commands:
- go build ./cmd/server/
- name: vet
image: golang:1.22-alpine
commands:
- go vet ./...
- name: test
image: golang:1.22-alpine
commands:
- go test ./...
- name: docker-build
image: plugins/docker
settings:
repo: registry.sds.dev/cast/cast-ghl-provider
registry: registry.sds.dev
tags:
- latest
- "${CI_COMMIT_TAG}"
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
event: tag
ref: refs/tags/v*
- name: deploy
image: appleboy/drone-ssh
settings:
host:
from_secret: deploy_host
username:
from_secret: deploy_user
key:
from_secret: deploy_key
script:
- cd /opt/cast-ghl-provider
- docker compose pull
- docker compose up -d --remove-orphans
when:
event: tag
ref: refs/tags/v*
Woodpecker secrets to configure:
docker_username— container registry usernamedocker_password— container registry passworddeploy_host— Vultr server IPdeploy_user— SSH userdeploy_key— SSH private key
Release workflow:
git tag v0.1.0
git push origin v0.1.0
# Woodpecker: build → vet → test → docker build+push → SSH deploy
Part D: Nginx reverse proxy config
server {
listen 443 ssl;
server_name ghl.cast.ph;
ssl_certificate /etc/letsencrypt/live/ghl.cast.ph/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ghl.cast.ph/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3002;
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;
}
}
server {
listen 80;
server_name ghl.cast.ph;
return 301 https://$server_name$request_uri;
}
Part E: Server setup checklist
- Create directory:
mkdir -p /opt/cast-ghl-provider - Copy
docker-compose.yamland.envto server - Configure
.envwith production values - Set up Nginx + Let's Encrypt
docker compose up -d- Verify:
curl https://ghl.cast.ph/health - Update GHL Marketplace app:
- Delivery URL:
https://ghl.cast.ph/api/ghl/v1/webhook/messages - Redirect URI:
https://ghl.cast.ph/oauth-callback
- Delivery URL:
Acceptance Criteria
docker compose buildsucceedsdocker compose upstarts bridge + mongo- Health check passes:
curl localhost:3002/health - Docker image is <20MB
- MongoDB not exposed to host network
.woodpecker.ymlhas build, vet, test steps- Docker build+push only on
v*tags - Deploy step uses SSH to pull and restart
- Nginx config handles HTTPS + proxy
- Log rotation configured (10MB, 3 files)