Initial commit - Cleaned secrets
This commit is contained in:
commit
655b1b0d92
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# .gitignore
|
||||||
|
**/.env
|
||||||
|
**/mongo-data/
|
||||||
|
**/postgres-data/
|
||||||
|
**/redis-data/
|
||||||
|
**/data/
|
||||||
|
**/komodo/
|
||||||
82
databases/docker-compose.yml
Normal file
82
databases/docker-compose.yml
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo:7
|
||||||
|
container_name: mongodb
|
||||||
|
restart: always
|
||||||
|
command: ["--auth"]
|
||||||
|
environment:
|
||||||
|
- MONGO_INITDB_ROOT_USERNAME=${MONGO_ROOT_USER}
|
||||||
|
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_ROOT_PASS}
|
||||||
|
ports:
|
||||||
|
- "27017:27017"
|
||||||
|
volumes:
|
||||||
|
- ./mongo-data:/data/db
|
||||||
|
networks:
|
||||||
|
- db-net
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16
|
||||||
|
container_name: postgres
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=${DB_ROOT_USER}
|
||||||
|
- POSTGRES_PASSWORD=${DB_ROOT_PASS}
|
||||||
|
- POSTGRES_DB=postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- ./postgres-data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- db-net
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
container_name: redis
|
||||||
|
restart: always
|
||||||
|
command: redis-server --requirepass "${DB_ROOT_PASS}" --save 60 1
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- ./redis-data:/data
|
||||||
|
networks:
|
||||||
|
- db-net
|
||||||
|
|
||||||
|
komodo-periphery:
|
||||||
|
image: ghcr.io/moghtech/komodo-periphery:2
|
||||||
|
container_name: komodo-periphery
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
PERIPHERY_CORE_ADDRESS: ${CORE_IP}:9120
|
||||||
|
PERIPHERY_CONNECT_AS: Mystic-Databases
|
||||||
|
PERIPHERY_ONBOARDING_KEY: ${MYSTIC_ONBOARD_KEY}
|
||||||
|
PERIPHERY_SERVER_ENABLED: "true"
|
||||||
|
ports:
|
||||||
|
- "8120:8120"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./komodo:/config
|
||||||
|
- /proc:/proc:ro
|
||||||
|
networks:
|
||||||
|
- db-net
|
||||||
|
|
||||||
|
# Exporters updated with new variables
|
||||||
|
postgres-exporter:
|
||||||
|
image: prometheuscommunity/postgres-exporter
|
||||||
|
container_name: postgres-exporter
|
||||||
|
environment:
|
||||||
|
- DATA_SOURCE_NAME=postgresql://${DB_ROOT_USER}:${DB_ROOT_PASS}@postgres:5432/postgres?sslmode=disable
|
||||||
|
networks:
|
||||||
|
- db-net
|
||||||
|
|
||||||
|
redis-exporter:
|
||||||
|
image: oliver006/redis_exporter:latest
|
||||||
|
container_name: redis-exporter
|
||||||
|
environment:
|
||||||
|
- REDIS_ADDR=redis://redis:6379
|
||||||
|
- REDIS_PASSWORD=${DB_ROOT_PASS}
|
||||||
|
networks:
|
||||||
|
- db-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
db-net:
|
||||||
|
driver: bridge
|
||||||
70
dns/docker-compose.yml
Normal file
70
dns/docker-compose.yml
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
services:
|
||||||
|
pihole:
|
||||||
|
container_name: pihole
|
||||||
|
image: pihole/pihole:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
dns:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 8.8.8.8
|
||||||
|
ports:
|
||||||
|
- "53:53/tcp"
|
||||||
|
- "53:53/udp"
|
||||||
|
- "80:80/tcp"
|
||||||
|
environment:
|
||||||
|
TZ: 'America/New_York'
|
||||||
|
WEBPASSWORD: ${PIHOLE_PASS}
|
||||||
|
PIHOLE_DNS_: '8.8.8.8;1.1.1.1'
|
||||||
|
DNSMASQ_LISTENING: 'all'
|
||||||
|
volumes:
|
||||||
|
- './etc-pihole:/etc/pihole'
|
||||||
|
- './etc-dnsmasq.d:/etc/dnsmasq.d'
|
||||||
|
cap_add:
|
||||||
|
- SYS_NICE
|
||||||
|
|
||||||
|
# --- KOMODO AGENT (PERIPHERY) ---
|
||||||
|
komodo-periphery:
|
||||||
|
image: ghcr.io/moghtech/komodo-periphery:2
|
||||||
|
container_name: komodo-periphery
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
# Points back to your Cloud VM Core
|
||||||
|
PERIPHERY_CORE_ADDRESS: http://100.80.179.128:9120
|
||||||
|
PERIPHERY_CONNECT_AS: Mystic-DNS
|
||||||
|
PERIPHERY_ONBOARDING_KEY: ${DNS_ONBOARD_KEY}
|
||||||
|
PERIPHERY_SERVER_ENABLED: "true"
|
||||||
|
ports:
|
||||||
|
- "8120:8120"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./komodo:/config
|
||||||
|
- /proc:/proc:ro
|
||||||
|
|
||||||
|
pihole-exporter:
|
||||||
|
image: ekofr/pihole-exporter:latest
|
||||||
|
container_name: pihole-exporter
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- PIHOLE_PROTOCOL=http
|
||||||
|
- PIHOLE_HOSTNAME=pihole
|
||||||
|
- PIHOLE_PASSWORD=${PIHOLE_PASS}
|
||||||
|
ports:
|
||||||
|
- "9617:9617"
|
||||||
|
|
||||||
|
node-exporter:
|
||||||
|
image: prom/node-exporter:latest
|
||||||
|
container_name: node-exporter
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9100:9100"
|
||||||
|
|
||||||
|
cadvisor:
|
||||||
|
image: gcr.io/cadvisor/cadvisor:latest
|
||||||
|
container_name: cadvisor
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- /:/rootfs:ro
|
||||||
|
- /var/run:/var/run:ro
|
||||||
|
- /sys:/sys:ro
|
||||||
|
- /var/lib/docker/:/var/lib/docker:ro
|
||||||
69
git/docker-compose.yml
Normal file
69
git/docker-compose.yml
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
services:
|
||||||
|
forgejo:
|
||||||
|
image: codeberg.org/forgejo/forgejo:7
|
||||||
|
container_name: forgejo
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- FORGEJO__database__DB_TYPE=postgres
|
||||||
|
- FORGEJO__database__HOST=100.109.59.41:5432
|
||||||
|
- FORGEJO__database__NAME=forgejodb
|
||||||
|
- FORGEJO__database__USER=forgejodb
|
||||||
|
- FORGEJO__database__PASSWD=${FORGEJO_DB_PASS} # From .env
|
||||||
|
- FORGEJO__metrics__ENABLED=true
|
||||||
|
- FORGEJO__metrics__TOKEN=${FORGEJO_METRICS_TOKEN} # From .env
|
||||||
|
ports:
|
||||||
|
- "0.0.0.0:3000:3000"
|
||||||
|
- "0.0.0.0:2222:22"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
networks:
|
||||||
|
- git-net
|
||||||
|
|
||||||
|
komodo-periphery:
|
||||||
|
image: ghcr.io/moghtech/komodo-periphery:2
|
||||||
|
container_name: komodo-periphery
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
PERIPHERY_CORE_ADDRESS: http://100.80.179.128:9120 # Added http://
|
||||||
|
PERIPHERY_CONNECT_AS: Mystic-Git
|
||||||
|
PERIPHERY_ONBOARDING_KEY: ${GIT_ONBOARD_KEY} # From .env
|
||||||
|
PERIPHERY_SERVER_ENABLED: "true"
|
||||||
|
PERIPHERY_INCLUDE_DISK_MOUNTS: /etc/hostname
|
||||||
|
ports:
|
||||||
|
- "8120:8120"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./komodo:/config
|
||||||
|
- /proc:/proc:ro
|
||||||
|
networks:
|
||||||
|
- git-net
|
||||||
|
|
||||||
|
# --- MONITORING ---
|
||||||
|
node-exporter:
|
||||||
|
image: prom/node-exporter:latest
|
||||||
|
container_name: node-exporter
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9100:9100"
|
||||||
|
networks:
|
||||||
|
- git-net
|
||||||
|
|
||||||
|
cadvisor:
|
||||||
|
image: gcr.io/cadvisor/cadvisor:latest
|
||||||
|
container_name: cadvisor
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- /:/rootfs:ro
|
||||||
|
- /var/run:/var/run:ro
|
||||||
|
- /sys:/sys:ro
|
||||||
|
- /var/lib/docker/:/var/lib/docker:ro
|
||||||
|
networks:
|
||||||
|
- git-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
git-net:
|
||||||
|
driver: bridge
|
||||||
62
legal/html/privacy.html
Normal file
62
legal/html/privacy.html
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Privacy Policy | CoreBot Labs</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; line-height: 1.6; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #e0e0e0; background-color: #121212; }
|
||||||
|
h1, h2, h3 { color: #ffffff; border-bottom: 1px solid #333; padding-bottom: 10px; }
|
||||||
|
strong { color: #fff; }
|
||||||
|
.footer { margin-top: 50px; font-size: 0.8em; color: #888; border-top: 1px solid #333; padding-top: 20px; }
|
||||||
|
a { color: #4dabf7; text-decoration: none; }
|
||||||
|
a:hover { text-decoration: underline; }
|
||||||
|
ul li { margin-bottom: 10px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Privacy Policy</h1>
|
||||||
|
<p><strong>Effective Date:</strong> April 1, 2026</p>
|
||||||
|
|
||||||
|
<h2>1. Data Collection</h2>
|
||||||
|
<p>To provide our Discord bot services, we collect the following information:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Discord User Data:</strong> User IDs, Server IDs, and Channel IDs.</li>
|
||||||
|
<li><strong>Activity Metrics:</strong> We log that a message was sent, the length of the message, and total message counts per user. <strong>We do not log or store the text content of your messages.</strong></li>
|
||||||
|
<li><strong>System Metrics:</strong> Interaction metadata and infrastructure performance data are logged via our internal monitoring (Loki/Prometheus) to ensure service stability.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>2. Data Usage</h2>
|
||||||
|
<p>We use this information strictly to:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Power Bot features (e.g., user profiles and activity tracking).</li>
|
||||||
|
<li>Monitor the health and security of the CoreBot Labs infrastructure.</li>
|
||||||
|
<li>Facate user-requested data exports for external services.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>3. Storage and Retention</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Location:</strong> Data is hosted on secured servers in <strong>Canada</strong> and via <strong>Google Cloud (USA)</strong>.</li>
|
||||||
|
<li><strong>Discord User Data Retention:</strong> Personal data linked to Discord accounts is stored only as long as necessary to provide our services. This data is removed upon a verified request for deletion or if the service is no longer required.</li>
|
||||||
|
<li><strong>System Metrics Retention:</strong> Non-identifiable system and server metrics are kept indefinitely for historical trend analysis, troubleshooting, and infrastructure optimization.</li>
|
||||||
|
<li><strong>Deletion:</strong> You may request the removal of your Discord-related data at any time by contacting <strong>data@corebot.ca</strong>.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>4. Data Sharing and Third Parties</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>No Sale of Data:</strong> CoreBot Labs does not sell your information.</li>
|
||||||
|
<li><strong>Affiliates:</strong> We do not share user data with <strong>swvn.io</strong>, <strong>Nexus</strong>, or any other third parties.</li>
|
||||||
|
<li><strong>Public Services:</strong> Use of <strong>vault.corebot.services</strong> is subject to the same strict non-disclosure standards.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>5. Open Source Transparency</h2>
|
||||||
|
<p>As an open-source project, our data handling logic is transparent and available for review at <strong>git.corebot.ca</strong>. Users running their own instances of CoreBot are responsible for their own data privacy compliance.</p>
|
||||||
|
|
||||||
|
<h2>6. User Rights</h2>
|
||||||
|
<p>Under GDPR and related privacy frameworks, you have the right to access, rectify, or request the deletion of your personal data. We support data portability and will provide data exports upon request via our support email.</p>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
© 2026 CoreBot Labs. Contact: data@corebot.ca
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
46
legal/html/tos.html
Normal file
46
legal/html/tos.html
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Terms of Service | CoreBot Labs</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; line-height: 1.6; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #e0e0e0; background-color: #121212; }
|
||||||
|
h1, h2, h3 { color: #ffffff; border-bottom: 1px solid #333; padding-bottom: 10px; }
|
||||||
|
strong { color: #fff; }
|
||||||
|
.footer { margin-top: 50px; font-size: 0.8em; color: #888; border-top: 1px solid #333; padding-top: 20px; }
|
||||||
|
a { color: #4dabf7; text-decoration: none; }
|
||||||
|
a:hover { text-decoration: underline; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Terms of Service</h1>
|
||||||
|
<p><strong>Effective Date:</strong> April 1, 2026</p>
|
||||||
|
|
||||||
|
<h2>1. Agreement to Terms</h2>
|
||||||
|
<p>By adding <strong>CoreBot</strong> (the "Bot") to a Discord server or accessing <strong>CoreBot Labs</strong> infrastructure (the "Lab"), you agree to be bound by these Terms of Service. If you do not agree, please remove the Bot and cease use of our services.</p>
|
||||||
|
|
||||||
|
<h2>2. Service Description</h2>
|
||||||
|
<p>CoreBot Labs provides a Discord-integrated utility bot and related web services. We reserve the right to modify, suspend, or discontinue any aspect of the service at any time to maintain the stability of the Lab.</p>
|
||||||
|
|
||||||
|
<h2>3. Open Source Licensing</h2>
|
||||||
|
<p>While the CoreBot source code is available via <strong>git.corebot.ca</strong> under its respective open-source license, the "CoreBot Labs" name, branding, and hosted service instances (the Lab) remain the property of CoreBot Labs. Contributors are welcome, but CoreBot Labs is not responsible for third-party forks or self-hosted instances of the code.</p>
|
||||||
|
|
||||||
|
<h2>4. License and Use</h2>
|
||||||
|
<ul>
|
||||||
|
<li>CoreBot Labs grants you a limited, non-exclusive license to use the Bot for its intended purposes.</li>
|
||||||
|
<li><strong>Prohibited Use:</strong> You may not use the Bot for spam, "self-botting," or any action that disrupts the Lab’s performance or security.</li>
|
||||||
|
<li><strong>Reverse Engineering:</strong> Unauthorized attempts to access the Lab's internal API or bypass security measures are strictly prohibited.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>5. Affiliates</h2>
|
||||||
|
<p>CoreBot is operated by CoreBot Labs (CB). While we maintain professional associations with <strong>swvn.io</strong> and <strong>Nexus</strong>, these are separate entities with their own terms and conditions.</p>
|
||||||
|
|
||||||
|
<h2>6. Limitation of Liability</h2>
|
||||||
|
<p>The Bot and all Lab services are provided "as-is." CoreBot Labs is not liable for any downtime, data loss, or damages resulting from the use of our services.</p>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
© 2026 CoreBot Labs. All rights reserved.
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
74
master/Caddyfile
Normal file
74
master/Caddyfile
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
# Keep this ONLY for the .io domains
|
||||||
|
local_certs
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- PUBLIC PRODUCTION (.ca) ---
|
||||||
|
# Cloudflare DNS points these to your Public IP (136.112.149.254)
|
||||||
|
# Caddy will automatically get REAL Let's Encrypt certificates.
|
||||||
|
|
||||||
|
core.corebot.ca {
|
||||||
|
reverse_proxy 100.80.179.128:9120
|
||||||
|
}
|
||||||
|
|
||||||
|
vault.corebot.ca {
|
||||||
|
reverse_proxy 100.120.171.124:8081 {
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tos.corebot.ca {
|
||||||
|
root * /usr/share/caddy/legal
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
privacy.corebot.ca {
|
||||||
|
root * /usr/share/caddy/legal
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- INTERNAL LAB (.io) ---
|
||||||
|
# Managed by Pi-hole, only accessible via Tailscale/Internal Network.
|
||||||
|
|
||||||
|
main.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy mystic-home:80
|
||||||
|
}
|
||||||
|
|
||||||
|
core.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy 100.80.179.128:9120
|
||||||
|
}
|
||||||
|
|
||||||
|
vault.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy 100.120.171.124:8081
|
||||||
|
}
|
||||||
|
|
||||||
|
git.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy 100.98.158.31:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
dns.bray.io {
|
||||||
|
tls internal
|
||||||
|
redir / /admin/ 308
|
||||||
|
reverse_proxy 100.64.238.34:80
|
||||||
|
}
|
||||||
|
|
||||||
|
database.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy 100.109.59.41:80
|
||||||
|
}
|
||||||
|
|
||||||
|
prometheus.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy prometheus:9090
|
||||||
|
}
|
||||||
|
|
||||||
|
grafana.bray.io {
|
||||||
|
tls internal
|
||||||
|
reverse_proxy grafana:3000
|
||||||
|
}
|
||||||
120
master/docker-compose.yml
Normal file
120
master/docker-compose.yml
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
services:
|
||||||
|
komodo-core:
|
||||||
|
image: ghcr.io/moghtech/komodo-core:2
|
||||||
|
container_name: komodo-core
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9120:9120"
|
||||||
|
environment:
|
||||||
|
- KOMODO_DATABASE_USERNAME=${DB_ROOT_USER}
|
||||||
|
- KOMODO_DATABASE_PASSWORD=${DB_ROOT_PASS}
|
||||||
|
# Path updated to include the database name and the admin auth source
|
||||||
|
- KOMODO_DATABASE_ADDRESS=${DB_VM_IP}:27017/komodo?authSource=admin
|
||||||
|
- KOMODO_LOCAL_AUTH=true
|
||||||
|
- KOMODO_INIT_ADMIN_USERNAME=${KOMODO_USER}
|
||||||
|
- KOMODO_INIT_ADMIN_PASSWORD=${KOMODO_PASS}
|
||||||
|
- KOMODO_HOST=https://core.corebot.ca
|
||||||
|
volumes:
|
||||||
|
- ./komodo:/config
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
container_name: caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||||
|
- ./legal:/usr/share/caddy/legal
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
komodo-periphery:
|
||||||
|
image: ghcr.io/moghtech/komodo-periphery:2
|
||||||
|
container_name: komodo-periphery
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
# Use the service name so Docker DNS can find the Core container
|
||||||
|
PERIPHERY_CORE_ADDRESS: http://komodo-core:9120
|
||||||
|
PERIPHERY_CONNECT_AS: Mystic-Master
|
||||||
|
PERIPHERY_ONBOARDING_KEY: ${MYSTIC_ONBOARD_KEY}
|
||||||
|
volumes:
|
||||||
|
# This allows Komodo to manage the containers on THIS Cloud VM
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
depends_on:
|
||||||
|
- komodo-core
|
||||||
|
|
||||||
|
# --- Restoring your "Orphaned" Monitoring Stack ---
|
||||||
|
|
||||||
|
mystic-home:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: mystic-home
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./html:/usr/share/nginx/html:ro
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus:latest
|
||||||
|
container_name: prometheus
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
|
- prometheus_data:/prometheus
|
||||||
|
command:
|
||||||
|
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||||
|
- '--storage.tsdb.path=/prometheus'
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:latest
|
||||||
|
container_name: grafana
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- GF_SERVER_ROOT_URL=https://grafana.bray.io
|
||||||
|
ports:
|
||||||
|
- "3001:3000"
|
||||||
|
volumes:
|
||||||
|
- grafana_data:/var/lib/grafana
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
node-exporter:
|
||||||
|
image: prom/node-exporter:latest
|
||||||
|
container_name: node-exporter
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
cadvisor:
|
||||||
|
image: gcr.io/cadvisor/cadvisor:latest
|
||||||
|
container_name: cadvisor
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- /:/rootfs:ro
|
||||||
|
- /var/run:/var/run:ro
|
||||||
|
- /sys:/sys:ro
|
||||||
|
- /var/lib/docker/:/var/lib/docker:ro
|
||||||
|
- /dev/disk/:/dev/disk:ro
|
||||||
|
networks:
|
||||||
|
- monitor-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
monitor-net:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
|
grafana_data:
|
||||||
|
prometheus_data:
|
||||||
6
master/mystic-home/Dockerfile
Normal file
6
master/mystic-home/Dockerfile
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
FROM nginx:alpine
|
||||||
|
# Copy the static files to the nginx html directory
|
||||||
|
COPY ./www /usr/share/nginx/html
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
105
master/mystic-home/www/index.html
Normal file
105
master/mystic-home/www/index.html
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>MysticOS</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script src="https://unpkg.com/lucide@latest"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>MYSTIC<span>OS</span></h1>
|
||||||
|
|
||||||
|
<div class="dock">
|
||||||
|
<a href="https://git.bray.io" class="icon-link">
|
||||||
|
<div class="icon-box"><i data-lucide="git-branch"></i></div>
|
||||||
|
<div class="label">Forgejo</div>
|
||||||
|
</a>
|
||||||
|
<a href="https://vault.bray.io" class="icon-link">
|
||||||
|
<div class="icon-box"><i data-lucide="shield-check"></i></div>
|
||||||
|
<div class="label">Vault</div>
|
||||||
|
</a>
|
||||||
|
<a href="https://dns.bray.io" class="icon-link">
|
||||||
|
<div class="icon-box"><i data-lucide="globe"></i></div>
|
||||||
|
<div class="label">Pi-hole</div>
|
||||||
|
</a>
|
||||||
|
<a href="https://grafana.bray.io" class="icon-link">
|
||||||
|
<div class="icon-box"><i data-lucide="line-chart"></i></div>
|
||||||
|
<div class="label">Grafana</div>
|
||||||
|
</a>
|
||||||
|
<a href="https://prometheus.bray.io" class="icon-link">
|
||||||
|
<div class="icon-box"><i data-lucide="activity"></i></div>
|
||||||
|
<div class="label">Prometheus</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-container">
|
||||||
|
<form action="https://www.google.com/search" method="GET">
|
||||||
|
<div class="search-wrapper">
|
||||||
|
<i data-lucide="search" class="search-icon"></i>
|
||||||
|
<input type="text" name="q" placeholder="Search the web..." autofocus autocomplete="off">
|
||||||
|
<button type="submit" style="display:none;"></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Configuration
|
||||||
|
const services = [
|
||||||
|
{ name: 'Forgejo', url: 'https://git.bray.io' },
|
||||||
|
{ name: 'Vault', url: 'https://vault.bray.io' },
|
||||||
|
{ name: 'Pi-hole', url: 'https://dns.bray.io' },
|
||||||
|
{ name: 'Grafana', url: 'https://grafana.bray.io' },
|
||||||
|
{ name: 'Prometheus', url: 'https://prometheus.bray.io' }
|
||||||
|
];
|
||||||
|
|
||||||
|
function updateStatus(name, isUp) {
|
||||||
|
const links = document.querySelectorAll('.icon-link');
|
||||||
|
links.forEach(link => {
|
||||||
|
if (link.querySelector('.label').textContent === name) {
|
||||||
|
const box = link.querySelector('.icon-box');
|
||||||
|
box.style.borderColor = isUp ? '#3fb950' : '#f85149';
|
||||||
|
box.style.boxShadow = isUp ? '0 0 10px rgba(63, 185, 80, 0.2)' : '0 0 10px rgba(248, 81, 73, 0.2)';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkHealth() {
|
||||||
|
services.forEach(service => {
|
||||||
|
const img = new Image();
|
||||||
|
let hasResponded = false;
|
||||||
|
|
||||||
|
// Success or security errors both indicate the service is "up"
|
||||||
|
img.onload = () => {
|
||||||
|
hasResponded = true;
|
||||||
|
updateStatus(service.name, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
img.onerror = () => {
|
||||||
|
hasResponded = true;
|
||||||
|
updateStatus(service.name, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trigger the request with a cache-buster
|
||||||
|
img.src = `${service.url}/favicon.ico?t=${Date.now()}`;
|
||||||
|
|
||||||
|
// If no response at all after 5s, mark as down
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!hasResponded) {
|
||||||
|
updateStatus(service.name, false);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize when DOM is ready
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
lucide.createIcons();
|
||||||
|
checkHealth();
|
||||||
|
// Refresh every 30 seconds
|
||||||
|
setInterval(checkHealth, 30000);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
98
master/mystic-home/www/style.css
Normal file
98
master/mystic-home/www/style.css
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
:root {
|
||||||
|
--bg: #0d1117;
|
||||||
|
--accent: #58a6ff;
|
||||||
|
--text: #c9d1d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
font-family: 'Segoe UI', system-ui, sans-serif;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
letter-spacing: 4px;
|
||||||
|
font-weight: 300;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 span { color: var(--accent); font-weight: 800; }
|
||||||
|
|
||||||
|
.dock {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 25px;
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-link:hover { transform: translateY(-8px); }
|
||||||
|
|
||||||
|
.icon-box {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background: #161b22;
|
||||||
|
border-radius: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid #30363d;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force icons to show up */
|
||||||
|
.icon-box svg, .icon-box i {
|
||||||
|
width: 28px !important;
|
||||||
|
height: 28px !important;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label { font-size: 12px; opacity: 0.7; font-weight: 500; }
|
||||||
|
|
||||||
|
.search-container { margin-top: 2.5rem; width: 100%; max-width: 450px; }
|
||||||
|
|
||||||
|
.search-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrapper:focus-within {
|
||||||
|
border-color: var(--accent);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon { width: 18px; height: 18px; color: var(--accent); margin-right: 12px; }
|
||||||
|
|
||||||
|
.search-wrapper input {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 15px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
144
master/prometheus/prometheus.yml
Normal file
144
master/prometheus/prometheus.yml
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
evaluation_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
# --- VM1: MYSTIC-CLOUD (Local) ---
|
||||||
|
- job_name: 'cloud-node'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['node-exporter:9100']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'control-plane'
|
||||||
|
task: 'exporter'
|
||||||
|
|
||||||
|
- job_name: 'cloud-docker'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['cadvisor:8080']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'control-plane'
|
||||||
|
task: 'monitoring'
|
||||||
|
|
||||||
|
- job_name: 'prometheus'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['localhost:9090']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'control-plane'
|
||||||
|
task: 'monitoring'
|
||||||
|
|
||||||
|
# --- VM3: MYSTIC-DATABASES (Tailscale) ---
|
||||||
|
- job_name: 'vm3-node'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.109.59.41:9100']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'database'
|
||||||
|
task: 'exporter'
|
||||||
|
|
||||||
|
- job_name: 'vm3-docker'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.109.59.41:8080']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'database'
|
||||||
|
task: 'monitoring'
|
||||||
|
|
||||||
|
- job_name: 'vm3-postgres'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.109.59.41:9187']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'database'
|
||||||
|
task: 'database'
|
||||||
|
|
||||||
|
- job_name: 'vm3-mongo'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.109.59.41:9216']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'database'
|
||||||
|
task: 'database'
|
||||||
|
|
||||||
|
- job_name: 'vm3-redis'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.109.59.41:9121']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'database'
|
||||||
|
task: 'database'
|
||||||
|
app: 'redis'
|
||||||
|
# --- VM2: Mystic-Git (Tailscale) ---
|
||||||
|
- job_name: 'vm2-node'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.98.158.31:9100']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'git'
|
||||||
|
task: 'exporter'
|
||||||
|
|
||||||
|
- job_name: 'vm2-docker'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.98.158.31:8080']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'git'
|
||||||
|
task: 'monitoring'
|
||||||
|
|
||||||
|
- job_name: 'vm2-forgejo'
|
||||||
|
metrics_path: '/metrics'
|
||||||
|
authorization:
|
||||||
|
credentials: "mystic_metrics_token"
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.98.158.31:3000']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'git'
|
||||||
|
task: 'app'
|
||||||
|
|
||||||
|
# --- VM4: Mystic-Passwords (Tailscale) ---
|
||||||
|
- job_name: 'vm4-node'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.120.171.124:9100']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'passwords'
|
||||||
|
task: 'exporter'
|
||||||
|
|
||||||
|
- job_name: 'vm4-docker'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.120.171.124:8080']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'passwords'
|
||||||
|
task: 'monitoring'
|
||||||
|
|
||||||
|
- job_name: 'vm4-vaultwarden'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.120.171.124:3040']
|
||||||
|
|
||||||
|
# --- VM5: NEW NODE (35.192.210.155) ---
|
||||||
|
- job_name: 'vm5-dns'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.64.238.34:9100']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'worker'
|
||||||
|
task: 'exporter'
|
||||||
|
|
||||||
|
- job_name: 'vm5-docker'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.64.238.34:8080']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'worker'
|
||||||
|
task: 'monitoring'
|
||||||
|
- job_name: 'vm5-pihole'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['100.64.238.34:9617']
|
||||||
|
labels:
|
||||||
|
infrastructure: 'cloud'
|
||||||
|
type: 'worker'
|
||||||
|
task: 'dns'
|
||||||
|
app: 'pihole'
|
||||||
36
passwords/docker-compose.yml
Normal file
36
passwords/docker-compose.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
services:
|
||||||
|
vaultwarden:
|
||||||
|
image: vaultwarden/server:latest
|
||||||
|
container_name: vaultwarden
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "8081:80"
|
||||||
|
environment:
|
||||||
|
- SIGNUPS_ALLOWED=false
|
||||||
|
- DOMAIN=https://vault.corebot.ca
|
||||||
|
- SMTP_HOST=${SMTP_HOST}
|
||||||
|
- SMTP_FROM=noreply@corebot.ca
|
||||||
|
- SMTP_PORT=${SMTP_PORT}
|
||||||
|
- SMTP_SECURITY=force_tls
|
||||||
|
- SMTP_USERNAME=${SMTP_USER}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASS}
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
networks:
|
||||||
|
- pass-net
|
||||||
|
|
||||||
|
komodo-periphery:
|
||||||
|
image: ghcr.io/moghtech/komodo-periphery:2
|
||||||
|
container_name: komodo-periphery
|
||||||
|
environment:
|
||||||
|
PERIPHERY_CORE_ADDRESS: ${CORE_IP}:9120
|
||||||
|
PERIPHERY_CONNECT_AS: Mystic-Passwords
|
||||||
|
PERIPHERY_ONBOARDING_KEY: ${MYSTIC_ONBOARD_KEY}
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
networks:
|
||||||
|
- pass-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
pass-net:
|
||||||
|
driver: bridge
|
||||||
40
setup-commands.md
Normal file
40
setup-commands.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# 🛠️ Mystic Stack: Node Onboarding Guide
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install ca-certificates curl gnupg git -y
|
||||||
|
|
||||||
|
# Add Docker’s official GPG key
|
||||||
|
sudo install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL [https://download.docker.com/linux/ubuntu/gpg](https://download.docker.com/linux/ubuntu/gpg) | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
|
||||||
|
# Add the repository to Apt sources
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] [https://download.docker.com/linux/ubuntu](https://download.docker.com/linux/ubuntu) \
|
||||||
|
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
|
||||||
|
# Install Docker Stack
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
|
||||||
|
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
newgrp docker
|
||||||
|
|
||||||
|
# Generate key (Press Enter for all prompts)
|
||||||
|
ssh-keygen -t ed25519 -C "$(hostname)"
|
||||||
|
|
||||||
|
# Output public key for Forgejo Web UI
|
||||||
|
cat ~/.ssh/id_ed25519.pub
|
||||||
|
|
||||||
|
# Setup Directory
|
||||||
|
mkdir -p ~/mystic-stack && cd ~/mystic-stack
|
||||||
|
|
||||||
|
# Clone Repository (Using Tailscale IP of Git VM)
|
||||||
|
git clone git@100.98.158.31:bray/infra.git .
|
||||||
|
|
||||||
|
# Launch Node Exporter
|
||||||
|
docker compose -f nodes/docker-compose.node.yml up -d
|
||||||
Loading…
Reference in a new issue