Bunch of monitoring services added. Need to work through all the configuration next.

This commit is contained in:
admin 2025-12-14 11:31:22 -07:00
parent 4ef4ac414b
commit 84d1285677
271 changed files with 3673 additions and 85 deletions

10
.gitignore vendored
View File

@ -4,6 +4,16 @@
/configs/code-server/.config/* /configs/code-server/.config/*
!/configs/code-server/.config/.gitkeep !/configs/code-server/.config/.gitkeep
# MkDocs cache and built site (created by containers)
/mkdocs/.cache/*
!/mkdocs/.cache/.gitkeep
/mkdocs/site/*
!/mkdocs/site/.gitkeep
# Homepage logs (created by container)
/configs/homepage/logs/*
!/configs/homepage/logs/.gitkeep
.env .env
.env* .env*

View File

@ -106,4 +106,35 @@ This project is licensed under the Apache License 2.0 - https://opensource.org/l
This project used AI tools to assist in its creation and large amounts of the boilerplate code was reviewed using AI. AI tools (although not activated or connected) are pre-installed in the Coder docker image. See `docker.code-server` for more details. This project used AI tools to assist in its creation and large amounts of the boilerplate code was reviewed using AI. AI tools (although not activated or connected) are pre-installed in the Coder docker image. See `docker.code-server` for more details.
While these tools can help generate code and documentation, they may also introduce errors or inaccuracies. Users should review and test all content to ensure it meets their requirements and standards. While these tools can help generate code and documentation, they may also introduce errors or inaccuracies. Users should review and test all content to ensure it meets their requirements and standards.
## Troubleshooting
### Permission Denied Errors (EACCES)
If you see errors like `EACCES: permission denied` when starting containers, run the included fix script:
```bash
./fix-permissions.sh
```
This fixes permissions on directories that containers need to write to, such as:
- `configs/code-server/.config` and `.local` (Code Server)
- `mkdocs/.cache` (MkDocs social cards plugin)
- `mkdocs/site` (MkDocs built output)
If the script can't fix some directories (owned by a different container UID), it will prompt to use `sudo`.
### Manual Permission Fix
If you prefer to fix manually:
```bash
# Fix all permissions at once
sudo chown -R $(id -u):$(id -g) .
chmod -R 755 .
# Or fix specific directories
chmod -R 777 configs/code-server/.config configs/code-server/.local
chmod -R 777 mkdocs/.cache mkdocs/site
```

0
assets/uploads/.gitkeep Normal file
View File

163
config.sh
View File

@ -82,6 +82,85 @@ backup_env_file() {
fi fi
} }
# Function to fix permissions on directories that containers need to write to
# This prevents EACCES errors when containers try to create files/directories
fix_container_permissions() {
echo ""
echo "=== Fixing Container Directory Permissions ==="
echo "Setting up directories that containers need write access to..."
# Get the user/group IDs (default to 1000 if not set)
local user_id=${USER_ID:-1000}
local group_id=${GROUP_ID:-1000}
# Define directories that need to be writable by containers
# Format: "path:description"
local -a writable_dirs=(
"$SCRIPT_DIR/configs/code-server/.config:Code Server config"
"$SCRIPT_DIR/configs/code-server/.local:Code Server local data"
"$SCRIPT_DIR/mkdocs/.cache:MkDocs cache (social cards, etc.)"
"$SCRIPT_DIR/mkdocs/site:MkDocs built site"
"$SCRIPT_DIR/assets/uploads:Listmonk uploads"
"$SCRIPT_DIR/assets/images:Shared images"
)
local errors=0
for dir_entry in "${writable_dirs[@]}"; do
local dir_path="${dir_entry%%:*}"
local dir_desc="${dir_entry#*:}"
# Create directory if it doesn't exist
if [ ! -d "$dir_path" ]; then
echo " Creating: $dir_path ($dir_desc)"
mkdir -p "$dir_path"
fi
# Add .gitkeep to track empty directories in git
if [ ! -f "$dir_path/.gitkeep" ]; then
touch "$dir_path/.gitkeep"
fi
# Fix permissions - make writable by container user
if chmod -R 777 "$dir_path" 2>/dev/null; then
echo "$dir_desc: permissions fixed"
else
echo " ⚠️ $dir_desc: could not fix permissions (may need sudo)"
((errors++))
fi
done
# Handle directories that may have been created by containers with different UIDs
# These need special handling (may require sudo)
local -a potentially_owned_by_container=(
"$SCRIPT_DIR/mkdocs/site"
)
for dir_path in "${potentially_owned_by_container[@]}"; do
if [ -d "$dir_path" ]; then
# Check if we own the directory
if [ ! -w "$dir_path" ]; then
echo ""
echo " ⚠️ Directory $dir_path is not writable."
echo " This may have been created by a container with a different UID."
echo " To fix, run: sudo chown -R $user_id:$group_id $dir_path"
((errors++))
fi
fi
done
echo ""
if [ $errors -eq 0 ]; then
echo "✅ All container directories are properly configured!"
else
echo "⚠️ Some directories may need manual permission fixes."
echo " You can try: sudo chown -R $user_id:$group_id $SCRIPT_DIR"
fi
echo ""
return $errors
}
# Function to get all used ports on the system # Function to get all used ports on the system
get_used_ports() { get_used_ports() {
local used_ports=() local used_ports=()
@ -188,6 +267,11 @@ initialize_available_ports() {
["REDIS_PORT"]=6379 ["REDIS_PORT"]=6379
["PROMETHEUS_PORT"]=9090 ["PROMETHEUS_PORT"]=9090
["GRAFANA_PORT"]=3001 ["GRAFANA_PORT"]=3001
["CADVISOR_PORT"]=8080
["NODE_EXPORTER_PORT"]=9100
["REDIS_EXPORTER_PORT"]=9121
["ALERTMANAGER_PORT"]=9093
["GOTIFY_PORT"]=8889
) )
# Find available ports for each service # Find available ports for each service
@ -260,6 +344,15 @@ REDIS_PORT=${REDIS_PORT:-6379}
PROMETHEUS_PORT=${PROMETHEUS_PORT:-9090} PROMETHEUS_PORT=${PROMETHEUS_PORT:-9090}
GRAFANA_PORT=${GRAFANA_PORT:-3001} GRAFANA_PORT=${GRAFANA_PORT:-3001}
# Monitoring Exporters Ports
CADVISOR_PORT=${CADVISOR_PORT:-8080}
NODE_EXPORTER_PORT=${NODE_EXPORTER_PORT:-9100}
REDIS_EXPORTER_PORT=${REDIS_EXPORTER_PORT:-9121}
# Alerting Services Ports
ALERTMANAGER_PORT=${ALERTMANAGER_PORT:-9093}
GOTIFY_PORT=${GOTIFY_PORT:-8889}
# Domain Configuration # Domain Configuration
BASE_DOMAIN=https://changeme.org BASE_DOMAIN=https://changeme.org
DOMAIN=changeme.org DOMAIN=changeme.org
@ -324,6 +417,24 @@ PROMETHEUS_RETENTION_TIME=30d
GRAFANA_PORT=3001 GRAFANA_PORT=3001
GRAFANA_ADMIN_USER=admin GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=changeMe GRAFANA_ADMIN_PASSWORD=changeMe
GRAFANA_ROOT_URL=http://localhost:3001
# Monitoring Exporters
CADVISOR_PORT=8080
NODE_EXPORTER_PORT=9100
REDIS_EXPORTER_PORT=9121
# Alertmanager (alert routing)
ALERTMANAGER_PORT=9093
# Gotify (push notifications)
GOTIFY_PORT=8889
GOTIFY_ADMIN_USER=admin
GOTIFY_ADMIN_PASSWORD=changeMe
GOTIFY_APP_TOKEN=
# Alert Email Configuration
ALERT_EMAIL_TO=admin@changeme.org
EOL EOL
echo "New .env file created with conflict-free port assignments." echo "New .env file created with conflict-free port assignments."
@ -349,6 +460,13 @@ EOL
echo "Redis: ${REDIS_PORT:-6379}" echo "Redis: ${REDIS_PORT:-6379}"
echo "Prometheus: ${PROMETHEUS_PORT:-9090}" echo "Prometheus: ${PROMETHEUS_PORT:-9090}"
echo "Grafana: ${GRAFANA_PORT:-3001}" echo "Grafana: ${GRAFANA_PORT:-3001}"
echo ""
echo "=== Monitoring Services ==="
echo "cAdvisor: ${CADVISOR_PORT:-8080}"
echo "Node Exporter: ${NODE_EXPORTER_PORT:-9100}"
echo "Redis Exporter: ${REDIS_EXPORTER_PORT:-9121}"
echo "Alertmanager: ${ALERTMANAGER_PORT:-9093}"
echo "Gotify: ${GOTIFY_PORT:-8889}"
echo "================================" echo "================================"
} }
@ -413,6 +531,9 @@ update_services_yaml() {
["Gitea"]="git.$new_domain" ["Gitea"]="git.$new_domain"
["Prometheus"]="prometheus.$new_domain" ["Prometheus"]="prometheus.$new_domain"
["Grafana"]="grafana.$new_domain" ["Grafana"]="grafana.$new_domain"
["Alertmanager"]="alertmanager.$new_domain"
["Gotify"]="gotify.$new_domain"
["cAdvisor"]="cadvisor.$new_domain"
) )
# Process each service mapping # Process each service mapping
@ -573,6 +694,15 @@ ingress:
- hostname: grafana.$new_domain - hostname: grafana.$new_domain
service: http://localhost:${GRAFANA_PORT:-3001} service: http://localhost:${GRAFANA_PORT:-3001}
- hostname: alertmanager.$new_domain
service: http://localhost:${ALERTMANAGER_PORT:-9093}
- hostname: gotify.$new_domain
service: http://localhost:${GOTIFY_PORT:-8889}
- hostname: cadvisor.$new_domain
service: http://localhost:${CADVISOR_PORT:-8080}
# Catch-all rule (required) # Catch-all rule (required)
- service: http_status:404 - service: http_status:404
EOL EOL
@ -862,6 +992,11 @@ check_port_conflicts() {
"REDIS_PORT" "REDIS_PORT"
"PROMETHEUS_PORT" "PROMETHEUS_PORT"
"GRAFANA_PORT" "GRAFANA_PORT"
"CADVISOR_PORT"
"NODE_EXPORTER_PORT"
"REDIS_EXPORTER_PORT"
"ALERTMANAGER_PORT"
"GOTIFY_PORT"
) )
for var in "${port_vars[@]}"; do for var in "${port_vars[@]}"; do
@ -1097,6 +1232,9 @@ update_env_var "GITEA_ROOT_URL" "https://git.$domain_name"
update_env_var "COOKIE_DOMAIN" ".$domain_name" update_env_var "COOKIE_DOMAIN" ".$domain_name"
update_env_var "ALLOWED_ORIGINS" "https://map.$domain_name,http://localhost:3000" update_env_var "ALLOWED_ORIGINS" "https://map.$domain_name,http://localhost:3000"
# Update alert email to use new domain
update_env_var "ALERT_EMAIL_TO" "admin@$domain_name"
echo "Domain settings updated successfully!" echo "Domain settings updated successfully!"
# Update the map's .env file # Update the map's .env file
@ -1229,8 +1367,15 @@ update_env_var "GITEA_DB_ROOT_PASSWORD" "$gitea_db_root_password"
grafana_admin_password=$(generate_password 20) grafana_admin_password=$(generate_password 20)
update_env_var "GRAFANA_ADMIN_PASSWORD" "$grafana_admin_password" update_env_var "GRAFANA_ADMIN_PASSWORD" "$grafana_admin_password"
# Generate and update Gotify admin password
gotify_admin_password=$(generate_password 20)
update_env_var "GOTIFY_ADMIN_PASSWORD" "$gotify_admin_password"
echo "Secure passwords generated and updated." echo "Secure passwords generated and updated."
# Fix container directory permissions before finishing
fix_container_permissions
echo -e "\n✅ Configuration completed successfully!" echo -e "\n✅ Configuration completed successfully!"
echo "Your .env file has been configured with:" echo "Your .env file has been configured with:"
echo "- Instance ID: $instance_identifier" echo "- Instance ID: $instance_identifier"
@ -1242,7 +1387,9 @@ echo "- Listmonk Admin: $listmonk_user"
echo "- N8N Admin Email: $n8n_email" echo "- N8N Admin Email: $n8n_email"
echo "- Secure random passwords for database, encryption, and NocoDB" echo "- Secure random passwords for database, encryption, and NocoDB"
echo "- Grafana Admin Password: Generated (see .env file)" echo "- Grafana Admin Password: Generated (see .env file)"
echo "- Gotify Admin Password: Generated (see .env file)"
echo "- Centralized services: Redis, Prometheus, Grafana" echo "- Centralized services: Redis, Prometheus, Grafana"
echo "- Monitoring services: cAdvisor, Node Exporter, Redis Exporter, Alertmanager, Gotify"
echo "- Tunnel configuration updated at: $TUNNEL_CONFIG_FILE" echo "- Tunnel configuration updated at: $TUNNEL_CONFIG_FILE"
echo -e "\nYour .env file is located at: $ENV_FILE" echo -e "\nYour .env file is located at: $ENV_FILE"
echo "A backup of your original .env file was created before modifications." echo "A backup of your original .env file was created before modifications."
@ -1271,13 +1418,25 @@ echo " - Map: http://localhost:${MAP_PORT:-3000}"
echo " - Influence: http://localhost:${INFLUENCE_PORT:-3333}" echo " - Influence: http://localhost:${INFLUENCE_PORT:-3333}"
echo " - Mini QR: http://localhost:${MINI_QR_PORT:-8089}" echo " - Mini QR: http://localhost:${MINI_QR_PORT:-8089}"
echo "" echo ""
echo " Centralized Services (optional monitoring profile):" echo " Centralized Services:"
echo " - Redis: http://localhost:${REDIS_PORT:-6379}"
echo ""
echo " Monitoring Services (optional monitoring profile):"
echo " - Prometheus: http://localhost:${PROMETHEUS_PORT:-9090}" echo " - Prometheus: http://localhost:${PROMETHEUS_PORT:-9090}"
echo " - Grafana: http://localhost:${GRAFANA_PORT:-3001} (admin/${GRAFANA_ADMIN_PASSWORD})" echo " - Grafana: http://localhost:${GRAFANA_PORT:-3001}"
echo " - Alertmanager: http://localhost:${ALERTMANAGER_PORT:-9093}"
echo " - Gotify: http://localhost:${GOTIFY_PORT:-8889}"
echo " - cAdvisor: http://localhost:${CADVISOR_PORT:-8080}"
echo " - Node Exporter: http://localhost:${NODE_EXPORTER_PORT:-9100}/metrics"
echo " - Redis Exporter: http://localhost:${REDIS_EXPORTER_PORT:-9121}/metrics"
echo "" echo ""
echo " To start with monitoring:" echo " To start with monitoring:"
echo " docker compose --profile monitoring up -d" echo " docker compose --profile monitoring up -d"
echo "" echo ""
echo " Monitoring Credentials:"
echo " - Grafana: admin / (check .env: GRAFANA_ADMIN_PASSWORD)"
echo " - Gotify: admin / (check .env: GOTIFY_ADMIN_PASSWORD)"
echo ""
echo "3. When ready for production:" echo "3. When ready for production:"
echo " ./start-production.sh" echo " ./start-production.sh"
echo "" echo ""

View File

@ -0,0 +1,100 @@
global:
resolve_timeout: 5m
# SMTP configuration for email alerts (fallback)
# Using MailHog for development - update for production
smtp_from: 'alerts@changemaker.local'
smtp_smarthost: 'mailhog:1025'
smtp_auth_username: ''
smtp_auth_password: ''
smtp_require_tls: false
# Templates for notification content
templates:
- '/etc/alertmanager/*.tmpl'
# Route alerts to appropriate receivers based on severity
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'default'
routes:
# Critical alerts go to both Gotify and email
- match:
severity: critical
receiver: 'critical-alerts'
group_wait: 0s
group_interval: 5m
repeat_interval: 4h
# Warning alerts go to Gotify only
- match:
severity: warning
receiver: 'warning-alerts'
group_wait: 30s
repeat_interval: 12h
# Info alerts (rate limiting, etc.) - Gotify with lower priority
- match:
severity: info
receiver: 'info-alerts'
repeat_interval: 24h
# Alert receivers
receivers:
# Default receiver (catches all unmatched)
# Note: Configure GOTIFY_APP_TOKEN in .env and update this file for Gotify to work
- name: 'default'
email_configs:
- to: 'admin@changemaker.local'
headers:
Subject: '[Changemaker] {{ .GroupLabels.alertname }}'
# Critical alerts - email only (configure Gotify token for push notifications)
- name: 'critical-alerts'
email_configs:
- to: 'admin@changemaker.local'
headers:
Subject: '🚨 CRITICAL Alert: {{ .GroupLabels.alertname }}'
html: |
<h2 style="color: #d32f2f;">Critical Alert Triggered</h2>
{{ range .Alerts }}
<p><strong>Alert:</strong> {{ .Labels.alertname }}</p>
<p><strong>Severity:</strong> {{ .Labels.severity }}</p>
<p><strong>Summary:</strong> {{ .Annotations.summary }}</p>
<p><strong>Description:</strong> {{ .Annotations.description }}</p>
<p><strong>Started:</strong> {{ .StartsAt }}</p>
<hr>
{{ end }}
# Warning alerts - email only
- name: 'warning-alerts'
email_configs:
- to: 'admin@changemaker.local'
headers:
Subject: '⚠️ Warning: {{ .GroupLabels.alertname }}'
# Info alerts - email only
- name: 'info-alerts'
email_configs:
- to: 'admin@changemaker.local'
headers:
Subject: ' Info: {{ .GroupLabels.alertname }}'
# Inhibition rules (prevent spam)
inhibit_rules:
# If a critical alert is firing, suppress related warnings
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'instance']
# If disk is critical, suppress disk warning
- source_match:
alertname: 'DiskSpaceCritical'
target_match:
alertname: 'DiskSpaceLow'
equal: ['instance']

0
configs/code-server/.config/.gitkeep Normal file → Executable file
View File

0
configs/code-server/.local/.gitkeep Normal file → Executable file
View File

View File

@ -0,0 +1,509 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [
{
"options": {
"0": {
"color": "red",
"index": 1,
"text": "DOWN"
},
"1": {
"color": "green",
"index": 0,
"text": "UP"
}
},
"type": "value"
}
],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "red",
"value": null
},
{
"color": "green",
"value": 1
}
]
},
"unit": "short"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"orientation": "auto",
"reduceOptions": {
"values": false,
"calcs": [
"lastNotNull"
],
"fields": ""
},
"showThresholdLabels": false,
"showThresholdMarkers": true,
"text": {}
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "up{job=\"influence-app\"}",
"legendFormat": "Influence App",
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "redis_up",
"legendFormat": "Redis",
"refId": "B"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "up{job=\"node\"}",
"legendFormat": "System Node",
"refId": "C"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "up{job=\"prometheus\"}",
"legendFormat": "Prometheus",
"refId": "D"
}
],
"title": "Service Status",
"type": "gauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"tooltip": false,
"viz": false,
"legend": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percent"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "100 - (avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
"legendFormat": "CPU Usage",
"refId": "A"
}
],
"title": "CPU Usage",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"tooltip": false,
"viz": false,
"legend": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percent"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 8
},
"id": 3,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100",
"legendFormat": "Memory Usage",
"refId": "A"
}
],
"title": "Memory Usage",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"tooltip": false,
"viz": false,
"legend": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
},
"unit": "percent"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 16
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "(1 - (node_filesystem_avail_bytes{mountpoint=\"/\"} / node_filesystem_size_bytes{mountpoint=\"/\"})) * 100",
"legendFormat": "Disk Usage",
"refId": "A"
}
],
"title": "Disk Usage",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"tooltip": false,
"viz": false,
"legend": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "reqps"
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 16
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"expr": "rate(influence_http_requests_total[5m])",
"legendFormat": "Requests/sec",
"refId": "A"
}
],
"title": "HTTP Request Rate",
"type": "timeseries"
}
],
"refresh": "10s",
"schemaVersion": 38,
"style": "dark",
"tags": ["changemaker", "system-health"],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Changemaker System Health",
"uid": "changemaker-system-health",
"version": 1,
"weekStart": ""
}

1828
configs/homepage/logs/homepage.log Normal file → Executable file

File diff suppressed because it is too large Load Diff

5
configs/homepage/proxmox.yaml Executable file
View File

@ -0,0 +1,5 @@
---
# pve:
# url: https://proxmox.host.or.ip:8006
# token: username@pam!Token ID
# secret: secret

247
configs/homepage/services.yaml Normal file → Executable file
View File

@ -1,79 +1,274 @@
--- ---
# For public access, replace "http://localhost" with your subdomain URLs # Homepage Services Configuration
# Tab 1: Production URLs (external/public access)
# Tab 2: Local Development URLs (localhost with ports from config.sh)
- Essential Tools: #####################################
# PRODUCTION - External URLs
#####################################
- Production - Essential Tools:
- Code Server: - Code Server:
icon: mdi-code-braces icon: mdi-code-braces
href: "https://code.cmlite.org" href: "https://code.bnkserve.org"
description: VS Code in the browser - Platform Editor description: VS Code in the browser - Platform Editor
container: code-server-changemaker container: code-server-changemaker
- NocoDB: - NocoDB:
icon: mdi-database icon: mdi-database
href: "https://db.cmlite.org" href: "https://db.bnkserve.org"
description: No-code database platform description: No-code database platform
container: changemakerlite-nocodb-1 container: changemakerlite-nocodb-1
- Map Server: - Map Server:
icon: mdi-map icon: mdi-map
href: "https://map.cmlite.org" href: "https://map.bnkserve.org"
description: Map server for geospatial data description: Map server for geospatial data
container: nocodb-map-viewer container: nocodb-map-viewer
- Influence: - Influence:
icon: mdi-account-group icon: mdi-account-group
href: "https://influence.cmlite.org" href: "https://influence.bnkserve.org"
description: Political influence and campaign management description: Political influence and campaign management
container: influence-app-1 container: influence-app-1
- Content & Documentation: - Production - Content & Docs:
- Main Site:
- Main Site:
icon: mdi-web icon: mdi-web
href: "https://cmlite.org" href: "https://bnkserve.org"
description: CM-lite campaign website description: CM-lite campaign website
container: mkdocs-site-server-changemaker container: mkdocs-site-server-changemaker
- MkDocs (Live): - MkDocs (Live):
icon: mdi-book-open-page-variant icon: mdi-book-open-page-variant
href: "https://docs.cmlite.org" href: "https://docs.cmlite.org"
description: Live documentation server with hot reload description: Live documentation server with hot reload
container: mkdocs-changemaker container: mkdocs-changemaker
- Mini QR: - Mini QR:
icon: mdi-qrcode icon: mdi-qrcode
href: "https://qr.cmlite.org" href: "https://qr.bnkserve.org"
description: QR code generator description: QR code generator
container: mini-qr container: mini-qr
- Listmonk: - Listmonk:
icon: mdi-email-newsletter icon: mdi-email-newsletter
href: "https://listmonk.cmlite.org" href: "https://listmonk.bnkserve.org"
description: Newsletter & mailing list manager description: Newsletter & mailing list manager
container: listmonk_app container: listmonk_app
- Automation & Infrastructure: - Production - Automation:
- n8n: - n8n:
icon: mdi-robot-industrial icon: mdi-robot-industrial
href: "https://n8n.cmlite.org" href: "https://n8n.bnkserve.org"
description: Workflow automation platform description: Workflow automation platform
container: n8n-changemaker container: n8n-changemaker
- Gitea:
icon: mdi-git
href: "https://git.bnkserve.org"
description: Git repository hosting
container: gitea_changemaker
- PostgreSQL (Listmonk): - PostgreSQL (Listmonk):
icon: mdi-database-outline icon: mdi-database-outline
href: "#" href: "#"
description: Database for Listmonk description: Database for Listmonk
container: listmonk_db container: listmonk_db
- PostgreSQL (NocoDB): - PostgreSQL (NocoDB):
icon: mdi-database-outline icon: mdi-database-outline
href: "#" href: "#"
description: Database for NocoDB description: Database for NocoDB
container: changemakerlite-root_db-1 container: changemakerlite-root_db-1
- Redis:
icon: mdi-database-sync
href: "#"
description: Shared cache & session storage
container: redis-changemaker
- Production - Monitoring:
- Prometheus:
icon: mdi-chart-line
href: "https://prometheus.bnkserve.org"
description: Metrics collection & time-series database
container: prometheus-changemaker
- Grafana:
icon: mdi-chart-box
href: "https://grafana.bnkserve.org"
description: Monitoring dashboards & visualizations
container: grafana-changemaker
- Alertmanager:
icon: mdi-bell-alert
href: "https://alertmanager.bnkserve.org"
description: Alert routing & notification management
container: alertmanager-changemaker
- Gotify:
icon: mdi-cellphone-message
href: "https://gotify.bnkserve.org"
description: Self-hosted push notifications
container: gotify-changemaker
- cAdvisor:
icon: mdi-docker
href: "https://cadvisor.bnkserve.org"
description: Container resource metrics
container: cadvisor-changemaker
- Node Exporter:
icon: mdi-server
href: "#"
description: System-level metrics exporter
container: node-exporter-changemaker
- Redis Exporter:
icon: mdi-database-export
href: "#"
description: Redis metrics exporter
container: redis-exporter-changemaker
#####################################
# LOCAL DEVELOPMENT - Localhost URLs
#####################################
- Local - Essential Tools:
- Code Server:
icon: mdi-code-braces
href: "http://localhost:8888"
description: VS Code in the browser (port 8888)
container: code-server-changemaker
- NocoDB:
icon: mdi-database
href: "http://localhost:8090"
description: No-code database platform (port 8090)
container: changemakerlite-nocodb-1
- Map Server:
icon: mdi-map
href: "http://localhost:3000"
description: Map server for geospatial data (port 3000)
container: nocodb-map-viewer
- Influence:
icon: mdi-account-group
href: "http://localhost:3333"
description: Political influence and campaign management (port 3333)
container: influence-app-1
- Homepage:
icon: mdi-home
href: "http://localhost:3010"
description: This dashboard (port 3010)
container: homepage-changemaker
- Local - Content & Docs:
- Main Site:
icon: mdi-web
href: "http://localhost:4001"
description: CM-lite campaign website (port 4001)
container: mkdocs-site-server-changemaker
- MkDocs (Live):
icon: mdi-book-open-page-variant
href: "http://localhost:4000"
description: Live documentation with hot reload (port 4000)
container: mkdocs-changemaker
- Mini QR:
icon: mdi-qrcode
href: "http://localhost:8089"
description: QR code generator (port 8089)
container: mini-qr
- Listmonk:
icon: mdi-email-newsletter
href: "http://localhost:9000"
description: Newsletter & mailing list manager (port 9000)
container: listmonk_app
- Local - Automation:
- n8n:
icon: mdi-robot-industrial
href: "http://localhost:5678"
description: Workflow automation platform (port 5678)
container: n8n-changemaker
- Gitea: - Gitea:
icon: mdi-git icon: mdi-git
href: "https://git.cmlite.org" href: "http://localhost:3030"
description: Git repository hosting description: Git repository hosting (port 3030)
container: gitea_changemaker container: gitea_changemaker
- PostgreSQL (Listmonk):
icon: mdi-database-outline
href: "#"
description: Database for Listmonk (port 5432)
container: listmonk_db
- PostgreSQL (NocoDB):
icon: mdi-database-outline
href: "#"
description: Database for NocoDB
container: changemakerlite-root_db-1
- Redis:
icon: mdi-database-sync
href: "#"
description: Shared cache & session storage (port 6379)
container: redis-changemaker
- Local - Monitoring:
- Prometheus:
icon: mdi-chart-line
href: "http://localhost:9090"
description: Metrics collection & time-series database (port 9090)
container: prometheus-changemaker
- Grafana:
icon: mdi-chart-box
href: "http://localhost:3001"
description: Monitoring dashboards & visualizations (port 3001)
container: grafana-changemaker
- Alertmanager:
icon: mdi-bell-alert
href: "http://localhost:9093"
description: Alert routing & notification management (port 9093)
container: alertmanager-changemaker
- Gotify:
icon: mdi-cellphone-message
href: "http://localhost:8889"
description: Self-hosted push notifications (port 8889)
container: gotify-changemaker
- cAdvisor:
icon: mdi-docker
href: "http://localhost:8080"
description: Container resource metrics (port 8080)
container: cadvisor-changemaker
- Node Exporter:
icon: mdi-server
href: "http://localhost:9100/metrics"
description: System-level metrics exporter (port 9100)
container: node-exporter-changemaker
- Redis Exporter:
icon: mdi-database-export
href: "http://localhost:9121/metrics"
description: Redis metrics exporter (port 9121)
container: redis-exporter-changemaker

View File

@ -18,8 +18,33 @@ cardBlur: xl # xs, md,
headerStyle: boxed headerStyle: boxed
layout: layout:
style: columns # Production Tab Groups - displayed as vertical columns
columns: 3 Production - Essential Tools:
tab: Production
style: column
Production - Content & Docs:
tab: Production
style: column
Production - Automation:
tab: Production
style: column
Production - Monitoring:
tab: Production
style: column
# Local Development Tab Groups - displayed as vertical columns
Local - Essential Tools:
tab: Local
style: column
Local - Content & Docs:
tab: Local
style: column
Local - Automation:
tab: Local
style: column
Local - Monitoring:
tab: Local
style: column
docker: docker:
widget: widget:

0
configs/homepage/widgets.yaml Normal file → Executable file
View File

View File

@ -91,3 +91,145 @@ groups:
annotations: annotations:
summary: "High API latency" summary: "High API latency"
description: "95th percentile latency is {{ $value }}s for {{ $labels.route }}." description: "95th percentile latency is {{ $value }}s for {{ $labels.route }}."
# System health alerts
- name: system_alerts
interval: 30s
rules:
# NocoDB unreachable
- alert: NocoDBUnreachable
expr: up{job="nocodb"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "NocoDB database is unreachable"
description: "NocoDB has been unreachable for more than 2 minutes. All database operations will fail."
# Redis down
- alert: RedisDown
expr: redis_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Redis cache is down"
description: "Redis has been down for more than 1 minute. Caching and session management will fail."
# Disk space running low
- alert: DiskSpaceLow
expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.15
for: 5m
labels:
severity: warning
annotations:
summary: "Disk space is running low"
description: "Only {{ $value | humanizePercentage }} disk space remaining on root filesystem."
# Disk space critical
- alert: DiskSpaceCritical
expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.10
for: 2m
labels:
severity: critical
annotations:
summary: "CRITICAL: Disk space nearly exhausted"
description: "Only {{ $value | humanizePercentage }} disk space remaining! System may fail soon."
# High CPU usage
- alert: HighCPUUsage
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 10m
labels:
severity: warning
annotations:
summary: "High CPU usage detected"
description: "CPU usage is {{ $value }}% on {{ $labels.instance }}."
# Container CPU throttling
- alert: ContainerCPUThrottling
expr: rate(container_cpu_cfs_throttled_seconds_total[5m]) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "Container is being CPU throttled"
description: "Container {{ $labels.name }} is experiencing CPU throttling."
# Container memory usage high
- alert: ContainerMemoryHigh
expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) > 0.90
for: 5m
labels:
severity: warning
annotations:
summary: "Container memory usage is high"
description: "Container {{ $labels.name }} is using {{ $value | humanizePercentage }} of its memory limit."
# Infrastructure alerts
- name: infrastructure_alerts
interval: 30s
rules:
# Prometheus scrape failures
- alert: PrometheusScrapeFailures
expr: rate(prometheus_target_scrapes_failed_total[5m]) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "Prometheus scrape failures detected"
description: "Prometheus is failing to scrape {{ $labels.job }} target."
# Prometheus configuration reload failure
- alert: PrometheusConfigReloadFailed
expr: prometheus_config_last_reload_successful == 0
for: 1m
labels:
severity: warning
annotations:
summary: "Prometheus configuration reload failed"
description: "Prometheus failed to reload its configuration. Check prometheus logs."
# Alertmanager down
- alert: AlertmanagerDown
expr: up{job="alertmanager"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Alertmanager is down"
description: "Alertmanager has been down for 2 minutes. Alerts will not be delivered!"
# Security alerts
- name: security_alerts
interval: 15s
rules:
# Possible DDoS attack
- alert: PossibleDDoSAttack
expr: rate(influence_http_requests_total[1m]) > 1000
for: 2m
labels:
severity: critical
annotations:
summary: "Possible DDoS attack detected"
description: "Receiving {{ $value }} requests per second for 2 minutes. This may be a DDoS attack."
# Sustained high traffic
- alert: SustainedHighTraffic
expr: rate(influence_http_requests_total[5m]) > 500
for: 10m
labels:
severity: warning
annotations:
summary: "Sustained high traffic detected"
description: "Receiving {{ $value }} requests per second for 10 minutes. Monitor for performance issues."
# Too many 4xx errors
- alert: HighClientErrorRate
expr: rate(influence_http_requests_total{status_code=~"4.."}[5m]) > 5
for: 5m
labels:
severity: warning
annotations:
summary: "High rate of 4xx client errors"
description: "Receiving {{ $value }} client errors per second. Check for broken links or API misuse."

View File

@ -4,11 +4,11 @@ global:
external_labels: external_labels:
monitor: 'changemaker-lite' monitor: 'changemaker-lite'
# Alertmanager configuration (optional) # Alertmanager configuration
alerting: alerting:
alertmanagers: alertmanagers:
- static_configs: - static_configs:
- targets: [] - targets: ['alertmanager:9093']
# Load rules once and periodically evaluate them # Load rules once and periodically evaluate them
rule_files: rule_files:
@ -31,24 +31,31 @@ scrape_configs:
metrics_path: '/metrics' metrics_path: '/metrics'
scrape_interval: 30s scrape_interval: 30s
# Redis Metrics (requires redis_exporter - optional) # Redis Metrics
# Uncomment and add redis_exporter service to enable - job_name: 'redis'
# - job_name: 'redis' static_configs:
# static_configs: - targets: ['redis-exporter:9121']
# - targets: ['redis-exporter:9121'] scrape_interval: 15s
# Listmonk Metrics (if available) # cAdvisor - Docker container metrics
# - job_name: 'listmonk' - job_name: 'cadvisor'
# static_configs: static_configs:
# - targets: ['listmonk-app:9000'] - targets: ['cadvisor:8080']
# metrics_path: '/metrics' scrape_interval: 15s
# Node Exporter - System metrics
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
scrape_interval: 15s
# Prometheus self-monitoring # Prometheus self-monitoring
- job_name: 'prometheus' - job_name: 'prometheus'
static_configs: static_configs:
- targets: ['localhost:9090'] - targets: ['localhost:9090']
# Docker container metrics (requires cAdvisor - optional) # Alertmanager monitoring
# - job_name: 'cadvisor' - job_name: 'alertmanager'
# static_configs: static_configs:
# - targets: ['cadvisor:8080'] - targets: ['alertmanager:9093']
scrape_interval: 30s

View File

@ -21,16 +21,16 @@ services:
- "${CODE_SERVER_PORT:-8888}:8080" - "${CODE_SERVER_PORT:-8888}:8080"
restart: unless-stopped restart: unless-stopped
networks: networks:
- changemaker-lite-test4 - changemaker-lite
listmonk-app: listmonk-app:
image: listmonk/listmonk:latest image: listmonk/listmonk:latest
container_name: listmonk_app_test4-test4 container_name: listmonk_app_test4
restart: unless-stopped restart: unless-stopped
ports: ports:
- "${LISTMONK_PORT:-9001}:9000" - "${LISTMONK_PORT:-9001}:9000"
networks: networks:
- changemaker-lite-test4 - changemaker-lite
hostname: ${LISTMONK_HOSTNAME} hostname: ${LISTMONK_HOSTNAME}
depends_on: depends_on:
- listmonk-db - listmonk-db
@ -54,12 +54,12 @@ services:
listmonk-db: listmonk-db:
image: postgres:17-alpine image: postgres:17-alpine
container_name: listmonk_db_test4-test4 container_name: listmonk_db_test4
restart: unless-stopped restart: unless-stopped
ports: ports:
- "127.0.0.1:${LISTMONK_DB_PORT:-5432}:5432" - "127.0.0.1:${LISTMONK_DB_PORT:-5432}:5432"
networks: networks:
- changemaker-lite-test4 - changemaker-lite
environment: environment:
<<: *db-credentials <<: *db-credentials
healthcheck: healthcheck:
@ -69,12 +69,12 @@ services:
retries: 6 retries: 6
volumes: volumes:
- type: volume - type: volume
source: listmonk-data-test4 source: listmonk-data
target: /var/lib/postgresql/data target: /var/lib/postgresql/data
mkdocs: mkdocs:
image: squidfunk/mkdocs-material image: squidfunk/mkdocs-material
container_name: mkdocs-changemaker-test4 container_name: mkdocs-changemaker
volumes: volumes:
- ./mkdocs:/docs:rw - ./mkdocs:/docs:rw
- ./assets/images:/docs/assets/images:rw - ./assets/images:/docs/assets/images:rw
@ -85,7 +85,7 @@ services:
- SITE_URL=${BASE_DOMAIN:-https://changeme.org} - SITE_URL=${BASE_DOMAIN:-https://changeme.org}
command: serve --dev-addr=0.0.0.0:8000 --watch-theme --livereload command: serve --dev-addr=0.0.0.0:8000 --watch-theme --livereload
networks: networks:
- changemaker-lite-test4 - changemaker-lite
restart: unless-stopped restart: unless-stopped
mkdocs-site-server: mkdocs-site-server:
@ -102,11 +102,11 @@ services:
- "${MKDOCS_SITE_SERVER_PORT:-4001}:80" - "${MKDOCS_SITE_SERVER_PORT:-4001}:80"
restart: unless-stopped restart: unless-stopped
networks: networks:
- changemaker-lite-test4 - changemaker-lite
n8n: n8n:
image: docker.n8n.io/n8nio/n8n image: docker.n8n.io/n8nio/n8n
container_name: n8n-changemaker-test4 container_name: n8n-changemaker
restart: unless-stopped restart: unless-stopped
ports: ports:
- "${N8N_PORT:-5678}:5678" - "${N8N_PORT:-5678}:5678"
@ -125,7 +125,7 @@ services:
- n8n_data_test4:/home/node/.n8n - n8n_data_test4:/home/node/.n8n
- ./local-files:/files - ./local-files:/files
networks: networks:
- changemaker-lite-test4 - changemaker-lite
nocodb: nocodb:
depends_on: depends_on:
@ -140,7 +140,7 @@ services:
volumes: volumes:
- "nc_data_test4:/usr/app/data" - "nc_data_test4:/usr/app/data"
networks: networks:
- changemaker-lite-test4 - changemaker-lite
root_db: root_db:
environment: environment:
POSTGRES_DB: root_db POSTGRES_DB: root_db
@ -156,12 +156,12 @@ services:
volumes: volumes:
- "db_data_test4:/var/lib/postgresql/data" - "db_data_test4:/var/lib/postgresql/data"
networks: networks:
- changemaker-lite-test4 - changemaker-lite
# Homepage App # Homepage App
homepage-changemaker: homepage-changemaker:
image: ghcr.io/gethomepage/homepage:latest image: ghcr.io/gethomepage/homepage:latest
container_name: homepage-changemaker-test4 container_name: homepage-changemaker
ports: ports:
- "${HOMEPAGE_PORT:-3010}:3000" - "${HOMEPAGE_PORT:-3010}:3000"
volumes: volumes:
@ -177,12 +177,12 @@ services:
- HOMEPAGE_VAR_BASE_URL=${HOMEPAGE_VAR_BASE_URL:-http://localhost} - HOMEPAGE_VAR_BASE_URL=${HOMEPAGE_VAR_BASE_URL:-http://localhost}
restart: unless-stopped restart: unless-stopped
networks: networks:
- changemaker-lite-test4 - changemaker-lite
# Gitea - Git service # Gitea - Git service
gitea-app: gitea-app:
image: gitea/gitea:1.23.7 image: gitea/gitea:1.23.7
container_name: gitea_changemaker_test4-test4 container_name: gitea_changemaker_test4
environment: environment:
- USER_UID=${USER_ID:-1000} - USER_UID=${USER_ID:-1000}
- USER_GID=${GROUP_ID:-1000} - USER_GID=${GROUP_ID:-1000}
@ -201,7 +201,7 @@ services:
- GITEA__server__PROXY_ALLOW_SUBNET=0.0.0.0/0 - GITEA__server__PROXY_ALLOW_SUBNET=0.0.0.0/0
restart: unless-stopped restart: unless-stopped
networks: networks:
- changemaker-lite-test4 - changemaker-lite
volumes: volumes:
- gitea_data_test4:/data - gitea_data_test4:/data
- /etc/timezone:/etc/timezone:ro - /etc/timezone:/etc/timezone:ro
@ -214,7 +214,7 @@ services:
gitea-db: gitea-db:
image: mysql:8 image: mysql:8
container_name: gitea_mysql_changemaker_test4_test4-test4 container_name: gitea_mysql_changemaker_test4_test4
restart: unless-stopped restart: unless-stopped
environment: environment:
- MYSQL_ROOT_PASSWORD=${GITEA_DB_ROOT_PASSWORD} - MYSQL_ROOT_PASSWORD=${GITEA_DB_ROOT_PASSWORD}
@ -222,7 +222,7 @@ services:
- MYSQL_PASSWORD=${GITEA_DB_PASSWD} - MYSQL_PASSWORD=${GITEA_DB_PASSWD}
- MYSQL_DATABASE=${GITEA_DB_NAME:-gitea} - MYSQL_DATABASE=${GITEA_DB_NAME:-gitea}
networks: networks:
- changemaker-lite-test4 - changemaker-lite
volumes: volumes:
- mysql_data_test4:/var/lib/mysql - mysql_data_test4:/var/lib/mysql
healthcheck: healthcheck:
@ -238,17 +238,17 @@ services:
- "${MINI_QR_PORT:-8089}:8080" - "${MINI_QR_PORT:-8089}:8080"
restart: unless-stopped restart: unless-stopped
networks: networks:
- changemaker-lite-test4 - changemaker-lite
# Shared Redis - Used by all services for caching, queues, sessions # Shared Redis - Used by all services for caching, queues, sessions
redis: redis:
image: redis:7-alpine image: redis:7-alpine
container_name: redis-changemaker-test4 container_name: redis-changemaker
command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
ports: ports:
- "6379:6379" - "6379:6379"
volumes: volumes:
- redis-data-test4:/data - redis-data:/data
restart: always restart: always
healthcheck: healthcheck:
test: ["CMD", "redis-cli", "ping"] test: ["CMD", "redis-cli", "ping"]
@ -264,7 +264,7 @@ services:
cpus: '0.25' cpus: '0.25'
memory: 256M memory: 256M
networks: networks:
- changemaker-lite-test4 - changemaker-lite
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
@ -274,7 +274,7 @@ services:
# Prometheus - Metrics collection for all services # Prometheus - Metrics collection for all services
prometheus: prometheus:
image: prom/prometheus:latest image: prom/prometheus:latest
container_name: prometheus-changemaker-test4 container_name: prometheus-changemaker
command: command:
- '--config.file=/etc/prometheus/prometheus.yml' - '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus' - '--storage.tsdb.path=/prometheus'
@ -283,17 +283,17 @@ services:
- "${PROMETHEUS_PORT:-9090}:9090" - "${PROMETHEUS_PORT:-9090}:9090"
volumes: volumes:
- ./configs/prometheus:/etc/prometheus - ./configs/prometheus:/etc/prometheus
- prometheus-data-test4:/prometheus - prometheus-data:/prometheus
restart: always restart: always
networks: networks:
- changemaker-lite-test4 - changemaker-lite
profiles: profiles:
- monitoring - monitoring
# Grafana - Metrics visualization for all services # Grafana - Metrics visualization for all services
grafana: grafana:
image: grafana/grafana:latest image: grafana/grafana:latest
container_name: grafana-changemaker-test4 container_name: grafana-changemaker
ports: ports:
- "${GRAFANA_PORT:-3001}:3000" - "${GRAFANA_PORT:-3001}:3000"
environment: environment:
@ -301,13 +301,107 @@ services:
- GF_USERS_ALLOW_SIGN_UP=false - GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL:-http://localhost:3001} - GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL:-http://localhost:3001}
volumes: volumes:
- grafana-data-test4:/var/lib/grafana - grafana-data:/var/lib/grafana
- ./configs/grafana:/etc/grafana/provisioning - ./configs/grafana:/etc/grafana/provisioning
restart: always restart: always
depends_on: depends_on:
- prometheus - prometheus
networks: networks:
- changemaker-lite-test4 - changemaker-lite
profiles:
- monitoring
# cAdvisor - Container metrics exporter for Docker
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor-changemaker
ports:
- "${CADVISOR_PORT:-8080}:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
privileged: true
devices:
- /dev/kmsg
restart: always
networks:
- changemaker-lite
profiles:
- monitoring
# Node Exporter - System metrics exporter
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter-changemaker
ports:
- "${NODE_EXPORTER_PORT:-9100}:9100"
command:
- '--path.rootfs=/host'
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
restart: always
networks:
- changemaker-lite
profiles:
- monitoring
# Redis Exporter - Redis metrics exporter
redis-exporter:
image: oliver006/redis_exporter:latest
container_name: redis-exporter-changemaker
ports:
- "${REDIS_EXPORTER_PORT:-9121}:9121"
environment:
- REDIS_ADDR=redis:6379
restart: always
depends_on:
- redis
networks:
- changemaker-lite
profiles:
- monitoring
# Alertmanager - Alert routing and notification
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager-changemaker
ports:
- "${ALERTMANAGER_PORT:-9093}:9093"
volumes:
- ./configs/alertmanager:/etc/alertmanager
- alertmanager-data:/alertmanager
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
- '--storage.path=/alertmanager'
restart: always
networks:
- changemaker-lite
profiles:
- monitoring
# Gotify - Self-hosted push notification service
gotify:
image: gotify/server:latest
container_name: gotify-changemaker
ports:
- "${GOTIFY_PORT:-8889}:80"
environment:
- GOTIFY_DEFAULTUSER_NAME=${GOTIFY_ADMIN_USER:-admin}
- GOTIFY_DEFAULTUSER_PASS=${GOTIFY_ADMIN_PASSWORD:-admin}
- TZ=Etc/UTC
volumes:
- gotify-data:/app/data
restart: always
networks:
- changemaker-lite
profiles: profiles:
- monitoring - monitoring
@ -317,13 +411,13 @@ services:
# SMTP: mailhog-changemaker:1025 # SMTP: mailhog-changemaker:1025
mailhog: mailhog:
image: mailhog/mailhog:latest image: mailhog/mailhog:latest
container_name: mailhog-changemaker-test4 container_name: mailhog-changemaker
ports: ports:
- "1025:1025" # SMTP server - "1025:1025" # SMTP server
- "8025:8025" # Web UI - "8025:8025" # Web UI
restart: unless-stopped restart: unless-stopped
networks: networks:
- changemaker-lite-test4 - changemaker-lite
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
@ -331,16 +425,18 @@ services:
max-file: "2" max-file: "2"
networks: networks:
changemaker-lite-test4: changemaker-lite:
driver: bridge driver: bridge
volumes: volumes:
listmonk-data-test4: listmonk-data:
n8n_data_test4: n8n_data_test4:
nc_data_test4: nc_data_test4:
db_data_test4: db_data_test4:
gitea_data_test4: gitea_data_test4:
mysql_data_test4: mysql_data_test4:
redis-data-test4: redis-data:
prometheus-data-test4: prometheus-data:
grafana-data-test4: grafana-data:
alertmanager-data:
gotify-data:

118
fix-permissions.sh Executable file
View File

@ -0,0 +1,118 @@
#!/bin/bash
# Fix Container Directory Permissions
# Run this script if you encounter EACCES (permission denied) errors
# when starting Docker containers.
cat << "EOF"
╔═══════════════════════════════════════════════════╗
║ Changemaker - Fix Container Permissions ║
╚═══════════════════════════════════════════════════╝
EOF
# Get the absolute path of the script directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Get the user/group IDs from .env or use defaults
if [ -f "$SCRIPT_DIR/.env" ]; then
source <(grep -E '^(USER_ID|GROUP_ID)=' "$SCRIPT_DIR/.env")
fi
USER_ID=${USER_ID:-1000}
GROUP_ID=${GROUP_ID:-1000}
echo ""
echo "Using UID: $USER_ID, GID: $GROUP_ID"
echo ""
# Define directories that need to be writable by containers
declare -A writable_dirs=(
["$SCRIPT_DIR/configs/code-server/.config"]="Code Server config"
["$SCRIPT_DIR/configs/code-server/.local"]="Code Server local data"
["$SCRIPT_DIR/mkdocs/.cache"]="MkDocs cache (social cards, etc.)"
["$SCRIPT_DIR/mkdocs/site"]="MkDocs built site"
["$SCRIPT_DIR/assets/uploads"]="Listmonk uploads"
["$SCRIPT_DIR/assets/images"]="Shared images"
["$SCRIPT_DIR/configs/homepage/logs"]="Homepage logs"
)
errors=0
fixed=0
needs_sudo=()
echo "Checking and fixing directory permissions..."
echo ""
for dir_path in "${!writable_dirs[@]}"; do
dir_desc="${writable_dirs[$dir_path]}"
# Create directory if it doesn't exist
if [ ! -d "$dir_path" ]; then
echo " Creating: $dir_path"
mkdir -p "$dir_path"
fi
# Add .gitkeep to track empty directories in git
if [ ! -f "$dir_path/.gitkeep" ]; then
touch "$dir_path/.gitkeep" 2>/dev/null
fi
# Try to fix permissions
if chmod -R 777 "$dir_path" 2>/dev/null; then
echo "$dir_desc"
((fixed++))
else
echo " ⚠️ $dir_desc - needs sudo"
needs_sudo+=("$dir_path")
((errors++))
fi
done
echo ""
# If there are directories that need sudo, offer to fix them
if [ ${#needs_sudo[@]} -gt 0 ]; then
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Some directories need elevated permissions to fix."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
read -p "Would you like to fix them with sudo? [Y/n]: " use_sudo
if [[ ! "$use_sudo" =~ ^[Nn]$ ]]; then
echo ""
for dir_path in "${needs_sudo[@]}"; do
dir_desc="${writable_dirs[$dir_path]}"
echo " Fixing: $dir_desc"
# First try to change ownership, then permissions
if sudo chown -R "$USER_ID:$GROUP_ID" "$dir_path" 2>/dev/null && \
sudo chmod -R 777 "$dir_path" 2>/dev/null; then
echo " ✅ Fixed: $dir_desc"
((fixed++))
((errors--))
else
echo " ❌ Failed: $dir_desc"
fi
done
fi
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Summary"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Fixed: $fixed directories"
if [ $errors -gt 0 ]; then
echo " Errors: $errors directories still need attention"
echo ""
echo "To manually fix remaining issues, run:"
echo " sudo chown -R $USER_ID:$GROUP_ID $SCRIPT_DIR"
echo " sudo chmod -R 755 $SCRIPT_DIR"
exit 1
else
echo ""
echo "✅ All container directories are properly configured!"
echo ""
echo "You can now start your containers with:"
echo " docker compose up -d"
fi

0
mkdocs/.cache/.gitkeep Normal file
View File

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/18pt Black.ttf Normal file → Executable file
View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/18pt Bold.ttf Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/18pt Light.ttf Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/18pt Thin.ttf Normal file → Executable file
View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/24pt Black.ttf Normal file → Executable file
View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/24pt Bold.ttf Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/24pt Light.ttf Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/24pt Thin.ttf Normal file → Executable file
View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/28pt Black.ttf Normal file → Executable file
View File

View File

0
mkdocs/.cache/plugin/social/fonts/Inter/28pt Bold.ttf Normal file → Executable file
View File

View File

View File

View File

View File

View File

Some files were not shown because too many files have changed in this diff Show More