Bunch of monitoring services added. Need to work through all the configuration next.
10
.gitignore
vendored
@ -4,6 +4,16 @@
|
||||
/configs/code-server/.config/*
|
||||
!/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*
|
||||
|
||||
|
||||
33
README.md
@ -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.
|
||||
|
||||
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
163
config.sh
@ -82,6 +82,85 @@ backup_env_file() {
|
||||
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
|
||||
get_used_ports() {
|
||||
local used_ports=()
|
||||
@ -188,6 +267,11 @@ initialize_available_ports() {
|
||||
["REDIS_PORT"]=6379
|
||||
["PROMETHEUS_PORT"]=9090
|
||||
["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
|
||||
@ -260,6 +344,15 @@ REDIS_PORT=${REDIS_PORT:-6379}
|
||||
PROMETHEUS_PORT=${PROMETHEUS_PORT:-9090}
|
||||
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
|
||||
BASE_DOMAIN=https://changeme.org
|
||||
DOMAIN=changeme.org
|
||||
@ -324,6 +417,24 @@ PROMETHEUS_RETENTION_TIME=30d
|
||||
GRAFANA_PORT=3001
|
||||
GRAFANA_ADMIN_USER=admin
|
||||
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
|
||||
|
||||
echo "New .env file created with conflict-free port assignments."
|
||||
@ -349,6 +460,13 @@ EOL
|
||||
echo "Redis: ${REDIS_PORT:-6379}"
|
||||
echo "Prometheus: ${PROMETHEUS_PORT:-9090}"
|
||||
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 "================================"
|
||||
}
|
||||
|
||||
@ -413,6 +531,9 @@ update_services_yaml() {
|
||||
["Gitea"]="git.$new_domain"
|
||||
["Prometheus"]="prometheus.$new_domain"
|
||||
["Grafana"]="grafana.$new_domain"
|
||||
["Alertmanager"]="alertmanager.$new_domain"
|
||||
["Gotify"]="gotify.$new_domain"
|
||||
["cAdvisor"]="cadvisor.$new_domain"
|
||||
)
|
||||
|
||||
# Process each service mapping
|
||||
@ -573,6 +694,15 @@ ingress:
|
||||
- hostname: grafana.$new_domain
|
||||
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)
|
||||
- service: http_status:404
|
||||
EOL
|
||||
@ -862,6 +992,11 @@ check_port_conflicts() {
|
||||
"REDIS_PORT"
|
||||
"PROMETHEUS_PORT"
|
||||
"GRAFANA_PORT"
|
||||
"CADVISOR_PORT"
|
||||
"NODE_EXPORTER_PORT"
|
||||
"REDIS_EXPORTER_PORT"
|
||||
"ALERTMANAGER_PORT"
|
||||
"GOTIFY_PORT"
|
||||
)
|
||||
|
||||
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 "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!"
|
||||
|
||||
# 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)
|
||||
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."
|
||||
|
||||
# Fix container directory permissions before finishing
|
||||
fix_container_permissions
|
||||
|
||||
echo -e "\n✅ Configuration completed successfully!"
|
||||
echo "Your .env file has been configured with:"
|
||||
echo "- Instance ID: $instance_identifier"
|
||||
@ -1242,7 +1387,9 @@ echo "- Listmonk Admin: $listmonk_user"
|
||||
echo "- N8N Admin Email: $n8n_email"
|
||||
echo "- Secure random passwords for database, encryption, and NocoDB"
|
||||
echo "- Grafana Admin Password: Generated (see .env file)"
|
||||
echo "- Gotify Admin Password: Generated (see .env file)"
|
||||
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 -e "\nYour .env file is located at: $ENV_FILE"
|
||||
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 " - Mini QR: http://localhost:${MINI_QR_PORT:-8089}"
|
||||
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 " - 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 " To start with monitoring:"
|
||||
echo " docker compose --profile monitoring up -d"
|
||||
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 " ./start-production.sh"
|
||||
echo ""
|
||||
|
||||
100
configs/alertmanager/alertmanager.yml
Normal 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
0
configs/code-server/.local/.gitkeep
Normal file → Executable file
509
configs/grafana/system-health.json
Normal 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
5
configs/homepage/proxmox.yaml
Executable 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
@ -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:
|
||||
icon: mdi-code-braces
|
||||
href: "https://code.cmlite.org"
|
||||
href: "https://code.bnkserve.org"
|
||||
description: VS Code in the browser - Platform Editor
|
||||
container: code-server-changemaker
|
||||
|
||||
|
||||
- NocoDB:
|
||||
icon: mdi-database
|
||||
href: "https://db.cmlite.org"
|
||||
href: "https://db.bnkserve.org"
|
||||
description: No-code database platform
|
||||
container: changemakerlite-nocodb-1
|
||||
|
||||
|
||||
- Map Server:
|
||||
icon: mdi-map
|
||||
href: "https://map.cmlite.org"
|
||||
href: "https://map.bnkserve.org"
|
||||
description: Map server for geospatial data
|
||||
container: nocodb-map-viewer
|
||||
|
||||
|
||||
- Influence:
|
||||
icon: mdi-account-group
|
||||
href: "https://influence.cmlite.org"
|
||||
href: "https://influence.bnkserve.org"
|
||||
description: Political influence and campaign management
|
||||
container: influence-app-1
|
||||
|
||||
|
||||
- Content & Documentation:
|
||||
- Main Site:
|
||||
- Production - Content & Docs:
|
||||
|
||||
- Main Site:
|
||||
icon: mdi-web
|
||||
href: "https://cmlite.org"
|
||||
href: "https://bnkserve.org"
|
||||
description: CM-lite campaign website
|
||||
container: mkdocs-site-server-changemaker
|
||||
|
||||
|
||||
- MkDocs (Live):
|
||||
icon: mdi-book-open-page-variant
|
||||
href: "https://docs.cmlite.org"
|
||||
description: Live documentation server with hot reload
|
||||
container: mkdocs-changemaker
|
||||
|
||||
|
||||
- Mini QR:
|
||||
icon: mdi-qrcode
|
||||
href: "https://qr.cmlite.org"
|
||||
href: "https://qr.bnkserve.org"
|
||||
description: QR code generator
|
||||
container: mini-qr
|
||||
|
||||
|
||||
- Listmonk:
|
||||
icon: mdi-email-newsletter
|
||||
href: "https://listmonk.cmlite.org"
|
||||
href: "https://listmonk.bnkserve.org"
|
||||
description: Newsletter & mailing list manager
|
||||
container: listmonk_app
|
||||
|
||||
- Automation & Infrastructure:
|
||||
|
||||
- Production - Automation:
|
||||
|
||||
- n8n:
|
||||
icon: mdi-robot-industrial
|
||||
href: "https://n8n.cmlite.org"
|
||||
href: "https://n8n.bnkserve.org"
|
||||
description: Workflow automation platform
|
||||
container: n8n-changemaker
|
||||
|
||||
|
||||
- Gitea:
|
||||
icon: mdi-git
|
||||
href: "https://git.bnkserve.org"
|
||||
description: Git repository hosting
|
||||
container: gitea_changemaker
|
||||
|
||||
- PostgreSQL (Listmonk):
|
||||
icon: mdi-database-outline
|
||||
href: "#"
|
||||
description: Database for Listmonk
|
||||
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
|
||||
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:
|
||||
icon: mdi-git
|
||||
href: "https://git.cmlite.org"
|
||||
description: Git repository hosting
|
||||
href: "http://localhost:3030"
|
||||
description: Git repository hosting (port 3030)
|
||||
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
|
||||
|
||||
@ -18,8 +18,33 @@ cardBlur: xl # xs, md,
|
||||
headerStyle: boxed
|
||||
|
||||
layout:
|
||||
style: columns
|
||||
columns: 3
|
||||
# Production Tab Groups - displayed as vertical columns
|
||||
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:
|
||||
widget:
|
||||
|
||||
0
configs/homepage/widgets.yaml
Normal file → Executable file
@ -91,3 +91,145 @@ groups:
|
||||
annotations:
|
||||
summary: "High API latency"
|
||||
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."
|
||||
|
||||
@ -4,11 +4,11 @@ global:
|
||||
external_labels:
|
||||
monitor: 'changemaker-lite'
|
||||
|
||||
# Alertmanager configuration (optional)
|
||||
# Alertmanager configuration
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets: []
|
||||
- targets: ['alertmanager:9093']
|
||||
|
||||
# Load rules once and periodically evaluate them
|
||||
rule_files:
|
||||
@ -31,24 +31,31 @@ scrape_configs:
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 30s
|
||||
|
||||
# Redis Metrics (requires redis_exporter - optional)
|
||||
# Uncomment and add redis_exporter service to enable
|
||||
# - job_name: 'redis'
|
||||
# static_configs:
|
||||
# - targets: ['redis-exporter:9121']
|
||||
# Redis Metrics
|
||||
- job_name: 'redis'
|
||||
static_configs:
|
||||
- targets: ['redis-exporter:9121']
|
||||
scrape_interval: 15s
|
||||
|
||||
# Listmonk Metrics (if available)
|
||||
# - job_name: 'listmonk'
|
||||
# static_configs:
|
||||
# - targets: ['listmonk-app:9000']
|
||||
# metrics_path: '/metrics'
|
||||
# cAdvisor - Docker container metrics
|
||||
- job_name: 'cadvisor'
|
||||
static_configs:
|
||||
- targets: ['cadvisor:8080']
|
||||
scrape_interval: 15s
|
||||
|
||||
# Node Exporter - System metrics
|
||||
- job_name: 'node'
|
||||
static_configs:
|
||||
- targets: ['node-exporter:9100']
|
||||
scrape_interval: 15s
|
||||
|
||||
# Prometheus self-monitoring
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
# Docker container metrics (requires cAdvisor - optional)
|
||||
# - job_name: 'cadvisor'
|
||||
# static_configs:
|
||||
# - targets: ['cadvisor:8080']
|
||||
# Alertmanager monitoring
|
||||
- job_name: 'alertmanager'
|
||||
static_configs:
|
||||
- targets: ['alertmanager:9093']
|
||||
scrape_interval: 30s
|
||||
|
||||
@ -21,16 +21,16 @@ services:
|
||||
- "${CODE_SERVER_PORT:-8888}:8080"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
|
||||
listmonk-app:
|
||||
image: listmonk/listmonk:latest
|
||||
container_name: listmonk_app_test4-test4
|
||||
container_name: listmonk_app_test4
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${LISTMONK_PORT:-9001}:9000"
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
hostname: ${LISTMONK_HOSTNAME}
|
||||
depends_on:
|
||||
- listmonk-db
|
||||
@ -54,12 +54,12 @@ services:
|
||||
|
||||
listmonk-db:
|
||||
image: postgres:17-alpine
|
||||
container_name: listmonk_db_test4-test4
|
||||
container_name: listmonk_db_test4
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:${LISTMONK_DB_PORT:-5432}:5432"
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
environment:
|
||||
<<: *db-credentials
|
||||
healthcheck:
|
||||
@ -69,12 +69,12 @@ services:
|
||||
retries: 6
|
||||
volumes:
|
||||
- type: volume
|
||||
source: listmonk-data-test4
|
||||
source: listmonk-data
|
||||
target: /var/lib/postgresql/data
|
||||
|
||||
mkdocs:
|
||||
image: squidfunk/mkdocs-material
|
||||
container_name: mkdocs-changemaker-test4
|
||||
container_name: mkdocs-changemaker
|
||||
volumes:
|
||||
- ./mkdocs:/docs:rw
|
||||
- ./assets/images:/docs/assets/images:rw
|
||||
@ -85,7 +85,7 @@ services:
|
||||
- SITE_URL=${BASE_DOMAIN:-https://changeme.org}
|
||||
command: serve --dev-addr=0.0.0.0:8000 --watch-theme --livereload
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
restart: unless-stopped
|
||||
|
||||
mkdocs-site-server:
|
||||
@ -102,11 +102,11 @@ services:
|
||||
- "${MKDOCS_SITE_SERVER_PORT:-4001}:80"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n
|
||||
container_name: n8n-changemaker-test4
|
||||
container_name: n8n-changemaker
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${N8N_PORT:-5678}:5678"
|
||||
@ -125,7 +125,7 @@ services:
|
||||
- n8n_data_test4:/home/node/.n8n
|
||||
- ./local-files:/files
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
|
||||
nocodb:
|
||||
depends_on:
|
||||
@ -140,7 +140,7 @@ services:
|
||||
volumes:
|
||||
- "nc_data_test4:/usr/app/data"
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
root_db:
|
||||
environment:
|
||||
POSTGRES_DB: root_db
|
||||
@ -156,12 +156,12 @@ services:
|
||||
volumes:
|
||||
- "db_data_test4:/var/lib/postgresql/data"
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
|
||||
# Homepage App
|
||||
homepage-changemaker:
|
||||
image: ghcr.io/gethomepage/homepage:latest
|
||||
container_name: homepage-changemaker-test4
|
||||
container_name: homepage-changemaker
|
||||
ports:
|
||||
- "${HOMEPAGE_PORT:-3010}:3000"
|
||||
volumes:
|
||||
@ -177,12 +177,12 @@ services:
|
||||
- HOMEPAGE_VAR_BASE_URL=${HOMEPAGE_VAR_BASE_URL:-http://localhost}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
|
||||
# Gitea - Git service
|
||||
gitea-app:
|
||||
image: gitea/gitea:1.23.7
|
||||
container_name: gitea_changemaker_test4-test4
|
||||
container_name: gitea_changemaker_test4
|
||||
environment:
|
||||
- USER_UID=${USER_ID:-1000}
|
||||
- USER_GID=${GROUP_ID:-1000}
|
||||
@ -201,7 +201,7 @@ services:
|
||||
- GITEA__server__PROXY_ALLOW_SUBNET=0.0.0.0/0
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
volumes:
|
||||
- gitea_data_test4:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
@ -214,7 +214,7 @@ services:
|
||||
|
||||
gitea-db:
|
||||
image: mysql:8
|
||||
container_name: gitea_mysql_changemaker_test4_test4-test4
|
||||
container_name: gitea_mysql_changemaker_test4_test4
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${GITEA_DB_ROOT_PASSWORD}
|
||||
@ -222,7 +222,7 @@ services:
|
||||
- MYSQL_PASSWORD=${GITEA_DB_PASSWD}
|
||||
- MYSQL_DATABASE=${GITEA_DB_NAME:-gitea}
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
volumes:
|
||||
- mysql_data_test4:/var/lib/mysql
|
||||
healthcheck:
|
||||
@ -238,17 +238,17 @@ services:
|
||||
- "${MINI_QR_PORT:-8089}:8080"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
|
||||
# Shared Redis - Used by all services for caching, queues, sessions
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: redis-changemaker-test4
|
||||
container_name: redis-changemaker
|
||||
command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data-test4:/data
|
||||
- redis-data:/data
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
@ -264,7 +264,7 @@ services:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
@ -274,7 +274,7 @@ services:
|
||||
# Prometheus - Metrics collection for all services
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus-changemaker-test4
|
||||
container_name: prometheus-changemaker
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
@ -283,17 +283,17 @@ services:
|
||||
- "${PROMETHEUS_PORT:-9090}:9090"
|
||||
volumes:
|
||||
- ./configs/prometheus:/etc/prometheus
|
||||
- prometheus-data-test4:/prometheus
|
||||
- prometheus-data:/prometheus
|
||||
restart: always
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
profiles:
|
||||
- monitoring
|
||||
|
||||
# Grafana - Metrics visualization for all services
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana-changemaker-test4
|
||||
container_name: grafana-changemaker
|
||||
ports:
|
||||
- "${GRAFANA_PORT:-3001}:3000"
|
||||
environment:
|
||||
@ -301,13 +301,107 @@ services:
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL:-http://localhost:3001}
|
||||
volumes:
|
||||
- grafana-data-test4:/var/lib/grafana
|
||||
- grafana-data:/var/lib/grafana
|
||||
- ./configs/grafana:/etc/grafana/provisioning
|
||||
restart: always
|
||||
depends_on:
|
||||
- prometheus
|
||||
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:
|
||||
- monitoring
|
||||
|
||||
@ -317,13 +411,13 @@ services:
|
||||
# SMTP: mailhog-changemaker:1025
|
||||
mailhog:
|
||||
image: mailhog/mailhog:latest
|
||||
container_name: mailhog-changemaker-test4
|
||||
container_name: mailhog-changemaker
|
||||
ports:
|
||||
- "1025:1025" # SMTP server
|
||||
- "8025:8025" # Web UI
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- changemaker-lite-test4
|
||||
- changemaker-lite
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
@ -331,16 +425,18 @@ services:
|
||||
max-file: "2"
|
||||
|
||||
networks:
|
||||
changemaker-lite-test4:
|
||||
changemaker-lite:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
listmonk-data-test4:
|
||||
listmonk-data:
|
||||
n8n_data_test4:
|
||||
nc_data_test4:
|
||||
db_data_test4:
|
||||
gitea_data_test4:
|
||||
mysql_data_test4:
|
||||
redis-data-test4:
|
||||
prometheus-data-test4:
|
||||
grafana-data-test4:
|
||||
redis-data:
|
||||
prometheus-data:
|
||||
grafana-data:
|
||||
alertmanager-data:
|
||||
gotify-data:
|
||||
118
fix-permissions.sh
Executable 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
0
mkdocs/.cache/plugin/social/09bbbc93a961c0990fa7e3217673978f.png
Normal file → Executable file
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
0
mkdocs/.cache/plugin/social/10a5546a448a8a0b16de3eb978f8a68f.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/2030a47afa1104093ebf519a6f22a7d1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
0
mkdocs/.cache/plugin/social/3df345a41836bfa1f24aa074839aff71.png
Normal file → Executable file
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
0
mkdocs/.cache/plugin/social/461dbf70704556ebdba00d9b93fdd71a.png
Normal file → Executable file
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
0
mkdocs/.cache/plugin/social/499785a5782a92d89dee51c0bf8b6995.png
Normal file → Executable file
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
0
mkdocs/.cache/plugin/social/49f28fa8303f79b46bfb7904c8e551a1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
0
mkdocs/.cache/plugin/social/4fec9fd5349ccccf8012393802a1a5bd.png
Normal file → Executable file
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
0
mkdocs/.cache/plugin/social/513e74590c0aaa12f169c3f283993a05.png
Normal file → Executable file
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
0
mkdocs/.cache/plugin/social/5a026625721699a22ed4902c86e27264.png
Normal file → Executable file
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
0
mkdocs/.cache/plugin/social/5c8323641288ce96dac5e5d0c03d1d88.png
Normal file → Executable file
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
0
mkdocs/.cache/plugin/social/5de16fced5aba77a2bd09132eb5fda0d.png
Normal file → Executable file
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
0
mkdocs/.cache/plugin/social/62372a9d5b433f883e1358d69aafb99d.png
Normal file → Executable file
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
0
mkdocs/.cache/plugin/social/630ed53169b0d638a0ecbc5a43b36dd5.png
Normal file → Executable file
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
0
mkdocs/.cache/plugin/social/63fe0d7764ab46b6b1a896c92f5f08ad.png
Normal file → Executable file
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
0
mkdocs/.cache/plugin/social/6e0a466e141c6410aa3b931db727ad5a.png
Normal file → Executable file
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
0
mkdocs/.cache/plugin/social/6ff7c9a84364b85f150bfe85d21a1db8.png
Normal file → Executable file
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
0
mkdocs/.cache/plugin/social/72eda47b0bb6ddeeba9c715ee9d857ab.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/7b06061b4b9b4a82384b4b9cf809471d.png
Normal file → Executable file
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
0
mkdocs/.cache/plugin/social/7ca622286d4c40d181cd6c809308aadd.png
Normal file → Executable file
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
0
mkdocs/.cache/plugin/social/7cc7e1ec8732cd69b83aa549bfb13cc3.png
Normal file → Executable file
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
0
mkdocs/.cache/plugin/social/89cb9170565057569d85b76ef729d173.png
Normal file → Executable file
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
0
mkdocs/.cache/plugin/social/8b4d2b2992e85f6cc7dcfc9a7eb7c502.png
Normal file → Executable file
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
0
mkdocs/.cache/plugin/social/8e08f754f4d8c04a82391ae575aafaaa.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/9ce7dbc001bbf6d2aac4483d3c682a9b.png
Normal file → Executable file
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
0
mkdocs/.cache/plugin/social/a9aafe174d3666966343a65d9ae02f57.png
Normal file → Executable file
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
0
mkdocs/.cache/plugin/social/bae6e5d76e4a4ee30a1f912a9b050b3a.png
Normal file → Executable file
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
0
mkdocs/.cache/plugin/social/bededf2c367a86f373a8685ce19f8e12.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/c7a42e4b7c6d01803867d237fe2d8617.png
Normal file → Executable file
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
0
mkdocs/.cache/plugin/social/ca221d210444f7caca141f1462c1634d.png
Normal file → Executable file
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
0
mkdocs/.cache/plugin/social/df46ee213ba7b1f3bde0cf0978cb876f.png
Normal file → Executable file
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
0
mkdocs/.cache/plugin/social/e659a8119de264bb926772b209a5b992.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/f3cbac41242a5f4062687e6ebf8b69a9.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/fb1ef6eb92689bdb34466fc79a8aebdf.png
Normal file → Executable file
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
0
mkdocs/.cache/plugin/social/fd3474c8ee7ae0ad5529def83d0c8857.png
Normal file → Executable file
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
0
mkdocs/.cache/plugin/social/fd4de0e14e62b2216135775537405340.png
Normal file → Executable file
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
0
mkdocs/.cache/plugin/social/ffb13806ab8dc8c1835b9ebf4a4ba450.png
Normal file → Executable file
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |