Merge pull request #3776 from bluewave-labs/chore/simplify-deployment

chore: simplify deployment
This commit is contained in:
Alexander Holliday authored and GitHub committed 2026-07-13 09:57:13 -07:00
commit fe703199f5
98 files changed
+545 -2322

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
**/node_modules
**/dist
**/.env
**/*.env
.git
docker/dev/mongo/data
+103
View File
@@ -0,0 +1,103 @@
name: Build image
on:
push:
branches: ["develop", "master"]
tags: ["v*"]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# checkmate-backend-mono is a transitional alias so existing deployments
# keep receiving updates; drop it after one release cycle.
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository_owner }}/checkmate
ghcr.io/${{ github.repository_owner }}/checkmate-backend-mono
flavor: |
latest=false
tags: |
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
- name: Build and push multi-arch image
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# The hosted staging/prod instances share one host and one compose file; each
# deploy pulls and recreates only its own service.
deploy-staging:
needs: build-and-push
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- name: Deploy staging.checkmate.so
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.DEMO_SERVER_HOST }}
username: ${{ secrets.DEMO_SERVER_USER }}
key: ${{ secrets.DEMO_SERVER_SSH_KEY }}
script: |
cd checkmate
git pull
cd docs/hosting/checkmate-so
docker compose pull checkmate-staging
docker compose up -d checkmate-staging
docker system prune -af
deploy-prod:
needs: build-and-push
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- name: Deploy demo.checkmate.so
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.DEMO_SERVER_HOST }}
username: ${{ secrets.DEMO_SERVER_USER }}
key: ${{ secrets.DEMO_SERVER_SSH_KEY }}
script: |
cd checkmate
git pull
cd docs/hosting/checkmate-so
docker compose pull checkmate-demo
docker compose up -d checkmate-demo
docker system prune -af
@@ -1,148 +0,0 @@
name: Deploy images on release
on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
docker-build-and-push-client:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag
id: extract_tag
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-client:${{ steps.extract_tag.outputs.version }} \
-f ./docker/dist/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push Client Docker image
run: |
docker push ghcr.io/bluewave-labs/checkmate-client:${{ steps.extract_tag.outputs.version }}
docker-build-and-push-server:
needs: docker-build-and-push-client
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Extract version
id: extract_tag
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-backend:${{ steps.extract_tag.outputs.version }} \
-f ./docker/dist/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push Server Docker image
run: |
docker push ghcr.io/bluewave-labs/checkmate-backend:${{ steps.extract_tag.outputs.version }}
- name: Build Mongo Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-mongo:${{ steps.extract_tag.outputs.version }} \
-f ./docker/dist/mongoDB.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push MongoDB Docker image
run: |
docker push ghcr.io/bluewave-labs/checkmate-mongo:${{ steps.extract_tag.outputs.version }}
docker-build-and-push-server-mono-multiarch:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract version
id: extract_tag
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push multi-arch Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/dist-arm/server.Dockerfile
push: true
no-cache: true
tags: |
ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:${{ steps.extract_tag.outputs.version }}
platforms: linux/amd64,linux/arm64
labels: |
org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate
build-args: |
VITE_APP_VERSION=${{ steps.extract_tag.outputs.version }}
docker-build-and-push-server-mono:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version
id: extract_tag
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-backend-mono:${{ steps.extract_tag.outputs.version }} \
-f ./docker/dist-mono/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
--build-arg VITE_APP_VERSION=${{ steps.extract_tag.outputs.version }} \
.
- name: Push Server Docker image
run: docker push ghcr.io/bluewave-labs/checkmate-backend-mono:${{ steps.extract_tag.outputs.version }}
-143
View File
@@ -1,143 +0,0 @@
name: Deploy images
on:
push:
branches: ["master"]
workflow_dispatch:
jobs:
docker-build-and-push-client:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get version
id: vars
run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-client:latest \
-f ./docker/dist/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
--build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Client Docker image
run: |
docker push ghcr.io/bluewave-labs/checkmate-client:latest
docker-build-and-push-server:
needs: docker-build-and-push-client
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-backend:latest \
-f ./docker/dist/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push Server Docker image
run: |
docker push ghcr.io/bluewave-labs/checkmate-backend:latest
- name: Build Mongo Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-mongo:latest \
-f ./docker/dist/mongoDB.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push MongoDB Docker image
run: |
docker push ghcr.io/bluewave-labs/checkmate-mongo:latest
docker-build-and-push-server-mono-multiarch:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get version
id: vars
run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build and push multi-arch Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/dist-arm/server.Dockerfile
push: true
no-cache: true
tags: |
ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:latest
platforms: linux/amd64,linux/arm64
labels: |
org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate
build-args: |
VITE_APP_VERSION=${{ env.VERSION }}
docker-build-and-push-server-mono:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get version
id: vars
run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-backend-mono:latest \
-f ./docker/dist-mono/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
--build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Server Docker image
run: docker push ghcr.io/bluewave-labs/checkmate-backend-mono:latest
-91
View File
@@ -1,91 +0,0 @@
name: Demo deploy
on:
push:
branches: [ "demo" ]
workflow_dispatch:
jobs:
docker-build-and-push-client:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get version
id: vars
run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:frontend-demo \
-f ./docker/prod/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
--build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Client Docker image
run: docker push ghcr.io/bluewave-labs/checkmate:frontend-demo
docker-build-and-push-server:
needs: docker-build-and-push-client
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:backend-demo \
-f ./docker/prod/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push Server Docker image
run: docker push ghcr.io/bluewave-labs/checkmate:backend-demo
- name: Build Mongo Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:mongo-demo \
-f ./docker/prod/mongoDB.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push MongoDB Docker image
run: docker push ghcr.io/bluewave-labs/checkmate:mongo-demo
deploy-to-demo:
needs: docker-build-and-push-server
runs-on: ubuntu-latest
steps:
- name: SSH into server and restart container using Docker Compose
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.DEMO_SERVER_HOST }}
username: ${{ secrets.DEMO_SERVER_USER }}
key: ${{ secrets.DEMO_SERVER_SSH_KEY }}
script: |
cd checkmate
git pull
cd docker/unified
docker compose down
docker compose pull
docker compose up -d
docker system prune -af
-91
View File
@@ -1,91 +0,0 @@
name: Staging deploy
on:
push:
branches: [ "develop" ]
jobs:
docker-build-and-push-client:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get version
id: vars
run: echo "VERSION=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: Build Client Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:frontend-staging \
-f ./docker/staging/client.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
--build-arg VITE_APP_VERSION=${{ env.VERSION }} \
.
- name: Push Client Docker image
run: docker push ghcr.io/bluewave-labs/checkmate:frontend-staging
docker-build-and-push-server:
needs: docker-build-and-push-client
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:backend-staging \
-f ./docker/staging/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push Server Docker image
run: docker push ghcr.io/bluewave-labs/checkmate:backend-staging
- name: Build Mongo Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate:mongo-staging \
-f ./docker/staging/mongoDB.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \
.
- name: Push MongoDB Docker image
run: docker push ghcr.io/bluewave-labs/checkmate:mongo-staging
deploy-to-staging:
needs: docker-build-and-push-server
runs-on: ubuntu-latest
steps:
- name: SSH into server and restart container using Docker Compose
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.DEMO_SERVER_HOST }}
username: ${{ secrets.DEMO_SERVER_USER }}
key: ${{ secrets.DEMO_SERVER_SSH_KEY }}
script: |
cd checkmate
git pull
cd docker/unified
docker compose down
docker compose pull
docker compose up -d
docker system prune -af
+3 -3
View File
@@ -35,9 +35,9 @@ npm run format # Prettier formatting
### Docker Development
```bash
cd docker/dev
./build_images.sh
docker run -d -p 27017:27017 -v uptime_mongo_data:/data/db --name uptime_database_mongo mongo:6.0
docker build -f docker/Dockerfile -t checkmate . # build the mono image (server + built client)
docker compose -f docker/dev/docker-compose.yaml up # local full stack (builds image, runs mongo + worker)
docker run -d -p 27017:27017 -v uptime_mongo_data:/data/db --name uptime_database_mongo mongo:8.0 # just a dev database
```
## Environment Setup
+1 -25
View File
@@ -88,34 +88,10 @@ cd Checkmate
#### Step 2: Set Up Docker Containers (MongoDB)
Navigate to the Docker dev directory:
```bash
cd docker/dev
```
Build the Docker images:
Linux:
```bash
./build_images.sh
```
Windows:
```bash
./build_images.bat
```
Run MongoDB container:
```bash
docker run -d -p 27017:27017 -v uptime_mongo_data:/data/db --name uptime_database_mongo mongo:6.0
```
Navigate back to the root directory:
```bash
cd ../..
docker run -d -p 27017:27017 -v uptime_mongo_data:/data/db --name uptime_database_mongo mongo:8.0
```
#### Step 3: Set Up the Backend (Server)
+31 -1
View File
@@ -80,7 +80,37 @@ Usage instructions can be found [here](https://checkmate.so/docs).
<a id="installation"></a>
## Installation
See installation instructions in [Checkmate documentation portal](https://checkmate.so/docs).
The quickest way to run Checkmate is the reference Docker Compose file, which runs the all-in-one image (`ghcr.io/bluewave-labs/checkmate`) plus MongoDB:
```bash
curl -O https://raw.githubusercontent.com/bluewave-labs/checkmate/master/docker/docker-compose.yaml
JWT_SECRET="$(openssl rand -hex 32)" docker compose up -d
```
Then open http://localhost:52345. If the app is reached at another origin (domain or LAN IP), set `CLIENT_HOST` accordingly. To build the image yourself, run `docker build -f docker/Dockerfile -t checkmate .` from a checkout. For TLS, put any reverse proxy (Caddy, Traefik, nginx) in front of port 52345.
### Configuration
The image is configured entirely through environment variables on the server container:
| Variable | Required | Description |
|---|---|---|
| `DB_CONNECTION_STRING` | Yes | MongoDB connection string, e.g. `mongodb://mongodb:27017/uptime_db` |
| `JWT_SECRET` | Yes | Secret used to sign auth tokens; generate one with `openssl rand -hex 32` |
| `CLIENT_HOST` | Yes | The URL users reach the app at, e.g. `https://checkmate.example.com`; used for CORS and for links in notifications and emails |
| `LOG_LEVEL` | No | Server log level: `error`, `warn`, `info`, or `debug` (default `debug`) |
The web client needs no configuration by default: it calls the API on the same origin it was served from (`/api/v1`). For setups where the defaults don't apply — for example, the API is reached through a different origin than the page — the server renders overrides into the client at runtime via these optional variables:
| Variable | Description |
|---|---|
| `CLIENT_CONFIG_API_BASE_URL` | Full base URL the client calls the API at, e.g. `https://api.example.com/api/v1`; defaults to same-origin `/api/v1` |
| `CLIENT_CONFIG_CLIENT_HOST` | Origin used when the client builds absolute links (invites, status pages); defaults to the browser's current origin |
| `CLIENT_CONFIG_LOG_LEVEL` | Browser console log level: `error`, `warn`, `info`, or `debug` (default `error`) |
> **Upgrading from an older image?** The `UPTIME_APP_*` variables (`UPTIME_APP_API_BASE_URL`, `UPTIME_APP_CLIENT_HOST`, `UPTIME_APP_LOG_LEVEL`) are no longer read. In most setups no replacement is needed — the same-origin defaults cover them; if you pointed the client at a different origin, use the `CLIENT_CONFIG_*` equivalents above. The `checkmate-client`, `checkmate-backend`, `checkmate-mongo`, and `checkmate-backend-mono-multiarch` images are no longer updated — switch to `ghcr.io/bluewave-labs/checkmate`, keeping your existing MongoDB service and data volume.
See full installation instructions in the [Checkmate documentation portal](https://checkmate.so/docs).
Alternatively, you can also use [Coolify](https://coolify.io/), [Elestio](https://elest.io/open-source/checkmate), [K8s](./charts/helm/checkmate/INSTALLATION.md), [Sive Host](https://sive.host) (South Africa), [Cloudzy](https://cloudzy.com/marketplace/checkmate) or [Pikapods](https://www.pikapods.com/) to quickly spin off a Checkmate instance. If you would like to monitor your server infrastructure, you'll need [Capture agent](https://github.com/bluewave-labs/capture). Capture repository also contains the installation instructions.
+4
View File
@@ -3,4 +3,8 @@ name: checkmate-chart
description: A Helm chart for Checkmate App
type: application
version: 0.2.0
# DO NOT bump appVersion past v3.8.1 until this chart is migrated to the all-in-one
# image (ghcr.io/bluewave-labs/checkmate). The checkmate-client / checkmate-backend /
# checkmate-mongo images this chart references are frozen at v3.8.1 — later versions
# are never published, so a bumped chart will fail to pull.
appVersion: "v3.8.1" # "v" prefix: published image tags are v-prefixed (ghcr.io/.../checkmate-*:v3.8.1)
+6 -4
View File
@@ -1,4 +1,6 @@
VITE_APP_API_BASE_URL=UPTIME_APP_API_BASE_URL
VITE_APP_API_V2_BASE_URL=UPTIME_APP_API_V2_BASE_URL
VITE_APP_CLIENT_HOST=UPTIME_APP_CLIENT_HOST
VITE_APP_LOG_LEVEL=UPTIME_APP_LOG_LEVEL
# Production builds use same-origin defaults: API at /api/v1, client host from
# window.location.origin. The empty values below override any local .env so a
# production build never bakes in a developer's localhost URLs.
VITE_APP_API_BASE_URL=
VITE_APP_CLIENT_HOST=
VITE_APP_LOG_LEVEL=
-1
View File
@@ -28,5 +28,4 @@ dist-ssr
# Scripts
*.sh
!env.sh
.env.development
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
for i in $(env | grep UPTIME_APP_)
do
key=$(echo $i | cut -d '=' -f 1)
value=$(echo $i | cut -d '=' -f 2-)
echo $key=$value
find /usr/share/nginx/html -type f \( -name '*.js' -o -name '*.css' \) -exec sed -i "s|${key}|${value}|g" '{}' +
done
+1
View File
@@ -12,6 +12,7 @@
/>
<title>Checkmate</title>
<script src="/config.js"></script>
</head>
<body>
+2 -22
View File
@@ -92,7 +92,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7",
@@ -408,7 +407,6 @@
"node_modules/@emotion/react": {
"version": "11.14.0",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -446,7 +444,6 @@
"node_modules/@emotion/styled": {
"version": "11.14.1",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -1226,7 +1223,6 @@
"node_modules/@mui/material": {
"version": "7.3.7",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/core-downloads-tracker": "^7.3.7",
@@ -1331,7 +1327,6 @@
"node_modules/@mui/system": {
"version": "7.3.7",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/private-theming": "^7.3.7",
@@ -2376,7 +2371,6 @@
"version": "24.5.2",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.12.0"
}
@@ -2392,7 +2386,6 @@
"node_modules/@types/react": {
"version": "18.3.27",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2"
@@ -2483,7 +2476,6 @@
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/types": "7.18.0",
@@ -2764,7 +2756,6 @@
"version": "8.15.0",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3121,7 +3112,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.42",
"caniuse-lite": "^1.0.30001800",
@@ -3565,8 +3555,7 @@
},
"node_modules/dayjs": {
"version": "1.11.13",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
@@ -3965,7 +3954,6 @@
"version": "8.57.1",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -4778,7 +4766,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.27.6"
},
@@ -5590,7 +5577,6 @@
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.19.0.tgz",
"integrity": "sha512-REhYUN8gNP3HlcIZS6QU2uy8iovl31cXsrNDkCcqWSQbCkcpdYLczqDz5PVIwNH42UQNyvukjes/RoHPDrOUmQ==",
"license": "BSD-3-Clause",
"peer": true,
"dependencies": {
"@mapbox/geojson-rewind": "^0.5.2",
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
@@ -6372,7 +6358,6 @@
"node_modules/react-dom": {
"version": "18.3.1",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -6384,7 +6369,6 @@
"node_modules/react-hook-form": {
"version": "7.71.1",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18.0.0"
},
@@ -6588,8 +6572,7 @@
},
"node_modules/redux": {
"version": "5.0.1",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/redux-persist": {
"version": "6.0.0",
@@ -6739,7 +6722,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz",
"integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "1.0.9"
},
@@ -7581,7 +7563,6 @@
"version": "5.9.3",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7719,7 +7700,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
"integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
+4
View File
@@ -0,0 +1,4 @@
// Fallback so /config.js always resolves (e.g. under the Vite dev server). In
// the Docker image the server shadows this path and renders the real config
// from its CLIENT_CONFIG_* environment variables.
window.__CHECKMATE_CONFIG__ = {};
@@ -10,8 +10,9 @@ import { useInviteForm } from "@/Hooks/useInviteForm";
import type { InviteFormData } from "@/Validation/invite";
import { usePost } from "@/Hooks/UseApi";
import { LAYOUT } from "@/Utils/Theme/constants";
import { runtimeConfig } from "@/Utils/runtimeConfig";
const CLIENT_HOST = import.meta.env.VITE_APP_CLIENT_HOST;
const CLIENT_HOST = runtimeConfig.clientHost || import.meta.env.VITE_APP_CLIENT_HOST;
interface InviteResponse {
token: string;
@@ -56,7 +57,7 @@ export const InviteTeamMemberDialog = ({
const result = await generateToken("/invite", data);
if (result?.data?.token) {
const token = result.data.token;
const link = CLIENT_HOST ? `${CLIENT_HOST}/register/${token}` : token;
const link = `${CLIENT_HOST || window.location.origin}/register/${token}`;
setInviteLink(link);
}
};
+2 -1
View File
@@ -3,7 +3,8 @@
declare const __APP_VERSION__: string;
interface ImportMetaEnv {
readonly VITE_APP_API_V2_BASE_URL?: string;
readonly VITE_APP_API_BASE_URL?: string;
readonly VITE_APP_CLIENT_HOST?: string;
readonly VITE_APP_LOG_LEVEL?: "debug" | "info" | "warn" | "error";
}
+3 -1
View File
@@ -1,8 +1,10 @@
import axios from "axios";
import type { AxiosError } from "axios";
import type { AxiosRequestConfig, AxiosResponse } from "axios";
import { runtimeConfig } from "@/Utils/runtimeConfig";
const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL;
const BASE_URL =
runtimeConfig.apiBaseUrl || import.meta.env.VITE_APP_API_BASE_URL || "/api/v1";
const api = axios.create({
baseURL: BASE_URL,
+3 -1
View File
@@ -1,4 +1,5 @@
import type { LogLevel } from "@/Types/Log";
import { runtimeConfig } from "@/Utils/runtimeConfig";
interface LogContext {
[key: string]: any;
@@ -25,7 +26,8 @@ interface ErrorLogData {
userAgent: string;
}
const configuredLevel: LogLevel = import.meta.env.VITE_APP_LOG_LEVEL || "error";
const configuredLevel: LogLevel =
runtimeConfig.logLevel || import.meta.env.VITE_APP_LOG_LEVEL || "error";
const configuredPriority = LOG_LEVEL_PRIORITY[configuredLevel];
const shouldLog = (level: LogLevel): boolean => {
+18
View File
@@ -0,0 +1,18 @@
import type { LogLevel } from "@/Types/Log";
// Served by GET /config.js (rendered from server env) or a static config.js
// next to index.html; loaded before the bundle in index.html.
export interface RuntimeConfig {
apiBaseUrl?: string;
clientHost?: string;
logLevel?: LogLevel;
}
declare global {
interface Window {
__CHECKMATE_CONFIG__?: RuntimeConfig;
}
}
export const runtimeConfig: RuntimeConfig =
(typeof window !== "undefined" && window.__CHECKMATE_CONFIG__) || {};
+4 -1
View File
@@ -1,6 +1,9 @@
import { PUBLIC_STATUS_PAGE_PREFIX, type StatusPage } from "@/Types/StatusPage";
import { runtimeConfig } from "@/Utils/runtimeConfig";
const CLIENT_HOST = import.meta.env.VITE_APP_CLIENT_HOST as string | undefined;
const CLIENT_HOST =
runtimeConfig.clientHost ||
(import.meta.env.VITE_APP_CLIENT_HOST as string | undefined);
const getClientOriginProtocol = (): string => {
const source =
@@ -4,7 +4,7 @@
# Build on the host arch (BUILDPLATFORM) rather than under QEMU — the output is
# pure JS so it's arch-independent, and this avoids the esbuild host/native
# binary version mismatch under emulation.
FROM --platform=$BUILDPLATFORM node:20-slim AS frontend-build
FROM --platform=$BUILDPLATFORM node:22-slim AS frontend-build
WORKDIR /app/client
@@ -19,7 +19,7 @@ RUN npm run build
# ---------------------
# Backend stage
# ---------------------
FROM node:22-slim AS backend
FROM node:22-slim AS app
# Install ping
RUN apt-get update \
@@ -28,23 +28,18 @@ RUN apt-get update \
WORKDIR /app/server
COPY server/package.json ./
COPY server/package*.json ./
RUN npm install
RUN npm ci
COPY server ./
RUN chmod +x ./scripts/inject-vars.sh
RUN npm run build
COPY --from=frontend-build /app/client/dist ./public
RUN chown -R node:node ./public \
&& chown -R node:node ./dist \
&& chown -R node:node ./scripts
USER node
EXPOSE 52345 52346
EXPOSE 52345
CMD ["sh", "-c", "./scripts/inject-vars.sh && node ./dist/index.js"]
CMD ["node", "dist/index.js"]
-33
View File
@@ -1,33 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=bluewaveuptime/uptime_client
set dockerfiles[0]=.\docker\coolify\client.Dockerfile
set services[1]=bluewaveuptime/uptime_database_mongo
set dockerfiles[1]=.\docker\coolify\mongoDB.Dockerfile
set services[2]=bluewaveuptime/uptime_server
set dockerfiles[2]=.\docker\coolify\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1,2) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-24
View File
@@ -1,24 +0,0 @@
#!/bin/bash
# Change directory to root Server directory for correct Docker Context
cd "$(dirname "$0")"
cd ../../
# Define an array of services and their Dockerfiles
declare -A services=(
["bluewaveuptime/uptime_client"]="./docker/coolify/client.Dockerfile"
["bluewaveuptime/uptime_database_mongo"]="./docker/coolify/mongoDB.Dockerfile"
["bluewaveuptime/uptime_server"]="./docker/coolify/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"
-22
View File
@@ -1,22 +0,0 @@
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 ./server/docker/dist/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
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;"]
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-35
View File
@@ -1,35 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name checkmate-demo.bluewavelabs.ca;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://server:5000/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:5000/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;
}
}
-20
View File
@@ -1,20 +0,0 @@
FROM node:22-slim
# Install ping
RUN apt-get update \
&& apt-get install -y iputils-ping \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY ../../package*.json ./
RUN npm install
COPY ../../ ./
RUN npm run build
EXPOSE 5000
CMD ["node", "dist/index.js"]
-33
View File
@@ -1,33 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=uptime_client
set dockerfiles[0]=.\docker\dev\client.Dockerfile
set services[1]=uptime_mongo
set dockerfiles[1]=.\docker\dev\mongoDB.Dockerfile
set services[2]=uptime_server
set dockerfiles[2]=.\docker\dev\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1,2) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-29
View File
@@ -1,29 +0,0 @@
#!/bin/bash
# Change directory to root Server directory for correct Docker Context
cd "$(dirname "$0")"
cd ../..
# Define service names and their corresponding Dockerfiles in parallel arrays
services=("uptime_client" "uptime_mongo" "uptime_server")
dockerfiles=(
"./docker/dev/client.Dockerfile"
"./docker/dev/mongoDB.Dockerfile"
"./docker/dev/server.Dockerfile"
)
# Loop through each service and build the corresponding image
for i in "${!services[@]}"; do
service="${services[$i]}"
dockerfile="${dockerfiles[$i]}"
docker build -f "$dockerfile" -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"
-20
View File
@@ -1,20 +0,0 @@
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;"]
@@ -2,28 +2,13 @@
# Example Docker Compose configuration for custom CA trust
# This file demonstrates how to configure Checkmate to trust custom CAs
#
# Usage: docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up
# Usage: docker compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up
services:
server:
image: uptime_server:latest
restart: always
ports:
- "52345:52345"
env_file:
- server.env
checkmate:
environment:
# Mount your custom CA certificate
NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem
volumes:
# Mount the certs directory (read-only for security)
- ./certs:/certs:ro
depends_on:
- mongodb
# Optional: Add healthcheck to ensure the server starts properly
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:52345/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
+12 -18
View File
@@ -1,27 +1,20 @@
services:
client:
image: uptime_client:latest
restart: always
ports:
- "80:80"
environment:
UPTIME_APP_API_BASE_URL: "http://localhost:52345/api/v1"
UPTIME_APP_CLIENT_HOST: "http://localhost"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d/
depends_on:
- server
server:
image: uptime_server:latest
checkmate:
build:
context: ../..
dockerfile: docker/Dockerfile
restart: always
ports:
- "52345:52345"
env_file:
- server.env
depends_on:
- mongodb
mongodb:
condition: service_healthy
worker:
image: uptime_server:latest
build:
context: ../..
dockerfile: docker/Dockerfile
restart: always
ports:
- "52346:52346"
@@ -43,9 +36,10 @@ services:
timeout: 3s
retries: 3
depends_on:
- mongodb
mongodb:
image: uptime_mongo:latest
condition: service_healthy
mongodb:
image: mongo:8.0
restart: always
ports:
- "27017:27017"
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-35
View File
@@ -1,35 +0,0 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost; # Set server name to localhost
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: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;
# proxy_set_header Connection '';
# chunked_transfer_encoding off;
# proxy_buffering off;
# proxy_cache off;
# }
# location /api-docs/ {
# proxy_pass http://server: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;
# }
}
-20
View File
@@ -1,20 +0,0 @@
FROM node:22-slim
# Install ping
RUN apt-get update \
&& apt-get install -y iputils-ping \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY ./server/package*.json ./
RUN npm install
COPY ./server/ ./
RUN npm run build
EXPOSE 52345
CMD ["node", "dist/index.js"]
-44
View File
@@ -1,44 +0,0 @@
#!/bin/bash
set -e # Exit on error
# Change directory to root Server directory for correct Docker Context
cd "$(dirname "$0")"
cd ../..
# Ensure buildx builder exists and is used
if ! docker buildx inspect mybuilder &>/dev/null; then
docker buildx create --name mybuilder --use
else
docker buildx use mybuilder
fi
# Define service names and Dockerfiles
services=("mono_server_arm")
dockerfiles=(
"./docker/dist-arm/server.Dockerfile"
)
# Static image name for GitHub Container Registry (GHCR)
image="ghcr.io/bluewave-labs/checkmate:backend-dist-multi-arch"
platforms="linux/amd64,linux/arm64"
repo_url="https://github.com/bluewave-labs/checkmate"
# Loop through each service and build
for i in "${!services[@]}"; do
service="${services[$i]}"
dockerfile="${dockerfiles[$i]}"
echo "🚀 Building multi-arch image for $service..."
docker buildx build \
--platform "$platforms" \
-f "$dockerfile" \
-t "$image" \
--label "org.opencontainers.image.source=$repo_url" \
--push \
.
echo "✅ $image pushed for platforms: $platforms"
done
echo "🎉 All multi-arch images built and pushed successfully"
-28
View File
@@ -1,28 +0,0 @@
services:
server:
image: ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:latest
restart: always
pull_policy: always
ports:
- "52345:52345"
environment:
- UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1
- UPTIME_APP_CLIENT_HOST=http://localhost
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
- CLIENT_HOST=http://localhost
- JWT_SECRET=my_secret
depends_on:
- mongodb
mongodb:
image: mongo:6.0
restart: always
command: ["mongod", "--quiet", "--bind_ip_all"]
volumes:
- ./mongo/data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.runCommand({ ping: 1 })", "--quiet"]
interval: 5s
timeout: 30s
start_period: 0s
start_interval: 1s
retries: 30
-30
View File
@@ -1,30 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=uptime_database_mongo
set dockerfiles[0]=.\docker\dist-mono\mongoDB.Dockerfile
set services[1]=uptime_server
set dockerfiles[1]=.\docker\dist-mono\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-28
View File
@@ -1,28 +0,0 @@
#!/bin/bash
# Change directory to root Server directory for correct Docker Context
cd "$(dirname "$0")"
cd ../..
# Define service names and their corresponding Dockerfiles in parallel arrays
services=("mono_mongo" "mono_server")
dockerfiles=(
"./docker/dist-mono/mongoDB.Dockerfile"
"./docker/dist-mono/server.Dockerfile"
)
# Loop through each service and build the corresponding image
for i in "${!services[@]}"; do
service="${services[$i]}"
dockerfile="${dockerfiles[$i]}"
docker build -f "$dockerfile" -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"
@@ -1,27 +0,0 @@
services:
server:
image: mono_server
restart: always
ports:
- "52345:52345"
environment:
- UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1
- UPTIME_APP_CLIENT_HOST=http://localhost
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
- CLIENT_HOST=http://localhost
- JWT_SECRET=my_secret
depends_on:
- mongodb
mongodb:
image: mono_mongo
restart: always
command: ["mongod", "--quiet", "--bind_ip_all"]
volumes:
- ./mongo/data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')", "--quiet"]
interval: 5s
timeout: 30s
start_period: 0s
start_interval: 1s
retries: 30
-28
View File
@@ -1,28 +0,0 @@
services:
server:
image: ghcr.io/bluewave-labs/checkmate-backend-mono:latest
pull_policy: always
restart: always
ports:
- "52345:52345"
environment:
- UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1
- UPTIME_APP_CLIENT_HOST=http://localhost
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
- CLIENT_HOST=http://localhost
- JWT_SECRET=my_secret
depends_on:
- mongodb
mongodb:
image: ghcr.io/bluewave-labs/checkmate-mongo:latest
restart: always
command: ["mongod", "--quiet", "--bind_ip_all"]
volumes:
- ./mongo/data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')", "--quiet"]
interval: 5s
timeout: 30s
start_period: 0s
start_interval: 1s
retries: 30
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-37
View File
@@ -1,37 +0,0 @@
FROM node:22-slim AS frontend-build
WORKDIR /app/client
COPY client/package*.json ./
RUN npm install
COPY client ./
RUN npm run build
FROM node:22-slim AS app
# Install ping
RUN apt-get update \
&& apt-get install -y iputils-ping \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app/server
COPY server ./
RUN npm install
RUN npm run build
RUN cp -r src/templates dist/templates
COPY --from=frontend-build /app/client/dist ./public
RUN chmod +x ./scripts/inject-vars.sh \
&& chown -R node:node ./public \
&& chown -R node:node ./dist \
&& chown -R node:node ./scripts
EXPOSE 52345
CMD ["sh", "-c", "./scripts/inject-vars.sh && node ./dist/index.js"]
-33
View File
@@ -1,33 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=bluewaveuptime/uptime_client
set dockerfiles[0]=.\docker\dist\client.Dockerfile
set services[1]=bluewaveuptime/uptime_database_mongo
set dockerfiles[1]=.\docker\dist\mongoDB.Dockerfile
set services[2]=bluewaveuptime/uptime_server
set dockerfiles[2]=.\docker\dist\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1,2) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-25
View File
@@ -1,25 +0,0 @@
#!/bin/bash
# Change directory to root Server directory for correct Docker Context
cd "$(dirname "$0")"
cd ../../
# Define an array of services and their Dockerfiles
declare -A services=(
["bluewaveuptime/uptime_client"]="./docker/dist/client.Dockerfile"
["bluewaveuptime/uptime_database_mongo"]="./docker/dist/mongoDB.Dockerfile"
["bluewaveuptime/uptime_server"]="./docker/dist/server.Dockerfile"
)
for service in "${!services[@]}"; do
docker build \
-f "${services[$service]}" \
-t "$service" \
.
if [ $? -ne 0 ]; then
echo "Error building $service image. Exiting..."
exit 1
fi
done
echo "All images built successfully"
-22
View File
@@ -1,22 +0,0 @@
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 ./docker/dist/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
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;"]
-38
View File
@@ -1,38 +0,0 @@
services:
client:
image: ghcr.io/bluewave-labs/checkmate-client:latest
restart: always
environment:
UPTIME_APP_API_BASE_URL: "http://localhost:52345/api/v1"
UPTIME_APP_CLIENT_HOST: "http://localhost"
ports:
- "80:80"
- "443:443"
depends_on:
- server
server:
image: ghcr.io/bluewave-labs/checkmate-backend:latest
restart: always
ports:
- "52345:52345"
depends_on:
- mongodb
environment:
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
- CLIENT_HOST=http://localhost
- JWT_SECRET=my_secret
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock:ro
mongodb:
image: ghcr.io/bluewave-labs/checkmate-mongo:latest
restart: always
volumes:
- ./mongo/data:/data/db
command: ["mongod", "--quiet", "--bind_ip_all"]
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')", "--quiet"]
interval: 5s
timeout: 30s
start_period: 0s
start_interval: 1s
retries: 30
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-35
View File
@@ -1,35 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name checkmate-demo.bluewavelabs.ca;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
# location /api/ {
# proxy_pass http://server:5000/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:5000/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;
}
}
-20
View File
@@ -1,20 +0,0 @@
FROM node:22-slim
# Install ping
RUN apt-get update \
&& apt-get install -y iputils-ping \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY ./server/package*.json ./
RUN npm install
COPY ./server/ ./
RUN npm run build
EXPOSE 52345
CMD ["node", "dist/index.js"]
+45
View File
@@ -0,0 +1,45 @@
services:
checkmate:
image: ghcr.io/bluewave-labs/checkmate:latest
pull_policy: always
restart: always
ports:
- "52345:52345"
environment:
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
- CLIENT_HOST=${CLIENT_HOST:-http://localhost:52345}
- JWT_SECRET=${JWT_SECRET:?set JWT_SECRET in your environment}
stop_grace_period: 60s
healthcheck:
test:
[
"CMD",
"node",
"-e",
"require('http').get('http://localhost:52346/livez',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))",
]
interval: 15s
timeout: 3s
start_period: 60s
start_interval: 2s
retries: 3
depends_on:
mongodb:
condition: service_healthy
mongodb:
image: mongo:8.0
restart: always
command: ["mongod", "--quiet", "--bind_ip_all"]
volumes:
- mongo-data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')", "--quiet"]
interval: 5s
timeout: 30s
start_period: 0s
start_interval: 1s
retries: 30
volumes:
mongo-data:
-33
View File
@@ -1,33 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=uptime_client
set dockerfiles[0]=.\docker\prod\client.Dockerfile
set services[1]=uptime_database_mongo
set dockerfiles[1]=.\docker\prod\mongoDB.Dockerfile
set services[2]=uptime_server
set dockerfiles[2]=.\docker\prod\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1,2) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-25
View File
@@ -1,25 +0,0 @@
#!/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"
-20
View File
@@ -1,20 +0,0 @@
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;"]
-53
View File
@@ -1,53 +0,0 @@
services:
client:
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"
ports:
- "80:80"
- "443:443"
depends_on:
- server
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d/:ro
- /etc/letsencrypt:/etc/nginx/ssl:ro
server:
image: ghcr.io/bluewave-labs/checkmate:backend-demo
restart: always
ports:
- "52345:52345"
env_file:
- server.env
depends_on:
- mongodb
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
mongodb:
image: ghcr.io/bluewave-labs/checkmate:mongo-demo
restart: always
command: ["mongod", "--quiet", "--bind_ip_all"]
volumes:
- ./mongo/data:/data/db
env_file:
- mongo.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
-41
View File
@@ -1,41 +0,0 @@
function initiateReplicaSet() {
try {
rs.initiate({
_id: "rs0",
members: [{ _id: 0, host: "localhost:27017" }],
});
} catch (e) {
print("Replica set already initiated or error occurred: " + e);
}
}
function waitForPrimary() {
while (true) {
const isMaster = db.isMaster();
if (isMaster.ismaster) {
print("This node is now PRIMARY.");
break;
}
print("Waiting to become PRIMARY...");
sleep(2000);
}
}
function createUser() {
db = db.getSiblingDB("uptime_db");
var username = process.env.USERNAME_ENV_VAR;
var password = process.env.PASSWORD_ENV_VAR;
db.createUser({
user: username,
pwd: password,
roles: [{ role: "readWrite", db: "uptime_db" }],
});
print("User '" + username + "' created successfully");
}
initiateReplicaSet();
waitForPrimary();
createUser();
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-15
View File
@@ -1,15 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name checkmate-demo.bluewavelabs.ca www.checkmate-demo.bluewavelabs.ca;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://[domain-name]$request_uri;
}
}
-69
View File
@@ -1,69 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name checkmate-demo.bluewavelabs.ca;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://server: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: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;
}
}
server {
listen 443 default_server ssl http2;
listen [::]:443 ssl http2;
server_name checkmate-demo.bluewavelabs.ca;
ssl_certificate /etc/nginx/ssl/live/demo.checkmate.so/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/demo.checkmate.so/privkey.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://server: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: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;
}
}
-24
View File
@@ -1,24 +0,0 @@
FROM node:22-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
RUN cp -r src/templates dist/templates
EXPOSE 52345
CMD ["node", "dist/index.js"]
-33
View File
@@ -1,33 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=uptime_client
set dockerfiles[0]=.\docker\staging\client.Dockerfile
set services[1]=uptime_database_mongo
set dockerfiles[1]=.\docker\staging\mongoDB.Dockerfile
set services[2]=uptime_server
set dockerfiles[2]=.\docker\staging\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1,2) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-25
View File
@@ -1,25 +0,0 @@
#!/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/staging/client.Dockerfile"
["uptime_database_mongo"]="./docker/staging/mongoDB.Dockerfile"
["uptime_server"]="./docker/staging/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"
-19
View File
@@ -1,19 +0,0 @@
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
-20
View File
@@ -1,20 +0,0 @@
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;"]
-62
View File
@@ -1,62 +0,0 @@
services:
client:
image: ghcr.io/bluewave-labs/checkmate:frontend-staging
restart: always
environment:
UPTIME_APP_API_BASE_URL: "https://checkmate-test.bluewavelabs.ca/api/v1"
UPTIME_APP_CLIENT_HOST: "https://checkmate-test.bluewavelabs.ca"
ports:
- "80:80"
- "443:443"
depends_on:
- server
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d/:ro
- ./certbot/www:/var/www/certbot/:ro
- ./certbot/conf/:/etc/nginx/ssl/:ro
certbot:
image: certbot/certbot:latest
restart: always
volumes:
- ./certbot/www/:/var/www/certbot/:rw
- ./certbot/conf/:/etc/letsencrypt/:rw
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'"
server:
image: ghcr.io/bluewave-labs/checkmate:backend-staging
restart: always
ports:
- "52345:52345"
env_file:
- server.env
depends_on:
- mongodb
mongodb:
image: ghcr.io/bluewave-labs/checkmate:mongo-staging
restart: always
command: ["mongod", "--quiet", "--bind_ip_all"]
ports:
- "27017:27017"
volumes:
- ./mongo/data:/data/db
env_file:
- mongo.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
@@ -1,15 +0,0 @@
try {
const status = rs.status();
printjson(status);
} catch (e) {
if (e.codeName === "NotYetInitialized") {
print("Replica set not initialized. Initiating...");
rs.initiate({
_id: "rs0",
members: [{ _id: 0, host: "mongodb:27017" }],
});
} else {
print("Unexpected error during rs.status():");
printjson(e);
}
}
@@ -1,16 +0,0 @@
var username = process.env.USERNAME_ENV_VAR;
var password = process.env.PASSWORD_ENV_VAR;
db = db.getSiblingDB("uptime_db");
db.createUser({
user: username,
pwd: password,
roles: [
{
role: "readWrite",
db: "uptime_db",
},
],
});
print("User uptime_user created successfully");
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-15
View File
@@ -1,15 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name checkmate-test.bluewavelabs.ca www.checkmate-test.bluewavelabs.ca;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://[domain-name]$request_uri;
}
}
-77
View File
@@ -1,77 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name checkmate-test.bluewavelabs.ca;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://server: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;
proxy_set_header Connection '';
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
location /api-docs/ {
proxy_pass http://server: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;
}
}
server {
listen 443 default_server ssl http2;
listen [::]:443 ssl http2;
server_name checkmate-test.bluewavelabs.ca;
ssl_certificate /etc/nginx/ssl/live/checkmate-test.bluewavelabs.ca/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/checkmate-test.bluewavelabs.ca/privkey.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://server: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;
proxy_set_header Connection '';
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
location /api-docs/ {
proxy_pass http://server: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;
}
}
-24
View File
@@ -1,24 +0,0 @@
FROM node:22-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
RUN cp -r src/templates dist/templates
EXPOSE 52345
CMD ["node", "dist/index.js"]
-33
View File
@@ -1,33 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Change directory to root Server directory for correct Docker Context
cd /d "%~dp0"
cd ../..
REM Define service names and their corresponding Dockerfiles
set services[0]=uptime_client
set dockerfiles[0]=.\docker\unified\client.Dockerfile
set services[1]=uptime_database_mongo
set dockerfiles[1]=.\docker\unified\mongoDB.Dockerfile
set services[2]=uptime_server
set dockerfiles[2]=.\docker\unified\server.Dockerfile
REM Loop through each service and build the corresponding image
for /L %%i in (0,1,2) do (
set service=!services[%%i]!
set dockerfile=!dockerfiles[%%i]!
docker build -f "!dockerfile!" -t "!service!" .
REM Check if the build succeeded
if errorlevel 1 (
echo Error building !service! image. Exiting...
exit /b 1
)
)
echo All images built successfully
exit /b 0
-25
View File
@@ -1,25 +0,0 @@
#!/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/unified/client.Dockerfile"
["uptime_database_mongo"]="./docker/unified/mongoDB.Dockerfile"
["uptime_server"]="./docker/unified/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"
-19
View File
@@ -1,19 +0,0 @@
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
-20
View File
@@ -1,20 +0,0 @@
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;"]
-114
View File
@@ -1,114 +0,0 @@
# 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
-3
View File
@@ -1,3 +0,0 @@
FROM mongo
EXPOSE 27017
CMD ["mongod"]
-31
View File
@@ -1,31 +0,0 @@
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;
}
}
-31
View File
@@ -1,31 +0,0 @@
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;
}
}
-22
View File
@@ -1,22 +0,0 @@
FROM node:22-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"]
-2
View File
@@ -19,8 +19,6 @@ If you need to monitor internal HTTPS endpoints with certificates from private C
### Example Configurations
The `docker/dev/` directory contains example configurations:
- `docker-compose.custom-ca-example.yaml` - Example Docker Compose with custom CA
- `server-custom-ca.Dockerfile` - Example Dockerfile for OS-level CA trust
- `export-smallstep-ca.sh` - Helper script for Smallstep CA export
## Contributing to Documentation
+18 -33
View File
@@ -18,8 +18,8 @@ Add a volume mount for your CA certificate and set the environment variable:
```yaml
services:
server:
image: uptime_server:latest
checkmate:
image: ghcr.io/bluewave-labs/checkmate:latest
restart: always
ports:
- "52345:52345"
@@ -30,7 +30,6 @@ services:
volumes:
- ./certs:/certs:ro
depends_on:
- redis
- mongodb
```
@@ -52,67 +51,53 @@ For more comprehensive trust configuration, you can create a derived Dockerfile
### Custom Dockerfile
Create `docker/dev/server-custom-ca.Dockerfile`:
Create `checkmate-custom-ca.Dockerfile`:
```dockerfile
FROM node:20-alpine
FROM ghcr.io/bluewave-labs/checkmate:latest
# Install ca-certificates for Alpine
RUN apk add --no-cache ca-certificates
USER root
WORKDIR /app
RUN apt-get update \
&& apt-get install -y ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY ./server/package*.json ./
RUN npm install
COPY ./server/ ./
# Copy your custom CA certificate
# Copy your custom CA certificate (must have a .crt extension)
COPY ./certs/custom-ca.crt /usr/local/share/ca-certificates/
# Update CA certificates
RUN update-ca-certificates
EXPOSE 52345
USER node
CMD ["node", "src/index.js"]
# Node uses its bundled CA store by default; make it read the system store
ENV NODE_OPTIONS="--use-system-ca"
```
### Docker Compose Override
Create `docker/dev/docker-compose.custom-ca.yaml`:
Create `docker-compose.custom-ca.yaml`:
```yaml
services:
server:
checkmate:
build:
context: .
dockerfile: server-custom-ca.Dockerfile
dockerfile: checkmate-custom-ca.Dockerfile
restart: always
ports:
- "52345:52345"
env_file:
- server.env
depends_on:
- redis
- mongodb
```
Run with: `docker-compose -f docker-compose.yaml -f docker-compose.custom-ca.yaml up`
Run with: `docker compose -f docker-compose.yaml -f docker-compose.custom-ca.yaml up`
## Alpine Linux Considerations
## Base Image Considerations
Since Checkmate uses Alpine Linux as the base image, you need to install the `ca-certificates` package:
```dockerfile
# Install ca-certificates for Alpine
RUN apk add --no-cache ca-certificates
# Copy and update CA certificates
COPY ./certs/custom-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
```
The Checkmate image is Debian-based (`node:22-slim`), which does not ship the `ca-certificates` package — install it before running `update-ca-certificates` (see the Dockerfile above). Certificates dropped into `/usr/local/share/ca-certificates/` must have a `.crt` extension, and Node only consults the system store when started with `--use-system-ca`. For most setups the `NODE_EXTRA_CA_CERTS` compose approach is simpler.
## Smallstep CA Configuration
+56
View File
@@ -0,0 +1,56 @@
# checkmate.so hosting (demo + staging)
Config for BlueWave's hosted instances at `demo.checkmate.so` and
`staging.checkmate.so`: one host, one nginx gateway terminating TLS, two
independent Checkmate stacks running the mono image
(`ghcr.io/bluewave-labs/checkmate`), plus a shared
[Capture](https://github.com/bluewave-labs/capture) agent. It replaces the old
`docker/unified/` setup (nginx client images + separate backend images + a
republished Mongo image) and doubles as a worked example of running the mono
image behind a TLS reverse proxy.
## How deploys work
`.github/workflows/build-image.yml` builds and pushes the image, then SSHes in
and runs `docker compose pull <service> && docker compose up -d <service>` in
this directory:
- merge to `develop` → image tagged `:develop` → `checkmate-staging` recreated
- merge to `master` → image tagged `:master` → `checkmate-demo` (prod) recreated
The host keeps a git checkout of this repo (on `develop`); the deploy does
`git pull` first so compose changes land with the code. Note the deploy only
recreates the checkmate service — changes to `gateway/nginx.conf` or the mongo
services need a manual `docker compose up -d` / gateway restart on the host.
## Host-local files (not committed)
Kept next to this compose file on the host:
- `server-prod.env` / `server-staging.env` — Checkmate server env
(`DB_CONNECTION_STRING`, `JWT_SECRET`, `CLIENT_HOST=https://demo.checkmate.so`
etc.). The old `UPTIME_APP_*` client vars are no-ops now and can be removed;
if a client override is ever needed, use the `CLIENT_CONFIG_*` vars (see the
Configuration section of the root README).
- `mongo-prod.env` / `mongo-staging.env` — Mongo credentials.
- `mongo/data-prod` / `mongo/data-staging` — Mongo data directories.
TLS certs live in `/etc/letsencrypt` (see `certbot-compose.yaml`; certbot
answers ACME challenges on port 8080 behind the gateway).
## One-time migration from docker/unified
1. `cd ~/checkmate && git pull` (must be on a branch containing this directory).
2. Stop the old stack: `cd docker/unified && docker compose down`.
3. Move host-local files here:
`mv docker/unified/{server-prod.env,server-staging.env,mongo-prod.env,mongo-staging.env} docs/hosting/checkmate-so/`
`mv docker/unified/mongo docs/hosting/checkmate-so/mongo`
4. **Check the Mongo data version before first start.** The old
`checkmate:mongo-*` images were built `FROM mongo` (floating latest), so the
data files follow whatever version was current at their last image build. Run
`db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })`
against the old container first and make the compose's `mongo:` tag match
(checked 2026-07-09: both stacks report FCV 8.2, hence the `mongo:8.2` pin
here). A lower pin than the data's FCV will refuse to start; a higher one
should step up one release at a time.
5. `cd docs/hosting/checkmate-so && docker compose up -d`.
@@ -0,0 +1,122 @@
# BlueWave's hosted demo + staging instances: one nginx gateway terminating TLS
# in front of two independent Checkmate stacks, both running the mono image
# (ghcr.io/bluewave-labs/checkmate). Doubles as a worked example of putting a
# TLS proxy in front of the image.
#
# Deployed by .github/workflows/build-image.yml (deploy-staging / deploy-demo
# jobs). Env files (server-prod.env, server-staging.env, mongo-prod.env,
# mongo-staging.env) live on the host next to this file and are not committed.
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
# Prod: demo.checkmate.so -----
checkmate-demo:
image: ghcr.io/bluewave-labs/checkmate:master
container_name: checkmate-demo
restart: always
env_file:
- server-prod.env
stop_grace_period: 60s
healthcheck:
test:
[
"CMD",
"node",
"-e",
"require('http').get('http://localhost:52346/livez',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))",
]
interval: 15s
timeout: 3s
start_period: 60s
start_interval: 2s
retries: 3
depends_on:
mongodb-prod:
condition: service_healthy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
mongodb-prod:
image: mongo:8.2
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: staging.checkmate.so -----
checkmate-staging:
image: ghcr.io/bluewave-labs/checkmate:develop
container_name: checkmate-staging
restart: always
env_file:
- server-staging.env
stop_grace_period: 60s
healthcheck:
test:
[
"CMD",
"node",
"-e",
"require('http').get('http://localhost:52346/livez',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))",
]
interval: 15s
timeout: 3s
start_period: 60s
start_interval: 2s
retries: 3
depends_on:
mongodb-staging:
condition: service_healthy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
mongodb-staging:
image: mongo:8.2
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
@@ -19,7 +19,7 @@ server {
}
# --- PRODUCTION: demo.checkmate.so ---
# --- DEMO: demo.checkmate.so ---
server {
listen 443 ssl;
server_name demo.checkmate.so;
@@ -31,13 +31,12 @@ server {
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# Passes traffic to the prod client on port 80
proxy_pass http://client-prod:80;
# The mono image serves both the SPA and the API
proxy_pass http://checkmate-demo:52345;
}
}
# --- STAGING: staging.checkmate.so ---
server {
listen 443 ssl;
server_name staging.checkmate.so;
@@ -49,7 +48,7 @@ server {
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# Passes traffic to the staging client on port 80
proxy_pass http://client-staging:80;
# The mono image serves both the SPA and the API
proxy_pass http://checkmate-staging:52345;
}
}
-25
View File
@@ -1,25 +0,0 @@
**(Please remove this line only before submitting your PR. Ensure that all relevant items are checked before submission.)**
## Describe your changes
Briefly describe the changes you made and their purpose.
## Write your issue number after "Fixes "
Fixes #123
## Please ensure all items are checked off before requesting a review. "Checked off" means you need to add an "x" character between brackets so they turn into checkmarks.
- [ ] (Do not skip this or your PR will be closed) I deployed the application locally.
- [ ] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
- [ ] I have included the issue # in the PR.
- [ ] I have added i18n support to visible strings (instead of `<div>Add</div>`, use):
```Javascript
const { t } = useTranslation();
<div>{t('add')}</div>
```
- [ ] The issue I am working on is assigned to me.
- [ ] I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
- [ ] My PR is granular and targeted to one specific feature.
-68
View File
@@ -1,68 +0,0 @@
name: Staging deploy
on:
push:
branches: ["develop"]
jobs:
docker-build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Server Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-backend:staging \
-f ./docker/staging/server.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate-backend \
.
- name: Push Server Docker image
run: docker push ghcr.io/bluewave-labs/checkmate-backend:staging
- name: Build Mongo Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-mongo:staging \
-f ./docker/staging/mongoDB.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate-backend \
.
- name: Push MongoDB Docker image
run: docker push ghcr.io/bluewave-labs/checkmate-mongo:staging
- name: Build Redis Docker image
run: |
docker build \
-t ghcr.io/bluewave-labs/checkmate-redis:staging \
-f ./docker/staging/redis.Dockerfile \
--label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate-backend \
.
- name: Push Redis Docker image
run: docker push ghcr.io/bluewave-labs/checkmate-redis:staging
deploy-to-staging:
needs: docker-build-and-push
runs-on: ubuntu-latest
steps:
- name: SSH into server and restart container using Docker Compose
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.STAGING_SERVER_HOST }}
username: ${{ secrets.STAGING_SERVER_USER }}
key: ${{ secrets.STAGING_SERVER_SSH_KEY }}
script: |
cd checkmate/server/docker/staging
docker compose down
docker compose pull
docker compose up -d
+24 -18
View File
@@ -867,7 +867,6 @@
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7",
@@ -1500,7 +1499,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
},
@@ -1545,7 +1543,6 @@
}
],
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18"
}
@@ -1561,6 +1558,29 @@
"kuler": "^2.0.0"
}
},
"node_modules/@emnapi/core": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz",
"integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz",
"integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
@@ -1568,6 +1588,7 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"tslib": "^2.4.0"
}
@@ -4239,7 +4260,6 @@
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^5.0.0",
@@ -4400,7 +4420,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -4638,7 +4657,6 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -5339,7 +5357,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5747,7 +5764,6 @@
"integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"peerDependencies": {
"bare-abort-controller": "*"
},
@@ -6073,7 +6089,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.10.42",
"caniuse-lite": "^1.0.30001800",
@@ -6959,7 +6974,6 @@
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.9.tgz",
"integrity": "sha512-uPR75+5Dk/WJ/YSPR1/YDHdwMM9c5FsaARljfKWgeCKLKOtJ0we21xy/RcCjn53fZnD/f6yYEIZ8pu18+GnbNQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"cssnano-preset-default": "^7.0.17",
"lilconfig": "^3.1.3"
@@ -7746,7 +7760,6 @@
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -8124,7 +8137,6 @@
"resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz",
"integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -9841,7 +9853,6 @@
"integrity": "sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "30.4.2",
"@jest/types": "30.4.1",
@@ -13146,7 +13157,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.12",
"picocolors": "^1.1.1",
@@ -15239,7 +15249,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -15409,7 +15418,6 @@
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -15573,7 +15581,6 @@
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -16362,7 +16369,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
-7
View File
@@ -1,7 +0,0 @@
for i in $(env | grep UPTIME_APP_)
do
key=$(echo $i | cut -d '=' -f 1)
value=$(echo $i | cut -d '=' -f 2-)
echo $key=$value
find ./public/assets -type f \( -name '*.js' -o -name '*.css' \) -exec sed -i "s|${key}|${value}|g" '{}' +
done
+7
View File
@@ -52,6 +52,13 @@ export const createApp = ({
app.use(createStatusPageDocumentCsp(allowedOrigin));
// Client runtime config; registered before express.static so it shadows the
// fallback config.js in the client build output
const clientConfigScript = `window.__CHECKMATE_CONFIG__ = ${JSON.stringify(envSettings.clientConfig).replace(/</g, "\\u003c")};`;
app.get("/config.js", (req, res) => {
res.set("Cache-Control", "no-cache").type("application/javascript").send(clientConfigScript);
});
app.use(express.static(frontendPath));
app.use("/api/v1/monitors/import/json", express.json({ limit: "10mb" }));
+17 -2
View File
@@ -1,5 +1,5 @@
import { z } from "zod";
import { DbTypes, QueueModes } from "@/domain/app-settings/app-settings.type.js";
import { DbTypes, LogLevels, QueueModes } from "@/domain/app-settings/app-settings.type.js";
import { booleanCoercion } from "@/api/validation/shared.js";
import { ILogger } from "@/utils/logger.js";
@@ -9,7 +9,7 @@ const envSchema = z.object({
// Port for worker health checks
HEALTH_PORT: z.string().default("52346"),
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).default("debug"),
LOG_LEVEL: z.enum(LogLevels).default("debug"),
// Database
DB_CONNECTION_STRING: z.string().min(1, "Database connection string is required"),
@@ -25,6 +25,12 @@ const envSchema = z.object({
// Client Configuration
CLIENT_HOST: z.string().url("CLIENT_HOST must be a valid URL"),
// Client runtime config overrides, rendered into GET /config.js; unset keys are
// omitted and the client uses its same-origin defaults
CLIENT_CONFIG_API_BASE_URL: z.string().optional(),
CLIENT_CONFIG_CLIENT_HOST: z.string().url("CLIENT_CONFIG_CLIENT_HOST must be a valid URL").optional(),
CLIENT_CONFIG_LOG_LEVEL: z.enum(LogLevels).optional(),
// Optional
ORIGIN: z.string().optional(),
@@ -63,6 +69,15 @@ export const validateEnv = (logger: ILogger): ValidatedEnv => {
process.exit(1);
}
const legacyClientVars = Object.keys(process.env).filter((key) => key.startsWith("UPTIME_APP_"));
if (legacyClientVars.length > 0) {
logger.warn({
message: `${legacyClientVars.join(", ")} no longer configure the client and will be ignored. The client defaults to the origin it is served from; to override, use CLIENT_CONFIG_API_BASE_URL, CLIENT_CONFIG_CLIENT_HOST, or CLIENT_CONFIG_LOG_LEVEL.`,
method: "validateEnv",
service: "Server",
});
}
logger.info({
message: "Environment variables validated successfully",
method: "validateEnv",
@@ -1,5 +1,5 @@
import { ISettingsRepository } from "@/domain/app-settings/app-settings-repository.interface.js";
import { Settings, SettingsUpdate, type DbType, type QueueMode } from "@/domain/app-settings/app-settings.type.js";
import { Settings, SettingsUpdate, type ClientRuntimeConfig, type DbType, type QueueMode } from "@/domain/app-settings/app-settings.type.js";
import { AppError } from "@/utils/AppError.js";
import { ValidatedEnv } from "@/config/envValidation.js";
import type { StringValue } from "ms";
@@ -16,6 +16,7 @@ export type EnvConfig = {
queueMode: QueueMode;
queuePrimaryProcesses: boolean;
statusPageThemesEnabled: boolean;
clientConfig: ClientRuntimeConfig;
};
export interface ISettingsService {
@@ -44,6 +45,11 @@ export class SettingsService implements ISettingsService {
queueMode: env.QUEUE_MODE,
queuePrimaryProcesses: env.QUEUE_PRIMARY_PROCESSES,
statusPageThemesEnabled: env.STATUS_PAGE_THEMES_ENABLED,
clientConfig: {
...(env.CLIENT_CONFIG_API_BASE_URL && { apiBaseUrl: env.CLIENT_CONFIG_API_BASE_URL }),
...(env.CLIENT_CONFIG_CLIENT_HOST && { clientHost: env.CLIENT_CONFIG_CLIENT_HOST }),
...(env.CLIENT_CONFIG_LOG_LEVEL && { logLevel: env.CLIENT_CONFIG_LOG_LEVEL }),
},
};
}
@@ -4,6 +4,17 @@ export type DbType = (typeof DbTypes)[number];
export const QueueModes = ["primary", "worker"] as const;
export type QueueMode = (typeof QueueModes)[number];
export const LogLevels = ["error", "warn", "info", "debug"] as const;
export type LogLevel = (typeof LogLevels)[number];
// Rendered into GET /config.js as window.__CHECKMATE_CONFIG__; keys left unset
// fall back to the client's same-origin defaults.
export type ClientRuntimeConfig = {
apiBaseUrl?: string;
clientHost?: string;
logLevel?: LogLevel;
};
export interface SettingsThresholds {
cpu?: number;
memory?: number;
+5 -2
View File
@@ -14,7 +14,7 @@ import Logger, { ILogger } from "@/utils/logger.js";
import { SettingsService } from "@/domain/app-settings/app-settings.service.js";
import { JobScheduler } from "@/worker/worker.job-scheduler.js";
import { IJobScheduler } from "@/worker/worker.interface.js";
import { HealthServer } from "@/worker/worker.health-server.js";
import { HealthServer, IHealthServer } from "@/worker/worker.health-server.js";
const SERVICE_NAME = "Server";
let logger: ILogger;
@@ -63,12 +63,15 @@ const startApp = async () => {
// Primary node path
// ***********************
let scheduler: IJobScheduler;
let healthServer: IHealthServer | undefined;
// ***********************
//Primary node processes jobs, need full worker
// ***********************
if (queuePrimaryProcesses === true) {
const { worker } = await buildWorker(shared, envSettings);
healthServer = new HealthServer(logger, env.HEALTH_PORT, worker);
await healthServer.listen();
scheduler = worker;
}
// ***********************
@@ -103,7 +106,7 @@ const startApp = async () => {
logger.info({ message: `Server started on port:${env.PORT}` });
});
initShutdownListener(server, services);
initShutdownListener(server, { ...services, healthServer });
};
startApp().catch((error) => {
@@ -83,6 +83,19 @@ describe("SettingsService", () => {
dbConnectionString: "mongodb://localhost:27017/test_db",
dbType: "mongodb",
statusPageThemesEnabled: false,
clientConfig: {},
});
});
it("maps only set CLIENT_CONFIG_* env vars into clientConfig", () => {
const { service } = createService({
CLIENT_CONFIG_API_BASE_URL: "https://api.example.com/api/v1",
CLIENT_CONFIG_LOG_LEVEL: "warn",
});
expect(service.loadSettings().clientConfig).toEqual({
apiBaseUrl: "https://api.example.com/api/v1",
logLevel: "warn",
});
});