feat: Improve TLS handling for multi-server deployments
- Add CORE_SERVER_IP variable for remote server configuration - Implement setup_multi_server_tls() function for shared CA management - Change TLS failure handling from exit-on-error to warning-based approach - Add TLS_ISSUES_SUMMARY for end-of-deployment remediation guidance - Update documentation for automated TLS setup process - Add comprehensive AI assistant instructions for project management This allows deployments to complete successfully even with TLS issues, providing clear remediation steps instead of failing the entire setup.
This commit is contained in:
26
.github/copilot-instructions.md
vendored
26
.github/copilot-instructions.md
vendored
@@ -47,6 +47,12 @@ docker-compose/
|
|||||||
- **Gluetun network mode**: Download clients use `network_mode: "service:gluetun"` for VPN routing
|
- **Gluetun network mode**: Download clients use `network_mode: "service:gluetun"` for VPN routing
|
||||||
- **Port mapping**: Only core services expose ports (80/443 for Traefik); others route via Traefik labels
|
- **Port mapping**: Only core services expose ports (80/443 for Traefik); others route via Traefik labels
|
||||||
|
|
||||||
|
### TLS and Multi-Server Architecture
|
||||||
|
- **Shared CA**: Core server generates CA for signing certificates across all servers
|
||||||
|
- **Docker TLS**: Remote servers use TCP 2376 with mutual TLS for Sablier access
|
||||||
|
- **Certificate Management**: Automated generation and distribution of client/server certificates
|
||||||
|
- **Sablier Integration**: Core Sablier connects to remote Docker daemons via TLS for lazy loading
|
||||||
|
|
||||||
## Critical Operational Principles
|
## Critical Operational Principles
|
||||||
|
|
||||||
### 1. Security-First SSO Strategy
|
### 1. Security-First SSO Strategy
|
||||||
@@ -284,6 +290,15 @@ Secrets auto-generated by `ez-homelab.sh`:
|
|||||||
- **Renewal**: Traefik handles automatically (90-day Let's Encrypt certs)
|
- **Renewal**: Traefik handles automatically (90-day Let's Encrypt certs)
|
||||||
- **Usage**: Services use `tls.certresolver=letsencrypt` label (no per-service cert requests)
|
- **Usage**: Services use `tls.certresolver=letsencrypt` label (no per-service cert requests)
|
||||||
|
|
||||||
|
### Remote Server TLS Setup
|
||||||
|
For multi-server deployments with Sablier lazy loading:
|
||||||
|
- **Core server**: Generates shared CA and client certificates
|
||||||
|
- **Remote servers**: Use `ez-homelab.sh` option 3, specify core server IP for CA import
|
||||||
|
- **Certificate chain**: Core has CA + client certs; remotes have CA + server certs
|
||||||
|
- **Sablier connection**: Uses TCP 2376 with mutual TLS to remote Docker daemons
|
||||||
|
- **Security**: All Docker API access encrypted and authenticated
|
||||||
|
- **Failure handling**: Setup fails if CA cannot be copied (prevents inconsistent TLS state)
|
||||||
|
|
||||||
### Homepage Dashboard AI Configuration
|
### Homepage Dashboard AI Configuration
|
||||||
Homepage (`/opt/stacks/dashboards/`) uses dynamic variable replacement:
|
Homepage (`/opt/stacks/dashboards/`) uses dynamic variable replacement:
|
||||||
- Services configured in `homepage/config/services.yaml`
|
- Services configured in `homepage/config/services.yaml`
|
||||||
@@ -357,6 +372,17 @@ docker logs gluetun | grep -i wireguard # Verify connection
|
|||||||
```
|
```
|
||||||
Verify: `SURFSHARK_PRIVATE_KEY` set in `.env`, service using `network_mode: "service:gluetun"`, ports mapped in Gluetun
|
Verify: `SURFSHARK_PRIVATE_KEY` set in `.env`, service using `network_mode: "service:gluetun"`, ports mapped in Gluetun
|
||||||
|
|
||||||
|
### Sablier TLS Connection Issues
|
||||||
|
```bash
|
||||||
|
# Test Docker TLS connection from core to remote
|
||||||
|
cd /opt/stacks/core/shared-ca
|
||||||
|
docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem --host=tcp://REMOTE_IP:2376 ps
|
||||||
|
|
||||||
|
# Check Sablier logs
|
||||||
|
docker compose -f /opt/stacks/core/docker-compose.yml logs sablier-service
|
||||||
|
```
|
||||||
|
Verify: Remote Docker daemon configured with shared CA, certificates properly signed, firewall allows 2376/tcp
|
||||||
|
|
||||||
### Wildcard Certificate Issues
|
### Wildcard Certificate Issues
|
||||||
```bash
|
```bash
|
||||||
docker logs traefik | grep -i certificate
|
docker logs traefik | grep -i certificate
|
||||||
|
|||||||
@@ -1,6 +1,66 @@
|
|||||||
# On Demand Remote Services with Authelia, Sablier & Traefik
|
# On Demand Remote Services with Authelia, Sablier & Traefik
|
||||||
|
|
||||||
## 4 Step Process
|
## Overview
|
||||||
|
|
||||||
|
This guide explains how to set up lazy-loading services on remote servers (like Raspberry Pi) that start automatically when accessed via Traefik. The core server runs Sablier, which connects to remote Docker daemons via TLS to manage container lifecycle.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Core server with Traefik, Authelia, and Sablier deployed
|
||||||
|
- Remote server with Docker installed
|
||||||
|
- Shared TLS CA configured between core and remote servers
|
||||||
|
|
||||||
|
## Automated Setup
|
||||||
|
|
||||||
|
For new remote servers, use the automated script:
|
||||||
|
|
||||||
|
1. On the remote server, run `ez-homelab.sh` and select option 3 (Infrastructure Only)
|
||||||
|
2. When prompted, enter the core server IP for shared TLS CA
|
||||||
|
3. The script will automatically:
|
||||||
|
- Copy shared CA from core server via SSH
|
||||||
|
- Configure Docker TLS with shared certificates
|
||||||
|
- Generate server certificates signed by shared CA
|
||||||
|
- Set up Docker daemon for TLS on port 2376
|
||||||
|
|
||||||
|
**Important**: The script will fail if it cannot copy the shared CA from the core server. Ensure SSH access is configured between servers before running option 3.
|
||||||
|
|
||||||
|
## Manual Setup (if automated fails)
|
||||||
|
|
||||||
|
If the automated setup fails, manually configure TLS:
|
||||||
|
|
||||||
|
### On Core Server:
|
||||||
|
```bash
|
||||||
|
# Generate server certificates for remote server
|
||||||
|
cd /opt/stacks/core/shared-ca
|
||||||
|
openssl genrsa -out server-key.pem 4096
|
||||||
|
openssl req -subj "/CN=<REMOTE_IP>" -new -key server-key.pem -out server.csr
|
||||||
|
echo "subjectAltName = DNS:<REMOTE_IP>,IP:<REMOTE_IP>,IP:127.0.0.1" > extfile.cnf
|
||||||
|
openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
|
||||||
|
```
|
||||||
|
|
||||||
|
### On Remote Server:
|
||||||
|
```bash
|
||||||
|
# Copy certificates
|
||||||
|
scp user@core-server:/opt/stacks/core/shared-ca/ca.pem /opt/stacks/core/shared-ca/
|
||||||
|
scp user@core-server:/opt/stacks/core/shared-ca/server-cert.pem /opt/stacks/core/shared-ca/
|
||||||
|
scp user@core-server:/opt/stacks/core/shared-ca/server-key.pem /opt/stacks/core/shared-ca/
|
||||||
|
|
||||||
|
# Update Docker daemon
|
||||||
|
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
|
||||||
|
{
|
||||||
|
"tls": true,
|
||||||
|
"tlsverify": true,
|
||||||
|
"tlscacert": "/opt/stacks/core/shared-ca/ca.pem",
|
||||||
|
"tlscert": "/opt/stacks/core/shared-ca/server-cert.pem",
|
||||||
|
"tlskey": "/opt/stacks/core/shared-ca/server-key.pem"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo systemctl restart docker
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4 Step Process for Adding Services
|
||||||
|
|
||||||
1. Add route & service in Traefik external hosts file
|
1. Add route & service in Traefik external hosts file
|
||||||
2. Add middleware in Sablier config file (sablier.yml)
|
2. Add middleware in Sablier config file (sablier.yml)
|
||||||
3. Add labels to compose files on Remote Host
|
3. Add labels to compose files on Remote Host
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# EZ-Homelab Unified Setup & Deployment Script
|
# EZ-Homelab Unified Setup & Deployment Script
|
||||||
# This script provides a guided setup and deployment experience
|
|
||||||
# Run as: ./ez-homelab.sh (will use sudo when needed)
|
|
||||||
|
|
||||||
|
# Two step process required for first-time setup:
|
||||||
|
# Run 'sudo ./ez-homelab.sh' to install Docker and perform system setup
|
||||||
|
# Run './ez-homelab.sh' to deploy stacks after initial setup
|
||||||
set -e # Exit on error
|
set -e # Exit on error
|
||||||
|
|
||||||
# Colors for output
|
# Colors for output
|
||||||
@@ -29,6 +30,86 @@ log_error() {
|
|||||||
echo -e "${RED}[ERROR]${NC} $1"
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Reusable function to replace environment variable placeholders in files
|
||||||
|
replace_env_placeholders() {
|
||||||
|
local file_path="$1"
|
||||||
|
local missing_vars=""
|
||||||
|
|
||||||
|
if [ ! -f "$file_path" ]; then
|
||||||
|
log_warning "File $file_path does not exist, skipping placeholder replacement"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find all ${VAR} patterns in the file
|
||||||
|
local vars=$(grep -o '\${[^}]*}' "$file_path" | sed 's/\${//' | sed 's/}//' | sort | uniq)
|
||||||
|
|
||||||
|
for var in $vars; do
|
||||||
|
if [ -z "${!var:-}" ]; then
|
||||||
|
log_warning "Environment variable $var not found in .env file"
|
||||||
|
missing_vars="$missing_vars $var"
|
||||||
|
else
|
||||||
|
# Replace ${VAR} with the value
|
||||||
|
sed -i "s|\${$var}|${!var}|g" "$file_path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Store missing vars for end-of-script summary
|
||||||
|
if [ -n "$missing_vars" ]; then
|
||||||
|
MISSING_VARS_SUMMARY="${MISSING_VARS_SUMMARY}${missing_vars}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to generate shared CA for multi-server TLS
|
||||||
|
generate_shared_ca() {
|
||||||
|
local ca_dir="/opt/stacks/core/shared-ca"
|
||||||
|
mkdir -p "$ca_dir"
|
||||||
|
openssl genrsa -out "$ca_dir/ca-key.pem" 4096
|
||||||
|
openssl req -new -x509 -days 365 -key "$ca_dir/ca-key.pem" -sha256 -out "$ca_dir/ca.pem" -subj "/C=US/ST=State/L=City/O=Homelab/CN=Homelab-CA"
|
||||||
|
chown -R "$ACTUAL_USER:$ACTUAL_USER" "$ca_dir"
|
||||||
|
log_success "Shared CA generated"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to setup multi-server TLS for remote servers
|
||||||
|
setup_multi_server_tls() {
|
||||||
|
if [ -n "$CORE_SERVER_IP" ]; then
|
||||||
|
log_info "Setting up multi-server TLS using shared CA from core server $CORE_SERVER_IP..."
|
||||||
|
|
||||||
|
# Create shared-ca directory
|
||||||
|
local ca_dir="/opt/stacks/core/shared-ca"
|
||||||
|
sudo mkdir -p "$ca_dir"
|
||||||
|
sudo chown "$ACTUAL_USER:$ACTUAL_USER" "$ca_dir"
|
||||||
|
|
||||||
|
# Copy shared CA from core server
|
||||||
|
if scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$ACTUAL_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem" "$ca_dir/" 2>/dev/null; then
|
||||||
|
log_success "Shared CA copied from core server"
|
||||||
|
else
|
||||||
|
log_warning "Failed to copy shared CA from core server $CORE_SERVER_IP"
|
||||||
|
log_warning "This will create TLS certificate mismatches between core and remote servers"
|
||||||
|
log_warning "Sablier will not be able to connect to this remote Docker daemon"
|
||||||
|
TLS_ISSUES_SUMMARY="⚠️ TLS Configuration Issue: Could not copy shared CA from core server $CORE_SERVER_IP
|
||||||
|
This will prevent Sablier from connecting to remote Docker daemons.
|
||||||
|
|
||||||
|
To fix this:
|
||||||
|
1. Ensure SSH access works: ssh $ACTUAL_USER@$CORE_SERVER_IP
|
||||||
|
2. Verify core server has: /opt/stacks/core/shared-ca/ca.pem
|
||||||
|
3. Manually copy CA: scp $ACTUAL_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem $ca_dir/
|
||||||
|
4. Regenerate server certificates on this server with shared CA
|
||||||
|
5. Restart Docker: sudo systemctl restart docker
|
||||||
|
6. Test connection: docker --tlsverify --tlscacert=$ca_dir/ca.pem --tlscert=$ca_dir/cert.pem --tlskey=$ca_dir/key.pem --host=tcp://localhost:2376 ps
|
||||||
|
|
||||||
|
Then restart Sablier on the core server to reconnect."
|
||||||
|
generate_shared_ca
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup Docker TLS with shared CA
|
||||||
|
setup_docker_tls
|
||||||
|
else
|
||||||
|
log_info "No core server specified, setting up local TLS..."
|
||||||
|
generate_shared_ca
|
||||||
|
setup_docker_tls
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Get script directory and repo directory
|
# Get script directory and repo directory
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
REPO_DIR="$( cd "$SCRIPT_DIR/.." && pwd )"
|
REPO_DIR="$( cd "$SCRIPT_DIR/.." && pwd )"
|
||||||
@@ -43,6 +124,7 @@ fi
|
|||||||
# Default values
|
# Default values
|
||||||
DOMAIN=""
|
DOMAIN=""
|
||||||
SERVER_IP=""
|
SERVER_IP=""
|
||||||
|
CORE_SERVER_IP=""
|
||||||
ADMIN_USER=""
|
ADMIN_USER=""
|
||||||
ADMIN_EMAIL=""
|
ADMIN_EMAIL=""
|
||||||
ADMIN_PASSWORD=""
|
ADMIN_PASSWORD=""
|
||||||
@@ -50,6 +132,7 @@ DEPLOY_CORE=false
|
|||||||
DEPLOY_INFRASTRUCTURE=false
|
DEPLOY_INFRASTRUCTURE=false
|
||||||
DEPLOY_DASHBOARDS=false
|
DEPLOY_DASHBOARDS=false
|
||||||
SETUP_STACKS=false
|
SETUP_STACKS=false
|
||||||
|
TLS_ISSUES_SUMMARY=""
|
||||||
|
|
||||||
# Load existing .env file if it exists
|
# Load existing .env file if it exists
|
||||||
load_env_file() {
|
load_env_file() {
|
||||||
@@ -158,6 +241,7 @@ prompt_for_values() {
|
|||||||
# Set defaults from env file or hardcoded fallbacks
|
# Set defaults from env file or hardcoded fallbacks
|
||||||
DEFAULT_DOMAIN="${DOMAIN:-example.duckdns.org}"
|
DEFAULT_DOMAIN="${DOMAIN:-example.duckdns.org}"
|
||||||
DEFAULT_SERVER_IP="${SERVER_IP:-$(hostname -I | awk '{print $1}')}"
|
DEFAULT_SERVER_IP="${SERVER_IP:-$(hostname -I | awk '{print $1}')}"
|
||||||
|
DEFAULT_CORE_SERVER_IP="${CORE_SERVER_IP:-}"
|
||||||
DEFAULT_SERVER_HOSTNAME="${SERVER_HOSTNAME:-$(hostname)}"
|
DEFAULT_SERVER_HOSTNAME="${SERVER_HOSTNAME:-$(hostname)}"
|
||||||
DEFAULT_TZ="${TZ:-America/New_York}"
|
DEFAULT_TZ="${TZ:-America/New_York}"
|
||||||
|
|
||||||
@@ -168,6 +252,12 @@ prompt_for_values() {
|
|||||||
echo " Server Hostname: $DEFAULT_SERVER_HOSTNAME"
|
echo " Server Hostname: $DEFAULT_SERVER_HOSTNAME"
|
||||||
echo " Timezone: $DEFAULT_TZ"
|
echo " Timezone: $DEFAULT_TZ"
|
||||||
|
|
||||||
|
if [ "$DEPLOY_CORE" = false ] && [ -z "$DEFAULT_CORE_SERVER_IP" ]; then
|
||||||
|
echo " Core Server IP: [Will be prompted for multi-server TLS]"
|
||||||
|
elif [ -n "$DEFAULT_CORE_SERVER_IP" ]; then
|
||||||
|
echo " Core Server IP: $DEFAULT_CORE_SERVER_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$DEPLOY_CORE" = true ]; then
|
if [ "$DEPLOY_CORE" = true ]; then
|
||||||
DEFAULT_ADMIN_USER="${DEFAULT_USER:-admin}"
|
DEFAULT_ADMIN_USER="${DEFAULT_USER:-admin}"
|
||||||
DEFAULT_ADMIN_EMAIL="${DEFAULT_EMAIL:-${DEFAULT_ADMIN_USER}@${DEFAULT_DOMAIN}}"
|
DEFAULT_ADMIN_EMAIL="${DEFAULT_EMAIL:-${DEFAULT_ADMIN_USER}@${DEFAULT_DOMAIN}}"
|
||||||
@@ -199,6 +289,12 @@ prompt_for_values() {
|
|||||||
read -p "Timezone [$DEFAULT_TZ]: " TZ
|
read -p "Timezone [$DEFAULT_TZ]: " TZ
|
||||||
TZ="${TZ:-$DEFAULT_TZ}"
|
TZ="${TZ:-$DEFAULT_TZ}"
|
||||||
|
|
||||||
|
# Core server IP (for multi-server setup)
|
||||||
|
if [ "$DEPLOY_CORE" = false ]; then
|
||||||
|
echo ""
|
||||||
|
read -p "Core server IP (for shared TLS CA): " CORE_SERVER_IP
|
||||||
|
fi
|
||||||
|
|
||||||
# Admin credentials (only if deploying core)
|
# Admin credentials (only if deploying core)
|
||||||
if [ "$DEPLOY_CORE" = true ]; then
|
if [ "$DEPLOY_CORE" = true ]; then
|
||||||
echo ""
|
echo ""
|
||||||
@@ -229,6 +325,7 @@ prompt_for_values() {
|
|||||||
SERVER_IP="$DEFAULT_SERVER_IP"
|
SERVER_IP="$DEFAULT_SERVER_IP"
|
||||||
SERVER_HOSTNAME="$DEFAULT_SERVER_HOSTNAME"
|
SERVER_HOSTNAME="$DEFAULT_SERVER_HOSTNAME"
|
||||||
TZ="$DEFAULT_TZ"
|
TZ="$DEFAULT_TZ"
|
||||||
|
CORE_SERVER_IP="$DEFAULT_CORE_SERVER_IP"
|
||||||
|
|
||||||
if [ "$DEPLOY_CORE" = true ]; then
|
if [ "$DEPLOY_CORE" = true ]; then
|
||||||
ADMIN_USER="$DEFAULT_ADMIN_USER"
|
ADMIN_USER="$DEFAULT_ADMIN_USER"
|
||||||
@@ -239,14 +336,14 @@ prompt_for_values() {
|
|||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Certificate sharing function for infrastructure-only deployments
|
# Certificate fetching function for infrastructure-only deployments
|
||||||
share_certs_with_core() {
|
get_certs_from_core_server() {
|
||||||
log_info "Infrastructure-only deployment detected. Setting up certificate sharing for remote Docker control..."
|
log_info "Infrastructure-only deployment detected. Fetching certificate from core server for remote Docker control..."
|
||||||
|
|
||||||
# Prompt for core server IP
|
# Prompt for core server IP
|
||||||
read -p "Enter the IP address of your core server: " CORE_SERVER_IP
|
read -p "Enter the IP address of your core server: " CORE_SERVER_IP
|
||||||
while [ -z "$CORE_SERVER_IP" ]; do
|
while [ -z "$CORE_SERVER_IP" ]; do
|
||||||
log_warning "Core server IP is required for certificate sharing"
|
log_warning "Core server IP is required for certificate fetching"
|
||||||
read -p "Enter the IP address of your core server: " CORE_SERVER_IP
|
read -p "Enter the IP address of your core server: " CORE_SERVER_IP
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -278,71 +375,85 @@ share_certs_with_core() {
|
|||||||
read -p "Do you want to continue anyway? (y/N): " -n 1 -r
|
read -p "Do you want to continue anyway? (y/N): " -n 1 -r
|
||||||
echo ""
|
echo ""
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
log_error "Certificate sharing cancelled. Please verify SSH access and try again."
|
log_error "Certificate fetching cancelled. Please verify SSH access and try again."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
USE_SSHPASS=true # Assume password auth for copying
|
USE_SSHPASS=true # Assume password auth for copying
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Copy shared CA certificates from core server
|
# Fetch shared CA certificates from core server
|
||||||
log_info "Copying shared CA certificates from core server..."
|
log_info "Fetching shared CA certificates from core server..."
|
||||||
mkdir -p "/opt/stacks/core/shared-ca"
|
sudo mkdir -p "/opt/stacks/core/shared-ca"
|
||||||
|
|
||||||
# First check if shared CA exists on core server
|
# First check if shared CA exists on core server (check both old and new locations)
|
||||||
SHARED_CA_EXISTS=false
|
SHARED_CA_EXISTS=false
|
||||||
if [ "$USE_SSHPASS" = true ] && [ -n "$SSH_PASSWORD" ]; then
|
if [ "$USE_SSHPASS" = true ] && [ -n "$SSH_PASSWORD" ]; then
|
||||||
if sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP" "[ -f /opt/stacks/core/shared-ca/ca.pem ] && [ -f /opt/stacks/core/shared-ca/ca-key.pem ]" 2>/dev/null; then
|
if sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP" "[ -f /opt/stacks/core/shared-ca/ca.pem ] && [ -f /opt/stacks/core/shared-ca/ca-key.pem ] && [ -r /opt/stacks/core/shared-ca/ca.pem ] && [ -r /opt/stacks/core/shared-ca/ca-key.pem ]" 2>/dev/null; then
|
||||||
SHARED_CA_EXISTS=true
|
SHARED_CA_EXISTS=true
|
||||||
|
SHARED_CA_PATH="/opt/stacks/core/shared-ca"
|
||||||
|
log_info "Detected CA certificate and key in shared-ca location"
|
||||||
|
elif sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP" "[ -f /opt/stacks/core/docker-tls/ca.pem ] && [ -f /opt/stacks/core/docker-tls/ca-key.pem ] && [ -r /opt/stacks/core/docker-tls/ca.pem ] && [ -r /opt/stacks/core/docker-tls/ca-key.pem ]" 2>/dev/null; then
|
||||||
|
SHARED_CA_EXISTS=true
|
||||||
|
SHARED_CA_PATH="/opt/stacks/core/docker-tls"
|
||||||
|
log_info "Detected CA certificate and key in docker-tls location"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if ssh -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP" "[ -f /opt/stacks/core/shared-ca/ca.pem ] && [ -f /opt/stacks/core/shared-ca/ca-key.pem ]" 2>/dev/null; then
|
if ssh -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP" "[ -f /opt/stacks/core/shared-ca/ca.pem ] && [ -f /opt/stacks/core/shared-ca/ca-key.pem ] && [ -r /opt/stacks/core/shared-ca/ca.pem ] && [ -r /opt/stacks/core/shared-ca/ca-key.pem ]" 2>/dev/null; then
|
||||||
SHARED_CA_EXISTS=true
|
SHARED_CA_EXISTS=true
|
||||||
|
SHARED_CA_PATH="/opt/stacks/core/shared-ca"
|
||||||
|
log_info "Detected CA certificate and key in shared-ca location"
|
||||||
|
elif ssh -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP" "[ -f /opt/stacks/core/docker-tls/ca.pem ] && [ -f /opt/stacks/core/docker-tls/ca-key.pem ] && [ -r /opt/stacks/core/docker-tls/ca.pem ] && [ -r /opt/stacks/core/docker-tls/ca-key.pem ]" 2>/dev/null; then
|
||||||
|
SHARED_CA_EXISTS=true
|
||||||
|
SHARED_CA_PATH="/opt/stacks/core/docker-tls"
|
||||||
|
log_info "Detected CA certificate and key in docker-tls location"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$SHARED_CA_EXISTS" = true ]; then
|
if [ "$SHARED_CA_EXISTS" = true ]; then
|
||||||
# Copy existing shared CA from core server
|
# Copy existing shared CA from core server
|
||||||
if [ "$USE_SSHPASS" = true ] && [ -n "$SSH_PASSWORD" ]; then
|
if [ "$USE_SSHPASS" = true ] && [ -n "$SSH_PASSWORD" ]; then
|
||||||
log_info "Running: sshpass -p [PASSWORD] scp -o StrictHostKeyChecking=no $SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem /opt/stacks/core/shared-ca/"
|
log_info "Running: sshpass -p [PASSWORD] scp -o StrictHostKeyChecking=no $SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca.pem $SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca-key.pem /opt/stacks/core/shared-ca/"
|
||||||
if sshpass -p "$SSH_PASSWORD" scp -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem" "$SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca-key.pem" "/opt/stacks/core/shared-ca/" 2>&1; then
|
if sshpass -p "$SSH_PASSWORD" scp -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca.pem" "$SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca-key.pem" "/opt/stacks/core/shared-ca/" 2>&1; then
|
||||||
log_success "Shared CA certificates copied from core server"
|
log_success "Shared CA certificate and key fetched from core server"
|
||||||
|
# Generate server certificates signed by the shared CA
|
||||||
|
setup_docker_tls
|
||||||
else
|
else
|
||||||
log_warning "Failed to copy shared CA certificates from core server"
|
log_warning "Failed to fetch shared CA certificate and key from core server"
|
||||||
SHARED_CA_EXISTS=false
|
SHARED_CA_EXISTS=false
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log_info "Running: scp -o StrictHostKeyChecking=no $SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem /opt/stacks/core/shared-ca/"
|
log_info "Running: scp -o StrictHostKeyChecking=no $SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca.pem $SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca-key.pem /opt/stacks/core/shared-ca/"
|
||||||
if scp -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem" "$SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca-key.pem" "/opt/stacks/core/shared-ca/" 2>&1; then
|
if scp -o StrictHostKeyChecking=no "$SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca.pem" "$SSH_USER@$CORE_SERVER_IP:$SHARED_CA_PATH/ca-key.pem" "/opt/stacks/core/shared-ca/" 2>&1; then
|
||||||
log_success "Shared CA certificates copied from core server"
|
log_success "Shared CA certificate and key fetched from core server"
|
||||||
|
# Generate server certificates signed by the shared CA
|
||||||
|
setup_docker_tls
|
||||||
else
|
else
|
||||||
log_warning "Failed to copy shared CA certificates from core server"
|
log_warning "Failed to fetch shared CA certificate and key from core server"
|
||||||
SHARED_CA_EXISTS=false
|
SHARED_CA_EXISTS=false
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$SHARED_CA_EXISTS" = false ]; then
|
if [ "$SHARED_CA_EXISTS" = false ]; then
|
||||||
# Generate local shared CA if not available from core server
|
|
||||||
log_warning "Shared CA certificates not found on core server."
|
log_warning "Shared CA certificates not found on core server."
|
||||||
log_info "Generating local shared CA for infrastructure server..."
|
log_info "Please ensure the core server has been set up first and has generated the shared CA certificates."
|
||||||
|
log_info "You can manually copy the certificates later (check both locations on core server):"
|
||||||
openssl genrsa -out "/opt/stacks/core/shared-ca/ca-key.pem" 4096
|
|
||||||
openssl req -new -x509 -days 365 -key "/opt/stacks/core/shared-ca/ca-key.pem" -sha256 -out "/opt/stacks/core/shared-ca/ca.pem" -subj "/C=US/ST=State/L=City/O=Homelab/CN=Homelab-CA"
|
|
||||||
|
|
||||||
log_success "Local shared CA generated"
|
|
||||||
log_info "IMPORTANT: Copy these certificates to your core server at /opt/stacks/core/shared-ca/"
|
|
||||||
log_info "Run this command on your CORE server:"
|
|
||||||
echo " sudo mkdir -p /opt/stacks/core/shared-ca"
|
echo " sudo mkdir -p /opt/stacks/core/shared-ca"
|
||||||
echo " sudo scp $SSH_USER@$SERVER_IP:/opt/stacks/core/shared-ca/ca.pem /opt/stacks/core/shared-ca/"
|
echo " # Try shared-ca location:"
|
||||||
echo " sudo scp $SSH_USER@$SERVER_IP:/opt/stacks/core/shared-ca/ca-key.pem /opt/stacks/core/shared-ca/"
|
echo " sudo scp $SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca.pem /opt/stacks/core/shared-ca/"
|
||||||
|
echo " sudo scp $SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/shared-ca/ca-key.pem /opt/stacks/core/shared-ca/"
|
||||||
|
echo " # Or docker-tls location:"
|
||||||
|
echo " sudo scp $SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/docker-tls/ca.pem /opt/stacks/core/shared-ca/"
|
||||||
|
echo " sudo scp $SSH_USER@$CORE_SERVER_IP:/opt/stacks/core/docker-tls/ca-key.pem /opt/stacks/core/shared-ca/"
|
||||||
echo " sudo chown -R $SSH_USER:$SSH_USER /opt/stacks/core/shared-ca"
|
echo " sudo chown -R $SSH_USER:$SSH_USER /opt/stacks/core/shared-ca"
|
||||||
echo ""
|
echo ""
|
||||||
log_info "After copying, restart the core server's Docker services for the changes to take effect."
|
log_info "Then restart the Docker daemon: sudo systemctl reload docker"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update Docker daemon configuration to use shared CA
|
# Update Docker daemon configuration to use shared CA
|
||||||
|
if [ "$SHARED_CA_EXISTS" = true ]; then
|
||||||
log_info "Updating Docker daemon to use shared CA for TLS..."
|
log_info "Updating Docker daemon to use shared CA for TLS..."
|
||||||
if [ -f "/opt/stacks/core/shared-ca/ca.pem" ]; then
|
if [ -f "/opt/stacks/core/shared-ca/ca.pem" ]; then
|
||||||
# Update daemon.json to use the shared CA for both server and client verification
|
# Update daemon.json to use the shared CA for both server and client verification
|
||||||
@@ -356,12 +467,13 @@ share_certs_with_core() {
|
|||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
sudo cp /tmp/daemon.json /etc/docker/daemon.json
|
sudo cp /tmp/daemon.json /etc/docker/daemon.json
|
||||||
sudo systemctl reload docker
|
sudo systemctl restart docker
|
||||||
log_success "Docker daemon updated to use shared CA"
|
log_success "Docker daemon updated to use shared CA"
|
||||||
log_info "Core server can now securely connect to this Docker daemon using shared CA"
|
log_info "Core server can now securely connect to this Docker daemon using shared CA"
|
||||||
else
|
else
|
||||||
log_warning "Shared CA certificate not found, daemon configuration not updated"
|
log_warning "Shared CA certificate not found, daemon configuration not updated"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
@@ -425,10 +537,7 @@ system_setup() {
|
|||||||
|
|
||||||
# Step 5: Generate shared CA for multi-server TLS
|
# Step 5: Generate shared CA for multi-server TLS
|
||||||
log_info "Step 5/10: Generating shared CA certificate for multi-server TLS..."
|
log_info "Step 5/10: Generating shared CA certificate for multi-server TLS..."
|
||||||
mkdir -p /opt/stacks/core/shared-ca
|
generate_shared_ca
|
||||||
openssl genrsa -out /opt/stacks/core/shared-ca/ca-key.pem 4096
|
|
||||||
openssl req -new -x509 -days 365 -key /opt/stacks/core/shared-ca/ca-key.pem -sha256 -out /opt/stacks/core/shared-ca/ca.pem -subj "/C=US/ST=State/L=City/O=Homelab/CN=Homelab-CA"
|
|
||||||
chown -R "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/shared-ca
|
|
||||||
|
|
||||||
# Step 6: Configure Docker TLS
|
# Step 6: Configure Docker TLS
|
||||||
log_info "Step 6/10: Configuring Docker TLS..."
|
log_info "Step 6/10: Configuring Docker TLS..."
|
||||||
@@ -466,39 +575,9 @@ system_setup() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Deployment function
|
# Deploy Dockge function
|
||||||
perform_deployment() {
|
deploy_dockge() {
|
||||||
log_info "Starting deployment..."
|
log_info "Deploying Dockge stack manager..."
|
||||||
|
|
||||||
# Switch back to regular user if we were running as root
|
|
||||||
if [ "$EUID" -eq 0 ]; then
|
|
||||||
ACTUAL_USER=${SUDO_USER:-$USER}
|
|
||||||
log_info "Switching to user $ACTUAL_USER for deployment..."
|
|
||||||
exec sudo -u "$ACTUAL_USER" "$0" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Source the .env file
|
|
||||||
source "$REPO_DIR/.env"
|
|
||||||
|
|
||||||
# Step 1: Create required directories
|
|
||||||
log_info "Step 1: Creating required directories..."
|
|
||||||
sudo mkdir -p /opt/stacks/core
|
|
||||||
sudo mkdir -p /opt/stacks/infrastructure
|
|
||||||
sudo mkdir -p /opt/stacks/dashboards
|
|
||||||
sudo mkdir -p /opt/dockge
|
|
||||||
sudo chown -R "$USER:$USER" /opt/stacks
|
|
||||||
sudo chown -R "$USER:$USER" /opt/dockge
|
|
||||||
log_success "Directories created"
|
|
||||||
|
|
||||||
# Step 2: Create Docker networks (if they don't exist)
|
|
||||||
log_info "Step 2: Creating Docker networks..."
|
|
||||||
docker network create homelab-network 2>/dev/null && log_success "Created homelab-network" || log_info "homelab-network already exists"
|
|
||||||
docker network create traefik-network 2>/dev/null && log_success "Created traefik-network" || log_info "traefik-network already exists"
|
|
||||||
docker network create media-network 2>/dev/null && log_success "Created media-network" || log_info "media-network already exists"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Step 3: Deploy Dockge (always deployed)
|
|
||||||
log_info "Step 3: Deploying Dockge stack manager..."
|
|
||||||
log_info " - Dockge (Docker Compose Manager)"
|
log_info " - Dockge (Docker Compose Manager)"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -506,15 +585,19 @@ perform_deployment() {
|
|||||||
sudo cp "$REPO_DIR/docker-compose/dockge/docker-compose.yml" /opt/dockge/docker-compose.yml
|
sudo cp "$REPO_DIR/docker-compose/dockge/docker-compose.yml" /opt/dockge/docker-compose.yml
|
||||||
sudo cp "$REPO_DIR/.env" /opt/dockge/.env
|
sudo cp "$REPO_DIR/.env" /opt/dockge/.env
|
||||||
|
|
||||||
|
# Replace placeholders in Dockge compose file
|
||||||
|
replace_env_placeholders "/opt/dockge/docker-compose.yml"
|
||||||
|
|
||||||
# Deploy Dockge stack
|
# Deploy Dockge stack
|
||||||
cd /opt/dockge
|
cd /opt/dockge
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
log_success "Dockge deployed"
|
log_success "Dockge deployed"
|
||||||
echo ""
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
# Deploy core infrastructure
|
# Deploy core stack function
|
||||||
if [ "$DEPLOY_CORE" = true ]; then
|
deploy_core() {
|
||||||
log_info "Step 4: Deploying core infrastructure stack..."
|
log_info "Deploying core stack..."
|
||||||
log_info " - DuckDNS (Dynamic DNS)"
|
log_info " - DuckDNS (Dynamic DNS)"
|
||||||
log_info " - Traefik (Reverse Proxy with SSL)"
|
log_info " - Traefik (Reverse Proxy with SSL)"
|
||||||
log_info " - Authelia (Single Sign-On)"
|
log_info " - Authelia (Single Sign-On)"
|
||||||
@@ -524,6 +607,9 @@ perform_deployment() {
|
|||||||
sudo cp "$REPO_DIR/docker-compose/core/docker-compose.yml" /opt/stacks/core/docker-compose.yml
|
sudo cp "$REPO_DIR/docker-compose/core/docker-compose.yml" /opt/stacks/core/docker-compose.yml
|
||||||
sudo cp "$REPO_DIR/.env" /opt/stacks/core/.env
|
sudo cp "$REPO_DIR/.env" /opt/stacks/core/.env
|
||||||
|
|
||||||
|
# Replace placeholders in core compose file
|
||||||
|
replace_env_placeholders "/opt/stacks/core/docker-compose.yml"
|
||||||
|
|
||||||
# Copy configs
|
# Copy configs
|
||||||
if [ -d "/opt/stacks/core/traefik" ]; then
|
if [ -d "/opt/stacks/core/traefik" ]; then
|
||||||
mv /opt/stacks/core/traefik /opt/stacks/core/traefik.backup.$(date +%Y%m%d_%H%M%S)
|
mv /opt/stacks/core/traefik /opt/stacks/core/traefik.backup.$(date +%Y%m%d_%H%M%S)
|
||||||
@@ -557,22 +643,21 @@ perform_deployment() {
|
|||||||
|
|
||||||
# Generate shared CA for multi-server TLS
|
# Generate shared CA for multi-server TLS
|
||||||
log_info "Generating shared CA certificate for multi-server TLS..."
|
log_info "Generating shared CA certificate for multi-server TLS..."
|
||||||
mkdir -p /opt/stacks/core/shared-ca
|
generate_shared_ca
|
||||||
openssl genrsa -out /opt/stacks/core/shared-ca/ca-key.pem 4096
|
|
||||||
openssl req -new -x509 -days 365 -key /opt/stacks/core/shared-ca/ca-key.pem -sha256 -out /opt/stacks/core/shared-ca/ca.pem -subj "/C=US/ST=State/L=City/O=Homelab/CN=Homelab-CA"
|
# Replace placeholders in core compose file
|
||||||
chown -R "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/shared-ca
|
replace_env_placeholders "/opt/stacks/core/docker-compose.yml"
|
||||||
|
|
||||||
# Deploy core stack
|
# Deploy core stack
|
||||||
cd /opt/stacks/core
|
cd /opt/stacks/core
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
log_success "Core infrastructure deployed"
|
log_success "Core infrastructure deployed"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
}
|
||||||
|
|
||||||
# Deploy infrastructure stack
|
# Deploy infrastructure stack function
|
||||||
if [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
|
deploy_infrastructure() {
|
||||||
step_num=$([ "$DEPLOY_CORE" = true ] && echo "5" || echo "4")
|
log_info "Deploying infrastructure stack..."
|
||||||
log_info "Step $step_num: Deploying infrastructure stack..."
|
|
||||||
log_info " - Pi-hole (DNS Ad Blocker)"
|
log_info " - Pi-hole (DNS Ad Blocker)"
|
||||||
log_info " - Watchtower (Container Updates)"
|
log_info " - Watchtower (Container Updates)"
|
||||||
log_info " - Dozzle (Log Viewer)"
|
log_info " - Dozzle (Log Viewer)"
|
||||||
@@ -584,6 +669,9 @@ perform_deployment() {
|
|||||||
cp "$REPO_DIR/docker-compose/infrastructure/docker-compose.yml" /opt/stacks/infrastructure/docker-compose.yml
|
cp "$REPO_DIR/docker-compose/infrastructure/docker-compose.yml" /opt/stacks/infrastructure/docker-compose.yml
|
||||||
cp "$REPO_DIR/.env" /opt/stacks/infrastructure/.env
|
cp "$REPO_DIR/.env" /opt/stacks/infrastructure/.env
|
||||||
|
|
||||||
|
# Replace placeholders in infrastructure compose file
|
||||||
|
replace_env_placeholders "/opt/stacks/infrastructure/docker-compose.yml"
|
||||||
|
|
||||||
# Copy any additional config directories
|
# Copy any additional config directories
|
||||||
for config_dir in "$REPO_DIR/docker-compose/infrastructure"/*/; do
|
for config_dir in "$REPO_DIR/docker-compose/infrastructure"/*/; do
|
||||||
if [ -d "$config_dir" ] && [ "$(basename "$config_dir")" != "." ]; then
|
if [ -d "$config_dir" ] && [ "$(basename "$config_dir")" != "." ]; then
|
||||||
@@ -597,23 +685,19 @@ perform_deployment() {
|
|||||||
sed -i '/middlewares=authelia@docker/d' /opt/stacks/infrastructure/docker-compose.yml
|
sed -i '/middlewares=authelia@docker/d' /opt/stacks/infrastructure/docker-compose.yml
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Replace placeholders in infrastructure compose file
|
||||||
|
replace_env_placeholders "/opt/stacks/infrastructure/docker-compose.yml"
|
||||||
|
|
||||||
# Deploy infrastructure stack
|
# Deploy infrastructure stack
|
||||||
cd /opt/stacks/infrastructure
|
cd /opt/stacks/infrastructure
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
log_success "Infrastructure stack deployed"
|
log_success "Infrastructure stack deployed"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
}
|
||||||
|
|
||||||
# Deploy dashboard stack
|
# Deploy dashboards stack function
|
||||||
if [ "$DEPLOY_DASHBOARDS" = true ]; then
|
deploy_dashboards() {
|
||||||
if [ "$DEPLOY_CORE" = true ] && [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
|
log_info "Deploying dashboard stack..."
|
||||||
step_num=6
|
|
||||||
elif [ "$DEPLOY_CORE" = true ] || [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
|
|
||||||
step_num=5
|
|
||||||
else
|
|
||||||
step_num=4
|
|
||||||
fi
|
|
||||||
log_info "Step $step_num: Deploying dashboard stack..."
|
|
||||||
log_info " - Homepage (Application Dashboard)"
|
log_info " - Homepage (Application Dashboard)"
|
||||||
log_info " - Homarr (Modern Dashboard)"
|
log_info " - Homarr (Modern Dashboard)"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -625,22 +709,109 @@ perform_deployment() {
|
|||||||
cp "$REPO_DIR/docker-compose/dashboards/docker-compose.yml" /opt/stacks/dashboards/docker-compose.yml
|
cp "$REPO_DIR/docker-compose/dashboards/docker-compose.yml" /opt/stacks/dashboards/docker-compose.yml
|
||||||
cp "$REPO_DIR/.env" /opt/stacks/dashboards/.env
|
cp "$REPO_DIR/.env" /opt/stacks/dashboards/.env
|
||||||
|
|
||||||
|
# Replace placeholders in dashboards compose file
|
||||||
|
replace_env_placeholders "/opt/stacks/dashboards/docker-compose.yml"
|
||||||
|
|
||||||
# Copy homepage config
|
# Copy homepage config
|
||||||
if [ -d "$REPO_DIR/docker-compose/dashboards/homepage" ]; then
|
if [ -d "$REPO_DIR/docker-compose/dashboards/homepage" ]; then
|
||||||
cp -r "$REPO_DIR/docker-compose/dashboards/homepage" /opt/stacks/dashboards/
|
cp -r "$REPO_DIR/docker-compose/dashboards/homepage" /opt/stacks/dashboards/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Replace placeholders in dashboards compose file
|
||||||
|
replace_env_placeholders "/opt/stacks/dashboards/docker-compose.yml"
|
||||||
|
|
||||||
# Deploy dashboards stack
|
# Deploy dashboards stack
|
||||||
cd /opt/stacks/dashboards
|
cd /opt/stacks/dashboards
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
log_success "Dashboard stack deployed"
|
log_success "Dashboard stack deployed"
|
||||||
echo ""
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deployment function
|
||||||
|
perform_deployment() {
|
||||||
|
log_info "Starting deployment..."
|
||||||
|
|
||||||
|
# Initialize missing vars summary
|
||||||
|
MISSING_VARS_SUMMARY=""
|
||||||
|
TLS_ISSUES_SUMMARY=""
|
||||||
|
|
||||||
|
# Switch back to regular user if we were running as root
|
||||||
|
if [ "$EUID" -eq 0 ]; then
|
||||||
|
ACTUAL_USER=${SUDO_USER:-$USER}
|
||||||
|
log_info "Switching to user $ACTUAL_USER for deployment..."
|
||||||
|
exec sudo -u "$ACTUAL_USER" "$0" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Source the .env file
|
||||||
|
source "$REPO_DIR/.env"
|
||||||
|
|
||||||
|
# Step 1: Create required directories
|
||||||
|
log_info "Step 1: Creating required directories..."
|
||||||
|
sudo mkdir -p /opt/stacks/core || { log_error "Failed to create /opt/stacks/core"; exit 1; }
|
||||||
|
sudo mkdir -p /opt/stacks/infrastructure || { log_error "Failed to create /opt/stacks/infrastructure"; exit 1; }
|
||||||
|
sudo mkdir -p /opt/stacks/dashboards || { log_error "Failed to create /opt/stacks/dashboards"; exit 1; }
|
||||||
|
sudo mkdir -p /opt/dockge || { log_error "Failed to create /opt/dockge"; exit 1; }
|
||||||
|
sudo chown -R "$USER:$USER" /opt/stacks
|
||||||
|
sudo chown -R "$USER:$USER" /opt/dockge
|
||||||
|
log_success "Directories created"
|
||||||
|
|
||||||
|
# Step 2: Setup multi-server TLS if needed
|
||||||
|
if [ "$DEPLOY_CORE" = false ]; then
|
||||||
|
setup_multi_server_tls
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 3: Create Docker networks (if they don't exist)
|
||||||
|
log_info "Step $([ "$DEPLOY_CORE" = false ] && echo "3" || echo "2"): Creating Docker networks..."
|
||||||
|
docker network create homelab-network 2>/dev/null && log_success "Created homelab-network" || log_info "homelab-network already exists"
|
||||||
|
docker network create traefik-network 2>/dev/null && log_success "Created traefik-network" || log_info "traefik-network already exists"
|
||||||
|
docker network create media-network 2>/dev/null && log_success "Created media-network" || log_info "media-network already exists"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 4: Deploy Dockge (always deployed)
|
||||||
|
deploy_dockge
|
||||||
|
|
||||||
|
# Deploy core stack
|
||||||
|
if [ "$DEPLOY_CORE" = true ]; then
|
||||||
|
deploy_core
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Deploy infrastructure stack
|
||||||
|
if [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
|
||||||
|
step_num=$([ "$DEPLOY_CORE" = true ] && echo "6" || echo "5")
|
||||||
|
deploy_infrastructure
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Deploy dashboard stack
|
||||||
|
if [ "$DEPLOY_DASHBOARDS" = true ]; then
|
||||||
|
if [ "$DEPLOY_CORE" = true ] && [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
|
||||||
|
step_num=7
|
||||||
|
elif [ "$DEPLOY_CORE" = true ] || [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
|
||||||
|
step_num=6
|
||||||
|
else
|
||||||
|
step_num=5
|
||||||
|
fi
|
||||||
|
deploy_dashboards
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Setup stacks for Dockge
|
# Setup stacks for Dockge
|
||||||
if [ "$SETUP_STACKS" = true ]; then
|
if [ "$SETUP_STACKS" = true ]; then
|
||||||
setup_stacks_for_dockge
|
setup_stacks_for_dockge
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Report any missing variables
|
||||||
|
if [ -n "$MISSING_VARS_SUMMARY" ]; then
|
||||||
|
log_warning "The following environment variables were missing and may cause issues:"
|
||||||
|
echo "$MISSING_VARS_SUMMARY"
|
||||||
|
log_info "Please update your .env file and redeploy affected stacks."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Report any TLS issues
|
||||||
|
if [ -n "$TLS_ISSUES_SUMMARY" ]; then
|
||||||
|
echo ""
|
||||||
|
log_warning "TLS Configuration Issues Detected:"
|
||||||
|
echo "$TLS_ISSUES_SUMMARY"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Setup Docker TLS function
|
# Setup Docker TLS function
|
||||||
@@ -675,7 +846,7 @@ setup_docker_tls() {
|
|||||||
openssl x509 -req -days 365 -in "$TLS_DIR/client.csr" -CA "$TLS_DIR/ca.pem" -CAkey "$TLS_DIR/ca-key.pem" -CAcreateserial -out "$TLS_DIR/client-cert.pem"
|
openssl x509 -req -days 365 -in "$TLS_DIR/client.csr" -CA "$TLS_DIR/ca.pem" -CAkey "$TLS_DIR/ca-key.pem" -CAcreateserial -out "$TLS_DIR/client-cert.pem"
|
||||||
|
|
||||||
# Configure Docker daemon
|
# Configure Docker daemon
|
||||||
cat > /etc/docker/daemon.json <<EOF
|
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
|
||||||
{
|
{
|
||||||
"tls": true,
|
"tls": true,
|
||||||
"tlsverify": true,
|
"tlsverify": true,
|
||||||
@@ -686,11 +857,11 @@ setup_docker_tls() {
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Update systemd service
|
# Update systemd service
|
||||||
sed -i 's|-H fd://|-H fd:// -H tcp://0.0.0.0:2376|' /lib/systemd/system/docker.service
|
sudo sed -i 's|-H fd://|-H fd:// -H tcp://0.0.0.0:2376|' /lib/systemd/system/docker.service
|
||||||
|
|
||||||
# Reload and restart Docker
|
# Reload and restart Docker
|
||||||
systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
systemctl restart docker
|
sudo systemctl restart docker
|
||||||
|
|
||||||
log_success "Docker TLS configured on port 2376"
|
log_success "Docker TLS configured on port 2376"
|
||||||
}
|
}
|
||||||
@@ -710,6 +881,9 @@ setup_stacks_for_dockge() {
|
|||||||
cp "$REPO_STACK_DIR/docker-compose.yml" "$STACK_DIR/docker-compose.yml"
|
cp "$REPO_STACK_DIR/docker-compose.yml" "$STACK_DIR/docker-compose.yml"
|
||||||
cp "$REPO_DIR/.env" "$STACK_DIR/.env"
|
cp "$REPO_DIR/.env" "$STACK_DIR/.env"
|
||||||
|
|
||||||
|
# Replace placeholders in the compose file
|
||||||
|
replace_env_placeholders "$STACK_DIR/docker-compose.yml"
|
||||||
|
|
||||||
# Copy any additional config directories
|
# Copy any additional config directories
|
||||||
for config_dir in "$REPO_STACK_DIR"/*/; do
|
for config_dir in "$REPO_STACK_DIR"/*/; do
|
||||||
if [ -d "$config_dir" ] && [ "$(basename "$config_dir")" != "." ]; then
|
if [ -d "$config_dir" ] && [ "$(basename "$config_dir")" != "." ]; then
|
||||||
@@ -749,6 +923,7 @@ show_main_menu() {
|
|||||||
echo "3) 🔧 Infrastructure Only"
|
echo "3) 🔧 Infrastructure Only"
|
||||||
echo " - Deploy Dockge and monitoring tools"
|
echo " - Deploy Dockge and monitoring tools"
|
||||||
echo " - Requires existing Traefik (from previous setup)"
|
echo " - Requires existing Traefik (from previous setup)"
|
||||||
|
echo " - Configures TLS for remote Docker access (Sablier)"
|
||||||
echo " - Services accessible without authentication"
|
echo " - Services accessible without authentication"
|
||||||
echo " - All stacks prepared for Dockge"
|
echo " - All stacks prepared for Dockge"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -783,7 +958,7 @@ main() {
|
|||||||
log_info "Selected: Core Only"
|
log_info "Selected: Core Only"
|
||||||
DEPLOY_CORE=true
|
DEPLOY_CORE=true
|
||||||
DEPLOY_INFRASTRUCTURE=false
|
DEPLOY_INFRASTRUCTURE=false
|
||||||
DEPLOY_DASHBOARDS=false
|
DEPLOY_DASHBOARDS=true
|
||||||
SETUP_STACKS=true
|
SETUP_STACKS=true
|
||||||
;;
|
;;
|
||||||
3)
|
3)
|
||||||
@@ -864,7 +1039,7 @@ main() {
|
|||||||
|
|
||||||
# Handle certificate sharing for infrastructure-only deployments
|
# Handle certificate sharing for infrastructure-only deployments
|
||||||
if [ "$MAIN_CHOICE" = "3" ]; then
|
if [ "$MAIN_CHOICE" = "3" ]; then
|
||||||
share_certs_with_core
|
get_certs_from_core_server
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Perform deployment
|
# Perform deployment
|
||||||
|
|||||||
Reference in New Issue
Block a user