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 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/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..199d0da21 --- /dev/null +++ b/docker/unified/docker-compose.yaml @@ -0,0 +1,114 @@ +# 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: + 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 + + # 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" + 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 + container_name: server-prod + restart: always + 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: + - ./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 + + # 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" + 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 + container_name: server-staging + restart: always + 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: + - ./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 + + # Shared Utils + 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/gateway/nginx.conf b/docker/unified/gateway/nginx.conf new file mode 100644 index 000000000..47ad4695e --- /dev/null +++ b/docker/unified/gateway/nginx.conf @@ -0,0 +1,55 @@ +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 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; + + 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 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-staging:80; + } + } 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/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 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