From aa3e097e16461bf6cee275e9e1efd3a05f54e204 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 17 Apr 2026 10:54:39 -0700 Subject: [PATCH 1/6] initial commit --- docker/unified/build_images.sh | 25 ++++++++++++ docker/unified/certbot-compose.yaml | 19 +++++++++ docker/unified/client.Dockerfile | 20 ++++++++++ docker/unified/docker-compose.yaml | 49 +++++++++++++++++++++++ docker/unified/gateway/nginx.conf | 56 +++++++++++++++++++++++++++ docker/unified/mongoDB.Dockerfile | 3 ++ docker/unified/nginx/conf.d/prod.conf | 31 +++++++++++++++ docker/unified/server.Dockerfile | 22 +++++++++++ 8 files changed, 225 insertions(+) create mode 100755 docker/unified/build_images.sh create mode 100755 docker/unified/certbot-compose.yaml create mode 100755 docker/unified/client.Dockerfile create mode 100755 docker/unified/docker-compose.yaml create mode 100644 docker/unified/gateway/nginx.conf create mode 100755 docker/unified/mongoDB.Dockerfile create mode 100755 docker/unified/nginx/conf.d/prod.conf create mode 100755 docker/unified/server.Dockerfile diff --git a/docker/unified/build_images.sh b/docker/unified/build_images.sh new file mode 100755 index 000000000..49f8c7841 --- /dev/null +++ b/docker/unified/build_images.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Change directory to root directory for correct Docker Context +cd "$(dirname "$0")" +cd ../../ + +# Define an array of services and their Dockerfiles +declare -A services=( + ["uptime_client"]="./docker/prod/client.Dockerfile" + ["uptime_database_mongo"]="./docker/prod/mongoDB.Dockerfile" + ["uptime_server"]="./docker/prod/server.Dockerfile" +) + +# Loop through each service and build the corresponding image +for service in "${!services[@]}"; do + docker build -f "${services[$service]}" -t "$service" . + + # Check if the build succeeded + if [ $? -ne 0 ]; then + echo "Error building $service image. Exiting..." + exit 1 + fi +done + +echo "All images built successfully" \ No newline at end of file diff --git a/docker/unified/certbot-compose.yaml b/docker/unified/certbot-compose.yaml new file mode 100755 index 000000000..9220d07a1 --- /dev/null +++ b/docker/unified/certbot-compose.yaml @@ -0,0 +1,19 @@ +version: "3" + +services: + webserver: + image: nginx:latest + ports: + - 80:80 + - 443:443 + restart: always + volumes: + - ./nginx/conf.d/:/etc/nginx/conf.d/:ro + - ./certbot/www/:/var/www/certbot/:ro + certbot: + image: certbot/certbot:latest + volumes: + - ./certbot/www/:/var/www/certbot/:rw + - ./certbot/conf/:/etc/letsencrypt/:rw + depends_on: + - webserver diff --git a/docker/unified/client.Dockerfile b/docker/unified/client.Dockerfile new file mode 100755 index 000000000..b4c685e3e --- /dev/null +++ b/docker/unified/client.Dockerfile @@ -0,0 +1,20 @@ +FROM node:20-slim AS build + +ENV NODE_OPTIONS="--max-old-space-size=4096" + +WORKDIR /app + +COPY ./client/package*.json ./ + +RUN npm install + +COPY ./client . + +RUN npm run build + +FROM nginx:1.27.1-alpine + +COPY --from=build /app/dist /usr/share/nginx/html +COPY --from=build /app/env.sh /docker-entrypoint.d/env.sh +RUN chmod +x /docker-entrypoint.d/env.sh +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker/unified/docker-compose.yaml b/docker/unified/docker-compose.yaml new file mode 100755 index 000000000..01fab5529 --- /dev/null +++ b/docker/unified/docker-compose.yaml @@ -0,0 +1,49 @@ +services: + gateway: + image: nginx:1.27.1-alpine + container_name: checkmate-gateway + restart: always + ports: + - "80:80" + - "443:443" + volumes: + - /etc/letsencrypt:/etc/nginx/ssl:ro + - ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro + client-prod: + image: ghcr.io/bluewave-labs/checkmate:frontend-demo + restart: always + environment: + UPTIME_APP_API_BASE_URL: "https://demo.checkmate.so/api/v1" + UPTIME_APP_CLIENT_HOST: "https://demo.checkmate.so" + expose: + - "80" + depends_on: + - server-prod + volumes: + - ./nginx/conf.d/prod.conf:/etc/nginx/conf.d/default.conf:ro + server-prod: + image: ghcr.io/bluewave-labs/checkmate:backend-demo + restart: always + ports: + - "52345:52345" + env_file: + - server-prod.env + depends_on: + - mongodb-prod + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + mongodb-prod: + image: ghcr.io/bluewave-labs/checkmate:mongo-demo + restart: always + command: [ "mongod", "--quiet", "--bind_ip_all" ] + volumes: + - ./mongo/data-prod:/data/db + env_file: + - mongo-prod.env + healthcheck: + test: [ "CMD", "mongosh", "--eval", "db.adminCommand('ping')", "--quiet" ] + interval: 5s + timeout: 30s + start_period: 0s + start_interval: 1s + retries: 30 diff --git a/docker/unified/gateway/nginx.conf b/docker/unified/gateway/nginx.conf new file mode 100644 index 000000000..958402196 --- /dev/null +++ b/docker/unified/gateway/nginx.conf @@ -0,0 +1,56 @@ +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; + +# --- PRODUCTION: demo.checkmate.so --- +server { + listen 80; + server_name demo.checkmate.so; + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl; + server_name demo.checkmate.so; + + ssl_certificate /etc/nginx/ssl/live/demo.checkmate.so/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/live/demo.checkmate.so/privkey.pem; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + location / { + # Passes traffic to the prod client on port 80 + proxy_pass http://client-prod:80; + } +} + +# --- STAGING: staging.checkmate.so --- +server { + listen 80; + server_name staging.checkmate.so; + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl; + server_name staging.checkmate.so; + + ssl_certificate /etc/nginx/ssl/live/staging.checkmate.so/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/live/staging.checkmate.so/privkey.pem; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + location / { + # Passes traffic to the staging client on port 80 + proxy_pass http://client-stage:80; + } +} \ No newline at end of file diff --git a/docker/unified/mongoDB.Dockerfile b/docker/unified/mongoDB.Dockerfile new file mode 100755 index 000000000..969a320c2 --- /dev/null +++ b/docker/unified/mongoDB.Dockerfile @@ -0,0 +1,3 @@ +FROM mongo +EXPOSE 27017 +CMD ["mongod"] diff --git a/docker/unified/nginx/conf.d/prod.conf b/docker/unified/nginx/conf.d/prod.conf new file mode 100755 index 000000000..63a42a401 --- /dev/null +++ b/docker/unified/nginx/conf.d/prod.conf @@ -0,0 +1,31 @@ +server { + listen 80; + listen [::]:80; + + server_name _; + server_tokens off; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://server-prod:52345/api/; + proxy_http_version 1.1; + 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 /api-docs/ { + proxy_pass http://server-prod:52345/api-docs/; + proxy_http_version 1.1; + 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; + } +} \ No newline at end of file diff --git a/docker/unified/server.Dockerfile b/docker/unified/server.Dockerfile new file mode 100755 index 000000000..7341b1e9b --- /dev/null +++ b/docker/unified/server.Dockerfile @@ -0,0 +1,22 @@ +FROM node:20-slim + +# Install ping +RUN apt-get update \ + && apt-get install -y iputils-ping \ + && rm -rf /var/lib/apt/lists/* + +ENV NODE_OPTIONS="--max-old-space-size=2048" + +WORKDIR /app + +COPY ./server/package*.json ./ + +RUN npm install + +COPY ./server ./ + +RUN npm run build + +EXPOSE 52345 + +CMD ["node", "dist/index.js"] \ No newline at end of file From b376fe9ab02ea28cfe0f9fe9a6af7963cba0587c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 17 Apr 2026 11:07:25 -0700 Subject: [PATCH 2/6] comment out staging --- docker/unified/gateway/nginx.conf | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docker/unified/gateway/nginx.conf b/docker/unified/gateway/nginx.conf index 958402196..d0989ace1 100644 --- a/docker/unified/gateway/nginx.conf +++ b/docker/unified/gateway/nginx.conf @@ -30,27 +30,27 @@ server { } # --- STAGING: staging.checkmate.so --- -server { - listen 80; - server_name staging.checkmate.so; +# server { +# listen 80; +# server_name staging.checkmate.so; - location / { - return 301 https://$host$request_uri; - } -} +# location / { +# return 301 https://$host$request_uri; +# } +# } -server { - listen 443 ssl; - server_name staging.checkmate.so; +# server { +# listen 443 ssl; +# server_name staging.checkmate.so; - ssl_certificate /etc/nginx/ssl/live/staging.checkmate.so/fullchain.pem; - ssl_certificate_key /etc/nginx/ssl/live/staging.checkmate.so/privkey.pem; +# ssl_certificate /etc/nginx/ssl/live/staging.checkmate.so/fullchain.pem; +# ssl_certificate_key /etc/nginx/ssl/live/staging.checkmate.so/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; +# ssl_protocols TLSv1.2 TLSv1.3; +# ssl_ciphers HIGH:!aNULL:!MD5; - location / { - # Passes traffic to the staging client on port 80 - proxy_pass http://client-stage:80; - } -} \ No newline at end of file +# location / { +# # Passes traffic to the staging client on port 80 +# proxy_pass http://client-stage:80; +# } +# } \ No newline at end of file From 61521448073c8449ca023a4c7c0b78da2a69e8ac Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 17 Apr 2026 11:18:03 -0700 Subject: [PATCH 3/6] add staging, comment out for now --- docker/prod/server.Dockerfile | 2 + docker/staging/server.Dockerfile | 2 + docker/unified/docker-compose.yaml | 53 ++++++++++++++++++++++++ docker/unified/nginx/conf.d/staging.conf | 31 ++++++++++++++ 4 files changed, 88 insertions(+) create mode 100755 docker/unified/nginx/conf.d/staging.conf diff --git a/docker/prod/server.Dockerfile b/docker/prod/server.Dockerfile index 7341b1e9b..8be8200ee 100755 --- a/docker/prod/server.Dockerfile +++ b/docker/prod/server.Dockerfile @@ -17,6 +17,8 @@ COPY ./server ./ RUN npm run build +RUN cp -r src/templates dist/templates + EXPOSE 52345 CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/docker/staging/server.Dockerfile b/docker/staging/server.Dockerfile index 7341b1e9b..8be8200ee 100755 --- a/docker/staging/server.Dockerfile +++ b/docker/staging/server.Dockerfile @@ -17,6 +17,8 @@ COPY ./server ./ RUN npm run build +RUN cp -r src/templates dist/templates + EXPOSE 52345 CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/docker/unified/docker-compose.yaml b/docker/unified/docker-compose.yaml index 01fab5529..785007e3f 100755 --- a/docker/unified/docker-compose.yaml +++ b/docker/unified/docker-compose.yaml @@ -1,4 +1,5 @@ services: + #Gateway gateway: image: nginx:1.27.1-alpine container_name: checkmate-gateway @@ -9,6 +10,7 @@ services: volumes: - /etc/letsencrypt:/etc/nginx/ssl:ro - ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro + # Production ----- client-prod: image: ghcr.io/bluewave-labs/checkmate:frontend-demo restart: always @@ -47,3 +49,54 @@ services: start_period: 0s start_interval: 1s retries: 30 + + # Staging ----- + client-staging: + image: ghcr.io/bluewave-labs/checkmate:frontend-staging + restart: always + environment: + UPTIME_APP_API_BASE_URL: "https://staging.checkmate.so/api/v1" + UPTIME_APP_CLIENT_HOST: "https://staging.checkmate.so" + expose: + - "80" + depends_on: + - server-staging + volumes: + - ./nginx/conf.d/staging.conf:/etc/nginx/conf.d/default.conf:ro + server-staging: + image: ghcr.io/bluewave-labs/checkmate:backend-staging + restart: always + ports: + - "52345:52345" + env_file: + - server-staging.env + depends_on: + - mongodb-staging + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + mongodb-staging: + image: ghcr.io/bluewave-labs/checkmate:mongo-staging + restart: always + command: [ "mongod", "--quiet", "--bind_ip_all" ] + volumes: + - ./mongo/data-staging:/data/db + env_file: + - mongo-staging.env + healthcheck: + test: [ "CMD", "mongosh", "--eval", "db.adminCommand('ping')", "--quiet" ] + interval: 5s + timeout: 30s + start_period: 0s + start_interval: 1s + retries: 30 + capture: + image: ghcr.io/bluewave-labs/capture:latest + container_name: capture + restart: unless-stopped + ports: + - "59232:59232" + environment: + - API_SECRET=my_secret + - GIN_MODE=release + volumes: + - /etc/os-release:/etc/os-release:ro diff --git a/docker/unified/nginx/conf.d/staging.conf b/docker/unified/nginx/conf.d/staging.conf new file mode 100755 index 000000000..6b640a06b --- /dev/null +++ b/docker/unified/nginx/conf.d/staging.conf @@ -0,0 +1,31 @@ +server { + listen 80; + listen [::]:80; + + server_name _; + server_tokens off; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://server-staging:52345/api/; + proxy_http_version 1.1; + 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 /api-docs/ { + proxy_pass http://server-staging:52345/api-docs/; + proxy_http_version 1.1; + 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; + } +} \ No newline at end of file From 97f4008f4cc8ed3d70e94adc526e9d80d51c7417 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 17 Apr 2026 18:24:01 +0000 Subject: [PATCH 4/6] remove explicit ports --- docker/unified/docker-compose.yaml | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docker/unified/docker-compose.yaml b/docker/unified/docker-compose.yaml index 785007e3f..0bc1ecaa6 100755 --- a/docker/unified/docker-compose.yaml +++ b/docker/unified/docker-compose.yaml @@ -1,5 +1,5 @@ services: - #Gateway + # Gateway (Single Entry Point) gateway: image: nginx:1.27.1-alpine container_name: checkmate-gateway @@ -10,9 +10,11 @@ services: volumes: - /etc/letsencrypt:/etc/nginx/ssl:ro - ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro - # Production ----- + + # Production Stack ----- client-prod: image: ghcr.io/bluewave-labs/checkmate:frontend-demo + container_name: client-prod restart: always environment: UPTIME_APP_API_BASE_URL: "https://demo.checkmate.so/api/v1" @@ -23,19 +25,21 @@ services: - server-prod volumes: - ./nginx/conf.d/prod.conf:/etc/nginx/conf.d/default.conf:ro + server-prod: image: ghcr.io/bluewave-labs/checkmate:backend-demo + container_name: server-prod restart: always - ports: - - "52345:52345" env_file: - server-prod.env depends_on: - mongodb-prod volumes: - /var/run/docker.sock:/var/run/docker.sock:ro + mongodb-prod: image: ghcr.io/bluewave-labs/checkmate:mongo-demo + container_name: mongodb-prod restart: always command: [ "mongod", "--quiet", "--bind_ip_all" ] volumes: @@ -50,9 +54,10 @@ services: start_interval: 1s retries: 30 - # Staging ----- + # Staging Stack ----- client-staging: image: ghcr.io/bluewave-labs/checkmate:frontend-staging + container_name: client-staging restart: always environment: UPTIME_APP_API_BASE_URL: "https://staging.checkmate.so/api/v1" @@ -63,19 +68,21 @@ services: - server-staging volumes: - ./nginx/conf.d/staging.conf:/etc/nginx/conf.d/default.conf:ro + server-staging: image: ghcr.io/bluewave-labs/checkmate:backend-staging + container_name: server-staging restart: always - ports: - - "52345:52345" env_file: - server-staging.env depends_on: - mongodb-staging volumes: - /var/run/docker.sock:/var/run/docker.sock:ro + mongodb-staging: image: ghcr.io/bluewave-labs/checkmate:mongo-staging + container_name: mongodb-staging restart: always command: [ "mongod", "--quiet", "--bind_ip_all" ] volumes: @@ -89,6 +96,8 @@ services: start_period: 0s start_interval: 1s retries: 30 + + # Shared Utils capture: image: ghcr.io/bluewave-labs/capture:latest container_name: capture From 999dfb13b9aa2ca2e34b02580bf0ee103d44a812 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 17 Apr 2026 11:25:53 -0700 Subject: [PATCH 5/6] update workflows --- .github/workflows/production-deploy.yml | 5 +++-- .github/workflows/staging-deploy.yml | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml index 532197710..a42efc4a4 100644 --- a/.github/workflows/production-deploy.yml +++ b/.github/workflows/production-deploy.yml @@ -2,7 +2,7 @@ name: Demo deploy on: push: - branches: ["demo"] + branches: [ "demo" ] workflow_dispatch: jobs: docker-build-and-push-client: @@ -84,7 +84,8 @@ jobs: script: | cd checkmate git pull - cd docker/prod + cd docker/unified docker compose down docker compose pull docker compose up -d + docker system prune -af diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml index 84be4e483..e7983f249 100644 --- a/.github/workflows/staging-deploy.yml +++ b/.github/workflows/staging-deploy.yml @@ -2,7 +2,7 @@ name: Staging deploy on: push: - branches: ["develop"] + branches: [ "develop" ] jobs: docker-build-and-push-client: @@ -78,13 +78,13 @@ jobs: - name: SSH into server and restart container using Docker Compose uses: appleboy/ssh-action@v1.2.2 with: - host: ${{ secrets.STAGING_SERVER_HOST }} - username: ${{ secrets.STAGING_SERVER_USER }} - key: ${{ secrets.STAGING_SERVER_SSH_KEY }} + host: ${{ secrets.DEMO_SERVER_HOST }} + username: ${{ secrets.DEMO_SERVER_USER }} + key: ${{ secrets.DEMO_SERVER_SSH_KEY }} script: | cd checkmate git pull - cd docker/staging + cd docker/unified docker compose down docker compose pull docker compose up -d From 29ea54419c0e356d300d4e713d05fb379d2ff99b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 17 Apr 2026 19:20:31 +0000 Subject: [PATCH 6/6] add staging --- docker/unified/docker-compose.yaml | 3 ++ docker/unified/gateway/nginx.conf | 45 +++++++++++++++--------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/docker/unified/docker-compose.yaml b/docker/unified/docker-compose.yaml index 0bc1ecaa6..199d0da21 100755 --- a/docker/unified/docker-compose.yaml +++ b/docker/unified/docker-compose.yaml @@ -1,3 +1,6 @@ +# sudo certbot certonly --standalone --http-01-port 8080 +# cerbot needs to run on 8080 since port 80 is used by the gateway + services: # Gateway (Single Entry Point) gateway: diff --git a/docker/unified/gateway/nginx.conf b/docker/unified/gateway/nginx.conf index d0989ace1..47ad4695e 100644 --- a/docker/unified/gateway/nginx.conf +++ b/docker/unified/gateway/nginx.conf @@ -3,16 +3,23 @@ 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; -# --- PRODUCTION: demo.checkmate.so --- + server { listen 80; - server_name demo.checkmate.so; - + server_name demo.checkmate.so staging.checkmate.so; + + location /.well-known/acme-challenge/ { + # Forward the challenge to Certbot listening on 8080 + proxy_pass http://172.17.0.1:8080; + } + location / { return 301 https://$host$request_uri; } } + +# --- PRODUCTION: demo.checkmate.so --- server { listen 443 ssl; server_name demo.checkmate.so; @@ -30,27 +37,19 @@ server { } # --- STAGING: staging.checkmate.so --- -# server { -# listen 80; -# server_name staging.checkmate.so; - -# location / { -# return 301 https://$host$request_uri; -# } -# } -# server { -# listen 443 ssl; -# server_name staging.checkmate.so; + server { + listen 443 ssl; + server_name staging.checkmate.so; -# ssl_certificate /etc/nginx/ssl/live/staging.checkmate.so/fullchain.pem; -# ssl_certificate_key /etc/nginx/ssl/live/staging.checkmate.so/privkey.pem; + ssl_certificate /etc/nginx/ssl/live/staging.checkmate.so/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/live/staging.checkmate.so/privkey.pem; -# ssl_protocols TLSv1.2 TLSv1.3; -# ssl_ciphers HIGH:!aNULL:!MD5; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; -# location / { -# # Passes traffic to the staging client on port 80 -# proxy_pass http://client-stage:80; -# } -# } \ No newline at end of file + location / { + # Passes traffic to the staging client on port 80 + proxy_pass http://client-staging:80; + } + }