Skip to content

Commit 73d8bee

Browse files
create deployment files
1 parent 91fe17c commit 73d8bee

File tree

8 files changed

+268
-5
lines changed

8 files changed

+268
-5
lines changed

.env.prod.sample

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Production Environment Configuration
2+
# This file serves as a template for GitHub Secrets configuration
3+
#
4+
# IMPORTANT: Secrets are injected directly into Docker containers via environment
5+
# variables. No .env files are created on the host system for security.
6+
7+
# Domain Configuration
8+
DOMAIN=
9+
10+
# Container Registry Configuration
11+
FRONTEND_IMAGE=
12+
BACKEND_IMAGE=
13+
14+
# Database Configuration (External PostgreSQL)
15+
PGUSER=
16+
PGPASSWORD=
17+
PGHOST=
18+
PGDATABASE=
19+
PGPORT=
20+
21+
# Security Keys (Store as GitHub Secrets)
22+
ENCRYPTION_KEY
23+
JWT_SECRET=
24+
25+
# RSKY Configuration
26+
RSKY_FEEDGEN=
27+
RSKY_API_KEY=your_rsky_api_key
28+
29+
# Fixed Configuration (automatically set in deployment)
30+
PORT=
31+
CLIENT_URL=
32+
BASE_URL=
33+
BSKY_BASE_API_URL=https://api.bsky.app
34+
MUTE_LIST_URI=
35+
MUTE_LIST_ADMIN_DID=
36+
RECONCILIATION_INTERVAL_MS=

.github/workflows/ci.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: CI - Validate Changes
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
jobs:
10+
validate:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: '22'
21+
cache: 'npm'
22+
23+
- name: Install dependencies
24+
run: npm ci
25+
26+
- name: Run type checking
27+
run: npm run type-check
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Build Docker image for testing
33+
uses: docker/build-push-action@v5
34+
with:
35+
context: .
36+
target: prodrunner
37+
load: true
38+
tags: safe-skies-api:test
39+
cache-from: type=gha
40+
cache-to: type=gha,mode=max
41+
42+
- name: Create test docker-compose override
43+
run: |
44+
cat > docker-compose.test.yml << EOF
45+
services:
46+
backend:
47+
image: safe-skies-api:test
48+
EOF
49+
50+
- name: Start test environment with built image
51+
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up -d
52+
53+
- name: Run tests using Docker image
54+
run: docker compose -f docker-compose.yml -f docker-compose.test.yml exec backend npm run test
55+
56+
- name: Stop test environment
57+
run: docker compose -f docker-compose.yml -f docker-compose.test.yml down
58+
if: always()
59+
60+
- name: Clean up test files
61+
run: rm -f docker-compose.test.yml
62+
if: always()

.github/workflows/deploy.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Deploy to Production
2+
3+
on:
4+
push:
5+
branches: [main]
6+
7+
env:
8+
IMAGE_NAME: safe-skies-api
9+
10+
jobs:
11+
build-and-push:
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
packages: write
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Docker Buildx
22+
uses: docker/setup-buildx-action@v3
23+
24+
- name: Log in to DigitalOcean Container Registry
25+
uses: docker/login-action@v3
26+
with:
27+
registry: ${{ secrets.DO_REGISTRY_URL }}
28+
username: ${{ vars.DIGITALOCEAN_USERNAME }}
29+
password: ${{ secrets.DO_REGISTRY_TOKEN }}
30+
31+
- name: Extract metadata
32+
id: meta
33+
uses: docker/metadata-action@v5
34+
with:
35+
images: ${{ secrets.DO_REGISTRY_URL }}/safe-skies-api
36+
tags: |
37+
type=sha,prefix={{branch}}-
38+
type=raw,value=latest
39+
40+
- name: Build and push Docker image
41+
uses: docker/build-push-action@v5
42+
with:
43+
context: .
44+
target: prodrunner
45+
push: true
46+
tags: ${{ steps.meta.outputs.tags }}
47+
labels: ${{ steps.meta.outputs.labels }}
48+
cache-from: type=gha
49+
cache-to: type=gha,mode=max

Caddyfile

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
safeskies.blackskyweb.xyz {
2+
# --- Compression (use both; zstd is faster/smaller where supported)
3+
encode zstd gzip
4+
5+
# --- Security headers
6+
header {
7+
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
8+
X-Content-Type-Options "nosniff"
9+
X-Frame-Options "DENY"
10+
Referrer-Policy "strict-origin-when-cross-origin"
11+
12+
# (Optional / legacy) XSS protection header; modern browsers ignore it
13+
X-XSS-Protection "1; mode=block"
14+
}
15+
16+
# --- Common /public files (add more as needed)
17+
handle /favicon.ico {
18+
root * /srv/frontend/public
19+
file_server
20+
header Cache-Control "public, max-age=86400"
21+
}
22+
handle /robots.txt {
23+
root * /srv/frontend/public
24+
file_server
25+
header Cache-Control "public, max-age=86400"
26+
}
27+
handle /sitemap.xml {
28+
root * /srv/frontend/public
29+
file_server
30+
header Cache-Control "public, max-age=3600"
31+
}
32+
33+
# --- Admin auth (hit backend service directly)
34+
handle /admin/auth/* {
35+
reverse_proxy backend:4000
36+
}
37+
38+
# Handle regular OAuth callbacks
39+
handle /auth/* {
40+
reverse_proxy backend:4000
41+
}
42+
43+
# Serve client metadata from backend
44+
handle /oauth/client-metadata.json {
45+
reverse_proxy backend:4000
46+
}
47+
48+
# Handle front-end login and callback after original OAuth callback returns
49+
handle /oauth/* {
50+
reverse_proxy frontend:3000
51+
}
52+
53+
# --- Everything else → Next.js server
54+
# (do NOT SPA-fallback; let Next handle routing)
55+
reverse_proxy frontend:3000 {
56+
header_up Host {host}
57+
}
58+
59+
# --- Access log
60+
log {
61+
output file /var/log/caddy/access.log
62+
format console
63+
}
64+
}

Dockerfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ RUN chown -R node:node /usr/src/app
2525

2626
USER node
2727
COPY --chown=node:node . .
28-
RUN npm run build
28+
RUN npm run build && npm run build:knexfile
2929

3030
FROM base AS prodrunner
31+
COPY docker-entrypoint.sh ./docker-entrypoint.sh
32+
RUN chmod +x ./docker-entrypoint.sh && sed -i 's/\r$//' ./docker-entrypoint.sh && chown node:node ./docker-entrypoint.sh
3133
USER node
3234
COPY --from=prodbuilder --chown=node:node /usr/src/app/node_modules ./node_modules
3335
COPY --from=prodbuilder --chown=node:node /usr/src/app/dist ./dist
34-
CMD node dist/src/server.js
36+
COPY --from=prodbuilder --chown=node:node /usr/src/app/migrations ./migrations
37+
COPY --from=prodbuilder --chown=node:node /usr/src/app/knexfile.js ./knexfile.js
38+
COPY --from=prodbuilder --chown=node:node /usr/src/app/package.json ./package.json
39+
ENTRYPOINT ["./docker-entrypoint.sh"]

docker-compose.prod.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: '3.8'
2+
3+
services:
4+
frontend:
5+
image: ${FRONTEND_IMAGE}
6+
restart: unless-stopped
7+
depends_on:
8+
- backend
9+
10+
backend:
11+
image: ${BACKEND_IMAGE}
12+
restart: unless-stopped
13+
# Provide the environment variables via .env file
14+
env_file:
15+
- .env.prod.sample
16+
expose:
17+
- "4000"
18+
logging:
19+
driver: "json-file"
20+
options:
21+
max-size: "10m"
22+
max-file: "3"
23+
24+
caddy:
25+
image: caddy:2-alpine
26+
restart: unless-stopped
27+
ports:
28+
- "80:80"
29+
- "443:443"
30+
volumes:
31+
- ./Caddyfile:/etc/caddy/Caddyfile
32+
- caddy_data:/data
33+
depends_on:
34+
- frontend
35+
- backend
36+
37+
volumes:
38+
caddy_data:

docker-entrypoint.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
set -e
3+
4+
echo "Running database migrations..."
5+
npm run migrate:up
6+
7+
echo "Starting server..."
8+
exec node dist/src/server.js

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
"type-check": "tsc --noEmit",
1717
"format": "biome format . --write",
1818
"prepare": "husky install",
19-
"migrate:create": "knex migrate:make",
20-
"migrate:up": "knex migrate:latest",
21-
"migrate:down": "knex migrate:down"
19+
"migrate:create": "ts-node node_modules/.bin/knex migrate:make",
20+
"migrate:up": "ts-node node_modules/.bin/knex migrate:latest",
21+
"migrate:down": "ts-node node_modules/.bin/knex migrate:down",
22+
"build:knexfile": "tsc knexfile.ts --outDir . --esModuleInterop --module commonjs --target ES2020 --skipLibCheck"
2223
},
2324
"keywords": [],
2425
"author": "",

0 commit comments

Comments
 (0)