mirror of
https://github.com/gadgethd/ukmesh.git
synced 2026-09-01 17:08:17 +00:00
Harden runtime and monitoring configuration
This commit is contained in:
@@ -32,8 +32,14 @@ MQTT_MAX_PAYLOAD_BYTES=65536
|
||||
MQTT_INGEST_CONCURRENCY=8
|
||||
MQTT_INGEST_QUEUE_MAX=1000
|
||||
|
||||
# Archive and remove repeater visibility after its own observer MQTT feed has
|
||||
# been silent for one month. Credentials and packet history are preserved.
|
||||
STALE_MQTT_OBSERVER_CLEANUP_DAYS=30
|
||||
STALE_MQTT_OBSERVER_CLEANUP_INTERVAL_MS=21600000
|
||||
|
||||
# Bound expensive statistics scans so they cannot exhaust the OLTP pool.
|
||||
STATS_DB_QUERY_CONCURRENCY=2
|
||||
WARMUP_NETWORKS=ukmesh
|
||||
|
||||
# ── Redis ─────────────────────────────────────────────────────────────────────
|
||||
# Docker Compose protects the internal Redis service with this password. The
|
||||
|
||||
@@ -31,6 +31,7 @@ COPY --from=backend-builder /build/backend/dist ./dist
|
||||
COPY --from=backend-builder /build/backend/src/db/schema ./dist/db/schema
|
||||
COPY --from=backend-builder /build/backend/src/db/migrations ./dist/db/migrations
|
||||
COPY --from=backend-builder /build/backend/src/db/owner-auth.sql ./dist/db/owner-auth.sql
|
||||
COPY --from=backend-builder /build/backend/src/backend-site/template.html ./dist/backend-site/template.html
|
||||
|
||||
# Copy frontend build into static dir served by backend
|
||||
COPY --from=frontend-builder /build/frontend/dist ./public
|
||||
|
||||
+2
-2
@@ -2,14 +2,14 @@
|
||||
FROM node:20-alpine AS backend-builder
|
||||
WORKDIR /build/backend
|
||||
COPY backend/package.json backend/package-lock.json ./
|
||||
RUN npm ci
|
||||
RUN npm ci --audit
|
||||
COPY backend/ ./
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine AS runtime
|
||||
WORKDIR /app
|
||||
COPY backend/package.json backend/package-lock.json ./
|
||||
RUN npm ci --omit=dev && npm cache clean --force
|
||||
RUN npm ci --omit=dev --audit && npm cache clean --force
|
||||
COPY --from=backend-builder /build/backend/dist ./dist
|
||||
COPY --from=backend-builder /build/backend/src/db/schema ./dist/db/schema
|
||||
COPY --from=backend-builder /build/backend/src/db/migrations ./dist/db/migrations
|
||||
|
||||
+27
-1
@@ -1,3 +1,5 @@
|
||||
name: ${COMPOSE_PROJECT_NAME:-meshcore-analytics}
|
||||
|
||||
x-anubis-base: &anubis-base
|
||||
image: ghcr.io/techarohq/anubis:v1.25.0
|
||||
restart: always
|
||||
@@ -203,6 +205,9 @@ services:
|
||||
volumes:
|
||||
- mosquitto_log:/mosquitto/log:ro
|
||||
- ./mosquitto:/mosquitto/config
|
||||
# The backend currently needs Docker API access for the owner ACL
|
||||
# reconciler. Production deployments should prefer docker-socket-proxy
|
||||
# with only the required endpoints; use :ro when mutation is not needed.
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/healthz >/dev/null"]
|
||||
@@ -298,6 +303,8 @@ services:
|
||||
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET required}
|
||||
DATABASE_STATEMENT_TIMEOUT_MS: 300000
|
||||
DATABASE_SKIP_SCHEMA_INIT: "true"
|
||||
STALE_MQTT_OBSERVER_CLEANUP_DAYS: ${STALE_MQTT_OBSERVER_CLEANUP_DAYS:-30}
|
||||
STALE_MQTT_OBSERVER_CLEANUP_INTERVAL_MS: ${STALE_MQTT_OBSERVER_CLEANUP_INTERVAL_MS:-21600000}
|
||||
NODE_ENV: production
|
||||
depends_on:
|
||||
timescaledb:
|
||||
@@ -338,7 +345,7 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.backend
|
||||
restart: "no"
|
||||
restart: on-failure:3
|
||||
logging: *json-log-limits
|
||||
mem_limit: "512m"
|
||||
memswap_limit: "512m"
|
||||
@@ -754,6 +761,23 @@ services:
|
||||
depends_on:
|
||||
- loki
|
||||
|
||||
prometheus:
|
||||
<<: *internal-hosts
|
||||
image: prom/prometheus:v3.5.0
|
||||
restart: always
|
||||
logging: *json-log-limits
|
||||
mem_limit: "256m"
|
||||
memswap_limit: "256m"
|
||||
command: ["--config.file=/etc/prometheus/prometheus.yml", "--storage.tsdb.retention.time=15d"]
|
||||
volumes:
|
||||
- ./logging/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus_data:/prometheus
|
||||
ports:
|
||||
- "127.0.0.1:9090:9090"
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
|
||||
grafana:
|
||||
<<: *internal-hosts
|
||||
image: grafana/grafana:11.5.0
|
||||
@@ -773,6 +797,7 @@ services:
|
||||
- "127.0.0.1:3010:3000"
|
||||
depends_on:
|
||||
- loki
|
||||
- prometheus
|
||||
|
||||
networks:
|
||||
default:
|
||||
@@ -792,4 +817,5 @@ volumes:
|
||||
srtm_data:
|
||||
loki_data:
|
||||
grafana_data:
|
||||
prometheus_data:
|
||||
mesh_health_check_data:
|
||||
|
||||
@@ -9,6 +9,11 @@ map "$mesh_trusted_edge:$http_cf_connecting_ip" $mesh_client_ip {
|
||||
~^1:([0-9A-Fa-f:.]+)$ $1;
|
||||
}
|
||||
|
||||
map $uri $mesh_permissions_policy {
|
||||
default "geolocation=(), camera=(), microphone=()";
|
||||
~^/(feed|repeater)?/?$ "geolocation=(self), camera=(), microphone=()";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
@@ -2,7 +2,7 @@ add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; prelo
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
|
||||
add_header Permissions-Policy "$mesh_permissions_policy" always;
|
||||
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
||||
add_header Cross-Origin-Resource-Policy "same-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self' wss: https:; font-src 'self' data:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://basemaps.cartocdn.com https://*.basemaps.cartocdn.com https://openstreetmap.org https://*.openstreetmap.org; connect-src 'self' wss: https:; font-src 'self' data:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'" always;
|
||||
|
||||
@@ -9,6 +9,11 @@ map "$mesh_trusted_edge:$http_cf_connecting_ip" $mesh_client_ip {
|
||||
~^1:([0-9A-Fa-f:.]+)$ $1;
|
||||
}
|
||||
|
||||
map $uri $mesh_permissions_policy {
|
||||
default "geolocation=(), camera=(), microphone=()";
|
||||
~^/(feed|repeater)?/?$ "geolocation=(self), camera=(), microphone=()";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
Reference in New Issue
Block a user