scaffold: Docker infrastructure — Compose, Nginx, NATS, Dockerfile
4-service stack (PostgreSQL 16, NATS JetStream, Rust API, Nginx), multi-stage Rust build with dependency caching, wildcard subdomain routing for public sites, WebSocket support, rate limiting zones. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
33
docker/Dockerfile.api
Normal file
33
docker/Dockerfile.api
Normal file
@@ -0,0 +1,33 @@
|
||||
# Multi-stage build for Corrosion API
|
||||
# Stage 1: Build the Rust binary
|
||||
FROM rust:1.84-alpine AS builder
|
||||
|
||||
RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Cache dependencies — copy manifests first
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
RUN mkdir src && echo "fn main() {}" > src/main.rs
|
||||
RUN cargo build --release 2>/dev/null || true
|
||||
|
||||
# Now copy actual source and build
|
||||
COPY src/ src/
|
||||
COPY migrations/ migrations/
|
||||
RUN touch src/main.rs && cargo build --release
|
||||
|
||||
# Stage 2: Runtime image
|
||||
FROM alpine:3.20
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /build/target/release/corrosion-api .
|
||||
COPY migrations/ migrations/
|
||||
|
||||
ENV RUST_LOG=corrosion_api=info,tower_http=info
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["./corrosion-api"]
|
||||
89
docker/docker-compose.yml
Normal file
89
docker/docker-compose.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: corrosion-db
|
||||
environment:
|
||||
POSTGRES_DB: corrosion
|
||||
POSTGRES_USER: corrosion
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-corrosion_dev}
|
||||
volumes:
|
||||
- pg_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U corrosion"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
nats:
|
||||
image: nats:latest
|
||||
container_name: corrosion-nats
|
||||
command:
|
||||
- "--jetstream"
|
||||
- "--store_dir=/data"
|
||||
- "--config=/etc/nats/nats.conf"
|
||||
volumes:
|
||||
- nats_data:/data
|
||||
- ./nats.conf:/etc/nats/nats.conf:ro
|
||||
ports:
|
||||
- "4222:4222" # Client connections
|
||||
- "8222:8222" # Monitoring
|
||||
- "9222:9222" # WebSocket (frontend real-time)
|
||||
healthcheck:
|
||||
test: ["CMD", "nats-server", "--signal", "ldm"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ../backend
|
||||
dockerfile: ../docker/Dockerfile.api
|
||||
container_name: corrosion-api
|
||||
environment:
|
||||
DATABASE_URL: postgres://corrosion:${DB_PASSWORD:-corrosion_dev}@postgres:5432/corrosion
|
||||
NATS_URL: nats://nats:4222
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN}
|
||||
CLOUDFLARE_ZONE_ID: ${CLOUDFLARE_ZONE_ID}
|
||||
STEAM_API_KEY: ${STEAM_API_KEY}
|
||||
SMTP_HOST: ${SMTP_HOST:-localhost}
|
||||
SMTP_PORT: ${SMTP_PORT:-587}
|
||||
SMTP_USERNAME: ${SMTP_USERNAME}
|
||||
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
||||
SMTP_FROM: ${SMTP_FROM:-noreply@corrosionmgmt.com}
|
||||
FRONTEND_URL: ${FRONTEND_URL:-https://panel.corrosionmgmt.com}
|
||||
RUST_LOG: corrosion_api=info,tower_http=info
|
||||
volumes:
|
||||
- map_data:/data/maps
|
||||
- backup_data:/data/backups
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
nats:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: corrosion-nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ../frontend/dist:/usr/share/nginx/html:ro
|
||||
- map_data:/data/maps:ro
|
||||
depends_on:
|
||||
- api
|
||||
|
||||
volumes:
|
||||
pg_data:
|
||||
nats_data:
|
||||
map_data:
|
||||
backup_data:
|
||||
35
docker/nats.conf
Normal file
35
docker/nats.conf
Normal file
@@ -0,0 +1,35 @@
|
||||
# Corrosion NATS Configuration
|
||||
# JetStream enabled for persistent messaging
|
||||
|
||||
listen: 0.0.0.0:4222
|
||||
|
||||
# JetStream configuration
|
||||
jetstream {
|
||||
store_dir: /data
|
||||
max_mem: 256MB
|
||||
max_file: 2GB
|
||||
}
|
||||
|
||||
# WebSocket listener for frontend real-time updates
|
||||
websocket {
|
||||
listen: "0.0.0.0:9222"
|
||||
no_tls: true # TLS terminated at Nginx/Cloudflare
|
||||
}
|
||||
|
||||
# HTTP monitoring
|
||||
http: 0.0.0.0:8222
|
||||
|
||||
# Logging
|
||||
debug: false
|
||||
trace: false
|
||||
logtime: true
|
||||
|
||||
# Limits
|
||||
max_payload: 8MB # Support map file transfer metadata
|
||||
max_connections: 10000
|
||||
|
||||
# Authorization — tokens validated per-connection
|
||||
# Plugin and companion agents authenticate with license-specific tokens
|
||||
authorization {
|
||||
timeout: 5
|
||||
}
|
||||
153
docker/nginx.conf
Normal file
153
docker/nginx.conf
Normal file
@@ -0,0 +1,153 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 250M; # Map uploads up to 200MB + overhead
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
# Rate limiting zones
|
||||
limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/s;
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
|
||||
|
||||
# Upstream API
|
||||
upstream api {
|
||||
server api:3000;
|
||||
}
|
||||
|
||||
# Main server — panel.corrosionmgmt.com
|
||||
server {
|
||||
listen 80;
|
||||
server_name panel.corrosionmgmt.com;
|
||||
|
||||
# API proxy
|
||||
location /api/ {
|
||||
limit_req zone=api burst=50 nodelay;
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
|
||||
# WebSocket support for console streaming
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Auth endpoints — stricter rate limiting
|
||||
location /api/auth/ {
|
||||
limit_req zone=auth burst=10 nodelay;
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
}
|
||||
|
||||
# Frontend SPA
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
|
||||
# Wildcard server — *.corrosionmgmt.com (public server sites)
|
||||
server {
|
||||
listen 80;
|
||||
server_name *.corrosionmgmt.com;
|
||||
|
||||
# Public API proxy (subset of endpoints)
|
||||
location /api/public/ {
|
||||
limit_req zone=api burst=50 nodelay;
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
}
|
||||
|
||||
# Store API proxy
|
||||
location /api/store/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
}
|
||||
|
||||
# PayPal webhook
|
||||
location /api/store/webhook/ {
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
}
|
||||
|
||||
# Public site frontend
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
|
||||
# Status page — status.corrosionmgmt.com
|
||||
server {
|
||||
listen 80;
|
||||
server_name status.corrosionmgmt.com;
|
||||
|
||||
location /api/public/ {
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
|
||||
# Map file downloads — direct file serving with sendfile
|
||||
server {
|
||||
listen 80;
|
||||
server_name api.corrosionmgmt.com;
|
||||
|
||||
location /maps/ {
|
||||
alias /data/maps/;
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
aio on;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://api;
|
||||
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;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user