commit 655b1b0d92be9ab918fc9f423803fc652051620e Author: Bray Date: Wed Apr 1 17:44:42 2026 -0400 Initial commit - Cleaned secrets diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..830131c --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# .gitignore +**/.env +**/mongo-data/ +**/postgres-data/ +**/redis-data/ +**/data/ +**/komodo/ \ No newline at end of file diff --git a/databases/docker-compose.yml b/databases/docker-compose.yml new file mode 100644 index 0000000..1c54617 --- /dev/null +++ b/databases/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/dns/docker-compose.yml b/dns/docker-compose.yml new file mode 100644 index 0000000..d115173 --- /dev/null +++ b/dns/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/git/docker-compose.yml b/git/docker-compose.yml new file mode 100644 index 0000000..883283b --- /dev/null +++ b/git/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/legal/html/privacy.html b/legal/html/privacy.html new file mode 100644 index 0000000..e1699be --- /dev/null +++ b/legal/html/privacy.html @@ -0,0 +1,62 @@ + + + + + + Privacy Policy | CoreBot Labs + + + +

Privacy Policy

+

Effective Date: April 1, 2026

+ +

1. Data Collection

+

To provide our Discord bot services, we collect the following information:

+ + +

2. Data Usage

+

We use this information strictly to:

+ + +

3. Storage and Retention

+ + +

4. Data Sharing and Third Parties

+ + +

5. Open Source Transparency

+

As an open-source project, our data handling logic is transparent and available for review at git.corebot.ca. Users running their own instances of CoreBot are responsible for their own data privacy compliance.

+ +

6. User Rights

+

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.

+ + + + \ No newline at end of file diff --git a/legal/html/tos.html b/legal/html/tos.html new file mode 100644 index 0000000..e5df915 --- /dev/null +++ b/legal/html/tos.html @@ -0,0 +1,46 @@ + + + + + + Terms of Service | CoreBot Labs + + + +

Terms of Service

+

Effective Date: April 1, 2026

+ +

1. Agreement to Terms

+

By adding CoreBot (the "Bot") to a Discord server or accessing CoreBot Labs 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.

+ +

2. Service Description

+

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.

+ +

3. Open Source Licensing

+

While the CoreBot source code is available via git.corebot.ca 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.

+ +

4. License and Use

+ + +

5. Affiliates

+

CoreBot is operated by CoreBot Labs (CB). While we maintain professional associations with swvn.io and Nexus, these are separate entities with their own terms and conditions.

+ +

6. Limitation of Liability

+

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.

+ + + + \ No newline at end of file diff --git a/master/Caddyfile b/master/Caddyfile new file mode 100644 index 0000000..74316ed --- /dev/null +++ b/master/Caddyfile @@ -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 +} \ No newline at end of file diff --git a/master/docker-compose.yml b/master/docker-compose.yml new file mode 100644 index 0000000..43a28f7 --- /dev/null +++ b/master/docker-compose.yml @@ -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: \ No newline at end of file diff --git a/master/mystic-home/Dockerfile b/master/mystic-home/Dockerfile new file mode 100644 index 0000000..8f11bee --- /dev/null +++ b/master/mystic-home/Dockerfile @@ -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;"] \ No newline at end of file diff --git a/master/mystic-home/www/index.html b/master/mystic-home/www/index.html new file mode 100644 index 0000000..46ee68c --- /dev/null +++ b/master/mystic-home/www/index.html @@ -0,0 +1,105 @@ + + + + + + MysticOS + + + + + +

MYSTICOS

+ +
+ +
+
Forgejo
+
+ +
+
Vault
+
+ +
+
Pi-hole
+
+ +
+
Grafana
+
+ +
+
Prometheus
+
+
+ +
+
+
+ + + +
+
+
+ + + + \ No newline at end of file diff --git a/master/mystic-home/www/style.css b/master/mystic-home/www/style.css new file mode 100644 index 0000000..8190e65 --- /dev/null +++ b/master/mystic-home/www/style.css @@ -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%; +} \ No newline at end of file diff --git a/master/prometheus/prometheus.yml b/master/prometheus/prometheus.yml new file mode 100644 index 0000000..df57c5a --- /dev/null +++ b/master/prometheus/prometheus.yml @@ -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' \ No newline at end of file diff --git a/passwords/docker-compose.yml b/passwords/docker-compose.yml new file mode 100644 index 0000000..344addf --- /dev/null +++ b/passwords/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/setup-commands.md b/setup-commands.md new file mode 100644 index 0000000..894b5de --- /dev/null +++ b/setup-commands.md @@ -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 \ No newline at end of file