infra: full IaC state after hf-pdocker-01 rebuild (2026-03-08)
Replaces initial Nomad/Consul/Terraform skeleton with current Docker-based infrastructure across all three nodes (hf-pdocker-01, hf-pdocker-02, bart). Key changes: - CLAUDE.md: updated service distribution reflecting hf-pdocker-01 restored - docs/plans/2026-03-08-hf-pdocker-01-rebuild.md: new rebuild plan doc - compose/bart/: ai-agents, guacamole, matrix, media, openvas, smarthome, watchtower - compose/hf-pdocker-02/: traefik, monitoring, adguard, gitea, semaphore, wikijs, unifi, vaultwarden, actual-budget, mcpo, netclaw, trivy, watchtower, n8n - compose/hf-pdocker-01/: frigate, frigate-notify, farm-agent - stacks/: all Swarm stack definitions (monitoring, traefik, smarthome, matrix, guacamole, media, ai-agents, frigate, gitea, semaphore, wikijs, unifi, etc.) - .gitignore: exclude .env credential files and acme.json certs - .env.example: placeholder credential files for all services - .claude/agents/: gitea-backup and other infrastructure agent configs - scripts/: frigate media cleanup and NAS sync scripts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
services:
|
||||
actual-budget:
|
||||
image: actualbudget/actual-server:latest
|
||||
container_name: actual-budget
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5006:5006"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/actual-budget:/data
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:5006/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,26 @@
|
||||
services:
|
||||
adguardhome:
|
||||
image: adguard/adguardhome:latest
|
||||
container_name: adguardhome
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/adguardhome/work:/opt/adguardhome/work
|
||||
- /mnt/docker-data/configs/adguardhome/conf:/opt/adguardhome/conf
|
||||
ports:
|
||||
- "53:53/tcp"
|
||||
- "53:53/udp"
|
||||
- "3000:3000/tcp"
|
||||
- "853:853/tcp"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
caddy-vw:
|
||||
image: caddy:alpine
|
||||
container_name: caddy-vw
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/caddy-vw/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- /mnt/docker-data/configs/caddy-vw/data:/data
|
||||
- /mnt/docker-data/configs/caddy-vw/config:/config
|
||||
command: caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "20m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1 @@
|
||||
GITEA_DB_PASSWORD=change_me
|
||||
@@ -0,0 +1,72 @@
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3003:3000"
|
||||
- "2222:22"
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=gitea-db:5432
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD=${GITEA_DB_PASSWORD}
|
||||
- GITEA__server__SSH_PORT=2222
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/gitea:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
depends_on:
|
||||
gitea-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- gitea-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
gitea-db:
|
||||
image: postgres:16-alpine
|
||||
container_name: gitea-db
|
||||
restart: unless-stopped
|
||||
user: "1024:100"
|
||||
environment:
|
||||
- POSTGRES_DB=gitea
|
||||
- POSTGRES_USER=gitea
|
||||
- POSTGRES_PASSWORD=${GITEA_DB_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/gitea-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- gitea-internal
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
gitea-internal:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,23 @@
|
||||
services:
|
||||
mcpo:
|
||||
image: ghcr.io/open-webui/mcpo:main
|
||||
container_name: mcpo
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8001:8000"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/mcpo:/app/config
|
||||
command: ["--config", "/app/config/config.json"]
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:8000/openapi.json || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,158 @@
|
||||
networks:
|
||||
monitoring-net:
|
||||
name: monitoring-net
|
||||
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
user: "104"
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "3001:3000"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/grafana:/var/lib/grafana
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
dns_search: ""
|
||||
extra_hosts:
|
||||
- "blackbox-exporter:172.24.0.4"
|
||||
- "alertmanager:172.24.0.5"
|
||||
- "influxdb:172.24.0.7"
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9095:9090"
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
|
||||
- '--web.console.templates=/usr/share/prometheus/consoles'
|
||||
- '--web.enable-lifecycle'
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/prometheus:/etc/prometheus
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:9090/-/healthy || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
alertmanager:
|
||||
image: prom/alertmanager:latest
|
||||
container_name: alertmanager
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9093:9093"
|
||||
command:
|
||||
- '--config.file=/etc/alertmanager/alertmanager.yml'
|
||||
- '--storage.path=/alertmanager'
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/alertmanager:/etc/alertmanager
|
||||
- alertmanager-data:/alertmanager
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:9093/-/healthy || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
influxdb:
|
||||
image: influxdb:1.8-alpine
|
||||
container_name: influxdb
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "8086:8086"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/influxdb:/var/lib/influxdb
|
||||
mem_limit: 1G
|
||||
memswap_limit: 1G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:8086/ping || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
matrix-alertmanager-receiver:
|
||||
image: metio/matrix-alertmanager-receiver:2026.2.25
|
||||
container_name: matrix-alertmanager-receiver
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9094:9094"
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/alertmanager/matrix-receiver-config.yml:/config/config.yml:ro
|
||||
command: ["--config-path", "/config/config.yml"]
|
||||
mem_limit: 128M
|
||||
memswap_limit: 128M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
blackbox-exporter:
|
||||
image: prom/blackbox-exporter:latest
|
||||
container_name: blackbox-exporter
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- monitoring-net
|
||||
ports:
|
||||
- "9115:9115"
|
||||
command:
|
||||
- '--config.file=/config/blackbox.yml'
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/blackbox:/config:ro
|
||||
mem_limit: 128M
|
||||
memswap_limit: 128M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
volumes:
|
||||
alertmanager-data:
|
||||
@@ -0,0 +1,2 @@
|
||||
N8N_DB_PASSWORD=change_me
|
||||
N8N_ENCRYPTION_KEY=change_me_32_char_random_key_here
|
||||
@@ -0,0 +1,70 @@
|
||||
services:
|
||||
n8n:
|
||||
image: n8nio/n8n:latest
|
||||
container_name: n8n
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5678:5678"
|
||||
environment:
|
||||
- DB_TYPE=postgresdb
|
||||
- DB_POSTGRESDB_HOST=n8n-db
|
||||
- DB_POSTGRESDB_PORT=5432
|
||||
- DB_POSTGRESDB_DATABASE=n8n
|
||||
- DB_POSTGRESDB_USER=n8n
|
||||
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD}
|
||||
- N8N_PORT=5678
|
||||
- GENERIC_TIMEZONE=America/Chicago
|
||||
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/n8n:/home/node/.n8n
|
||||
depends_on:
|
||||
n8n-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- n8n-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:5678/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 120s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
n8n-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: n8n-db
|
||||
restart: unless-stopped
|
||||
user: "1024:100"
|
||||
environment:
|
||||
- POSTGRES_DB=n8n
|
||||
- POSTGRES_USER=n8n
|
||||
- POSTGRES_PASSWORD=${N8N_DB_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/n8n-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- n8n-internal
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
n8n-internal:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,2 @@
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
MATRIX_ACCESS_TOKEN=syt_...
|
||||
@@ -0,0 +1,38 @@
|
||||
FROM node:20-bookworm
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3 python3-pip python3-venv python3-full \
|
||||
git curl jq openssh-client iputils-ping net-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install uv (Python package manager used by some MCP servers)
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
|
||||
# Install OpenClaw globally
|
||||
RUN npm install -g openclaw@latest
|
||||
|
||||
# Clone NetClaw
|
||||
WORKDIR /opt/netclaw
|
||||
RUN git clone https://github.com/automateyournetwork/netclaw.git .
|
||||
|
||||
# Create openclaw home directory
|
||||
RUN mkdir -p /root/.openclaw/workspace
|
||||
|
||||
# Copy NetClaw workspace config into openclaw home
|
||||
RUN cp -r workspace/skills /root/.openclaw/workspace/ 2>/dev/null || true
|
||||
RUN cp config/openclaw.json /root/.openclaw/openclaw.json 2>/dev/null || true
|
||||
|
||||
# Install Python dependencies for core MCP servers
|
||||
RUN python3 -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
RUN pip install --no-cache-dir pyats genie netmiko paramiko requests pyyaml jinja2 2>/dev/null || true
|
||||
|
||||
# Create entrypoint script
|
||||
COPY entrypoint.sh /opt/entrypoint.sh
|
||||
RUN chmod +x /opt/entrypoint.sh
|
||||
|
||||
EXPOSE 1179
|
||||
|
||||
ENTRYPOINT ["/opt/entrypoint.sh"]
|
||||
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
netclaw:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: netclaw-aaron
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- MATRIX_ACCESS_TOKEN=${MATRIX_ACCESS_TOKEN}
|
||||
- MATRIX_HOMESERVER=http://192.168.86.192:8008
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/netclaw:/root/.openclaw/data
|
||||
mem_limit: 2G
|
||||
memswap_limit: 2G
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Configure OpenClaw environment
|
||||
mkdir -p /root/.openclaw
|
||||
|
||||
# Write .env with API key
|
||||
cat > /root/.openclaw/.env << EOF
|
||||
ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
EOF
|
||||
|
||||
# Write openclaw config for gateway mode
|
||||
cat > /root/.openclaw/openclaw.json << 'OCEOF'
|
||||
{
|
||||
"mode": "gateway",
|
||||
"provider": "anthropic",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"fallbackModel": "claude-haiku-4-5-20251001",
|
||||
"name": "Aaron",
|
||||
"identity": "Aaron - NetClaw AI Network Engineering Agent"
|
||||
}
|
||||
OCEOF
|
||||
|
||||
# Copy workspace skills if they exist
|
||||
if [ -d /opt/netclaw/workspace/skills ]; then
|
||||
cp -r /opt/netclaw/workspace/skills /root/.openclaw/workspace/ 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Copy personality/identity docs
|
||||
for doc in SOUL.md AGENTS.md IDENTITY.md USER.md TOOLS.md; do
|
||||
if [ -f /opt/netclaw/$doc ]; then
|
||||
cp /opt/netclaw/$doc /root/.openclaw/ 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Send Matrix DM to Jeremy to announce availability
|
||||
if [ -n "$MATRIX_ACCESS_TOKEN" ] && [ -n "$MATRIX_HOMESERVER" ]; then
|
||||
echo "Sending Matrix DM to Jeremy..."
|
||||
|
||||
# Create a direct message room with Jeremy
|
||||
ROOM_RESPONSE=$(curl -sf -X POST "${MATRIX_HOMESERVER}/_matrix/client/r0/createRoom" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${MATRIX_ACCESS_TOKEN}" \
|
||||
-d "{
|
||||
\"is_direct\": true,
|
||||
\"invite\": [\"@jeremy:hobbs.farm\"],
|
||||
\"preset\": \"trusted_private_chat\"
|
||||
}" 2>/dev/null || echo "")
|
||||
|
||||
ROOM_ID=$(echo "$ROOM_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('room_id',''))" 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$ROOM_ID" ]; then
|
||||
# Send the message
|
||||
curl -sf -X PUT "${MATRIX_HOMESERVER}/_matrix/client/r0/rooms/${ROOM_ID}/send/m.room.message/$(date +%s%N)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${MATRIX_ACCESS_TOKEN}" \
|
||||
-d "{
|
||||
\"msgtype\": \"m.text\",
|
||||
\"body\": \"Hey Jeremy - Aaron here. I'm online and ready to help with network engineering tasks. I'm running NetClaw with CCIE-level networking skills. Ask me about device health checks, routing analysis, security audits, or anything network-related.\"
|
||||
}" 2>/dev/null || echo "Failed to send DM"
|
||||
echo "DM sent to @jeremy:hobbs.farm in room $ROOM_ID"
|
||||
else
|
||||
echo "Warning: Could not create DM room with Jeremy. Response: $ROOM_RESPONSE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start OpenClaw gateway
|
||||
echo "Starting NetClaw (Aaron) gateway..."
|
||||
exec openclaw gateway 2>&1 || {
|
||||
echo "OpenClaw gateway failed to start, keeping container alive for debugging..."
|
||||
tail -f /dev/null
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
SEMAPHORE_DB_PASSWORD=change_me
|
||||
SEMAPHORE_ADMIN_PASSWORD=change_me
|
||||
SEMAPHORE_ENCRYPTION_KEY=change_me_base64_encoded_32_byte_key
|
||||
SEMAPHORE_MYSQL_ROOT_PASSWORD=change_me
|
||||
@@ -0,0 +1,78 @@
|
||||
services:
|
||||
semaphore:
|
||||
image: semaphoreui/semaphore:latest
|
||||
container_name: semaphore
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3004:3000"
|
||||
environment:
|
||||
- SEMAPHORE_DB_DIALECT=mysql
|
||||
- SEMAPHORE_DB_HOST=semaphore-db
|
||||
- SEMAPHORE_DB_PORT=3306
|
||||
- SEMAPHORE_DB_USER=semaphore
|
||||
- SEMAPHORE_DB_PASS=${SEMAPHORE_DB_PASSWORD}
|
||||
- SEMAPHORE_DB_NAME=semaphore
|
||||
- SEMAPHORE_DB=semaphore
|
||||
- SEMAPHORE_PLAYBOOK_PATH=/tmp/semaphore
|
||||
- SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD}
|
||||
- SEMAPHORE_ADMIN_NAME=admin
|
||||
- SEMAPHORE_ADMIN_EMAIL=admin@hobbs.farm
|
||||
- SEMAPHORE_ADMIN=admin
|
||||
- SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ENCRYPTION_KEY}
|
||||
- SEMAPHORE_LDAP_ACTIVATED=no
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/semaphore:/etc/semaphore
|
||||
- /mnt/docker-data/configs/semaphore/playbooks:/tmp/semaphore
|
||||
depends_on:
|
||||
semaphore-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- semaphore-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/ping || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
semaphore-db:
|
||||
image: mysql:8.0
|
||||
container_name: semaphore-db
|
||||
restart: unless-stopped
|
||||
user: "1024:100"
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${SEMAPHORE_MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=semaphore
|
||||
- MYSQL_USER=semaphore
|
||||
- MYSQL_PASSWORD=${SEMAPHORE_DB_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/semaphore-db:/var/lib/mysql
|
||||
networks:
|
||||
- semaphore-internal
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
command: --innodb-buffer-pool-size=128M --innodb-log-file-size=32M
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 --silent"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
semaphore-internal:
|
||||
driver: bridge
|
||||
@@ -0,0 +1 @@
|
||||
CF_DNS_API_TOKEN=change_me_cloudflare_api_token
|
||||
@@ -0,0 +1,39 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.6
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- "--api.insecure=true"
|
||||
- "--providers.file.directory=/config/dynamic"
|
||||
- "--providers.file.watch=true"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
|
||||
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=jeremydanielhobbs@gmail.com"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
environment:
|
||||
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8090:8080"
|
||||
volumes:
|
||||
- /mnt/docker-data/traefik/letsencrypt:/letsencrypt
|
||||
- /mnt/docker-data/traefik/dynamic:/config/dynamic:ro
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/api/overview || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,88 @@
|
||||
http:
|
||||
routers:
|
||||
yoda:
|
||||
rule: "Host(`yoda.hobbs.farm`)"
|
||||
service: yoda
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
mess:
|
||||
rule: "Host(`mess.hobbs.farm`)"
|
||||
service: mess
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
mess-federation:
|
||||
rule: "Host(`mess.hobbs.farm`) && PathPrefix(`/_matrix/federation`)"
|
||||
service: mess
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
wellknown:
|
||||
rule: "Host(`hobbs.farm`) && PathPrefix(`/.well-known/matrix`)"
|
||||
service: wellknown
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
solo:
|
||||
rule: "Host(`solo.hobbs.farm`)"
|
||||
service: solo
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
vault:
|
||||
rule: "Host(`vault.hobbs.farm`)"
|
||||
service: vault
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
git:
|
||||
rule: "Host(`git.hobbs.farm`)"
|
||||
service: git
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
services:
|
||||
yoda:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.86.167:8123"
|
||||
|
||||
mess:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.86.167:8008"
|
||||
|
||||
wellknown:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.86.167:8010"
|
||||
|
||||
solo:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.86.167:8199"
|
||||
|
||||
vault:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.86.100:26226"
|
||||
|
||||
git:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://192.168.86.100:3003"
|
||||
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
trivy:
|
||||
image: aquasec/trivy:latest
|
||||
container_name: trivy
|
||||
restart: unless-stopped
|
||||
command: server --listen 0.0.0.0:4954
|
||||
ports:
|
||||
- "4954:4954"
|
||||
volumes:
|
||||
- trivy-cache:/root/.cache/
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
volumes:
|
||||
trivy-cache:
|
||||
@@ -0,0 +1,2 @@
|
||||
UNIFI_MONGO_USER=unifi
|
||||
UNIFI_MONGO_PASS=change_me
|
||||
@@ -0,0 +1,67 @@
|
||||
services:
|
||||
unifi:
|
||||
image: lscr.io/linuxserver/unifi-network-application:latest
|
||||
container_name: unifi
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/Chicago
|
||||
- MONGO_USER=${UNIFI_MONGO_USER}
|
||||
- MONGO_PASS=${UNIFI_MONGO_PASS}
|
||||
- MONGO_HOST=unifi-db
|
||||
- MONGO_PORT=27017
|
||||
- MONGO_DBNAME=unifi
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/unifi/data:/config
|
||||
ports:
|
||||
- "8443:8443"
|
||||
- "3478:3478/udp"
|
||||
- "10001:10001/udp"
|
||||
- "8080:8080"
|
||||
- "1900:1900/udp"
|
||||
- "8843:8843"
|
||||
- "8880:8880"
|
||||
- "6789:6789"
|
||||
- "5514:5514/udp"
|
||||
depends_on:
|
||||
unifi-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- unifi-internal
|
||||
mem_limit: 1G
|
||||
memswap_limit: 1G
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
unifi-db:
|
||||
image: mongo:7.0
|
||||
container_name: unifi-db
|
||||
restart: unless-stopped
|
||||
user: "1024:100"
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/unifi-db:/data/db
|
||||
networks:
|
||||
- unifi-internal
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
mem_limit: 1G
|
||||
memswap_limit: 1G
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mongosh --eval 'db.adminCommand(\"ping\")' --quiet"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
unifi-internal:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,25 @@
|
||||
services:
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:latest
|
||||
container_name: vaultwarden
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DOMAIN=https://vault.hobbs.farm
|
||||
- SIGNUPS_ALLOWED=false
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/vaultwarden:/data
|
||||
ports:
|
||||
- "26226:80"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:80/alive || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
watchtower:
|
||||
image: containrrr/watchtower:latest
|
||||
container_name: watchtower
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
- WATCHTOWER_INCLUDE_RESTARTING=true
|
||||
- WATCHTOWER_POLL_INTERVAL=86400
|
||||
- WATCHTOWER_MONITOR_ONLY=false
|
||||
- TZ=America/Chicago
|
||||
- DOCKER_API_VERSION=1.44
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -0,0 +1 @@
|
||||
WIKIJS_DB_PASSWORD=change_me
|
||||
@@ -0,0 +1,65 @@
|
||||
services:
|
||||
wikijs:
|
||||
image: ghcr.io/requarks/wiki:2
|
||||
container_name: wikijs
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3002:3000"
|
||||
environment:
|
||||
- DB_TYPE=postgres
|
||||
- DB_HOST=wikijs-db
|
||||
- DB_PORT=5432
|
||||
- DB_USER=wikijs
|
||||
- DB_PASS=${WIKIJS_DB_PASSWORD}
|
||||
- DB_NAME=wiki
|
||||
depends_on:
|
||||
wikijs-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- wikijs-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:3000/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 120s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
wikijs-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: wikijs-db
|
||||
restart: unless-stopped
|
||||
user: "1024:100"
|
||||
environment:
|
||||
- POSTGRES_DB=wiki
|
||||
- POSTGRES_USER=wikijs
|
||||
- POSTGRES_PASSWORD=${WIKIJS_DB_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/wikijs-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- wikijs-internal
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U wikijs -d wiki"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
wikijs-internal:
|
||||
driver: bridge
|
||||
Reference in New Issue
Block a user