287 lines
8.7 KiB
HCL
287 lines
8.7 KiB
HCL
terraform {
|
|
required_version = ">= 1.0"
|
|
required_providers {
|
|
null = {
|
|
source = "hashicorp/null"
|
|
version = "~> 3.2"
|
|
}
|
|
}
|
|
}
|
|
|
|
locals {
|
|
compose_file = templatefile("${path.module}/templates/docker-compose.yml.tftpl", {})
|
|
default_conf = templatefile("${path.module}/templates/default.conf.tftpl", {
|
|
server_name = var.server_name
|
|
backend_host = var.backend_host
|
|
demos_backend_port = var.demos_backend_port
|
|
gitea_backend_port = var.gitea_backend_port
|
|
})
|
|
default_vcl = templatefile("${path.module}/templates/default.vcl.tftpl", {
|
|
backend_host = var.backend_host
|
|
backend_port = tostring(var.backend_port)
|
|
})
|
|
haproxy_cfg = templatefile("${path.module}/templates/haproxy.cfg.tftpl", {
|
|
stats_user = var.haproxy_stats_user
|
|
stats_password = var.haproxy_stats_password
|
|
})
|
|
squid_conf = templatefile("${path.module}/templates/squid.conf.tftpl", {
|
|
backend_host = var.backend_host
|
|
backend_port = tostring(var.backend_port)
|
|
})
|
|
config_hash = sha256(join("\n---\n", [
|
|
local.compose_file,
|
|
local.default_conf,
|
|
local.default_vcl,
|
|
local.haproxy_cfg,
|
|
local.squid_conf,
|
|
]))
|
|
}
|
|
|
|
resource "null_resource" "edge_services" {
|
|
triggers = {
|
|
host = var.edge_host
|
|
user = var.edge_user
|
|
install_dir = var.edge_install_dir
|
|
server_name = var.server_name
|
|
enable_letsencrypt = tostring(var.enable_letsencrypt)
|
|
letsencrypt_email = var.letsencrypt_email
|
|
letsencrypt_staging = tostring(var.letsencrypt_staging)
|
|
certbot_version = "2"
|
|
config_hash = local.config_hash
|
|
}
|
|
|
|
connection {
|
|
type = "ssh"
|
|
user = self.triggers.user
|
|
private_key = file(var.edge_ssh_key_path)
|
|
host = self.triggers.host
|
|
}
|
|
|
|
provisioner "remote-exec" {
|
|
inline = [
|
|
"rm -rf /tmp/homelab-edge",
|
|
"mkdir -p /tmp/homelab-edge/config_files",
|
|
]
|
|
}
|
|
|
|
provisioner "file" {
|
|
content = local.compose_file
|
|
destination = "/tmp/homelab-edge/docker-compose.yml"
|
|
}
|
|
|
|
provisioner "file" {
|
|
content = local.default_conf
|
|
destination = "/tmp/homelab-edge/config_files/default.conf"
|
|
}
|
|
|
|
provisioner "file" {
|
|
content = local.default_vcl
|
|
destination = "/tmp/homelab-edge/config_files/default.vcl"
|
|
}
|
|
|
|
provisioner "file" {
|
|
content = local.haproxy_cfg
|
|
destination = "/tmp/homelab-edge/config_files/haproxy.cfg"
|
|
}
|
|
|
|
provisioner "file" {
|
|
content = local.squid_conf
|
|
destination = "/tmp/homelab-edge/config_files/squid.conf"
|
|
}
|
|
|
|
provisioner "remote-exec" {
|
|
inline = [
|
|
<<EOT
|
|
set -eu
|
|
|
|
install_dir="${self.triggers.install_dir}"
|
|
server_name="${self.triggers.server_name}"
|
|
enable_letsencrypt="${self.triggers.enable_letsencrypt}"
|
|
letsencrypt_email="${self.triggers.letsencrypt_email}"
|
|
letsencrypt_staging="${self.triggers.letsencrypt_staging}"
|
|
certbot_image="certbot/certbot:latest"
|
|
|
|
install_missing_packages() {
|
|
missing_packages=""
|
|
for package in "$@"; do
|
|
if ! dpkg-query -W -f='$${Status}' "$package" 2>/dev/null | grep -q "install ok installed"; then
|
|
missing_packages="$missing_packages $package"
|
|
fi
|
|
done
|
|
if [ -n "$missing_packages" ]; then
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends $missing_packages
|
|
fi
|
|
}
|
|
|
|
install_missing_packages ca-certificates curl openssl
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
curl -fsSL https://get.docker.com | sudo sh
|
|
fi
|
|
|
|
if ! sudo docker compose version >/dev/null 2>&1; then
|
|
install_missing_packages docker-compose-plugin
|
|
fi
|
|
|
|
sudo mkdir -p \
|
|
"$install_dir/config_files" \
|
|
"$install_dir/certs" \
|
|
"$install_dir/certbot/www" \
|
|
"$install_dir/letsencrypt"
|
|
sudo cp /tmp/homelab-edge/docker-compose.yml "$install_dir/docker-compose.yml"
|
|
sudo cp /tmp/homelab-edge/config_files/default.conf "$install_dir/config_files/default.conf"
|
|
sudo cp /tmp/homelab-edge/config_files/default.vcl "$install_dir/config_files/default.vcl"
|
|
sudo cp /tmp/homelab-edge/config_files/haproxy.cfg "$install_dir/config_files/haproxy.cfg"
|
|
sudo cp /tmp/homelab-edge/config_files/squid.conf "$install_dir/config_files/squid.conf"
|
|
|
|
if [ ! -s "$install_dir/certs/current.crt" ] || [ ! -s "$install_dir/certs/current.key" ]; then
|
|
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
|
-subj "/CN=$server_name" \
|
|
-keyout "$install_dir/certs/current.key" \
|
|
-out "$install_dir/certs/current.crt"
|
|
fi
|
|
|
|
deploy_current_certificate() {
|
|
if ! sudo test -s "$install_dir/letsencrypt/live/$server_name/fullchain.pem" ||
|
|
! sudo test -s "$install_dir/letsencrypt/live/$server_name/privkey.pem"; then
|
|
return 1
|
|
fi
|
|
|
|
sudo cp -L "$install_dir/letsencrypt/live/$server_name/fullchain.pem" "$install_dir/certs/current.crt"
|
|
sudo cp -L "$install_dir/letsencrypt/live/$server_name/privkey.pem" "$install_dir/certs/current.key"
|
|
sudo chmod 0644 "$install_dir/certs/current.crt"
|
|
sudo chmod 0600 "$install_dir/certs/current.key"
|
|
}
|
|
|
|
install_renewal_timer() {
|
|
sudo tee /usr/local/sbin/homelab-edge-renew-certs.sh >/dev/null <<RENEW_EOT
|
|
#!/bin/sh
|
|
set -eu
|
|
|
|
docker run --rm -v "$install_dir/letsencrypt:/etc/letsencrypt" -v "$install_dir/certbot/www:/var/www/certbot" "$certbot_image" renew --webroot -w /var/www/certbot --quiet
|
|
|
|
if [ -s "$install_dir/letsencrypt/live/$server_name/fullchain.pem" ] &&
|
|
[ -s "$install_dir/letsencrypt/live/$server_name/privkey.pem" ]; then
|
|
cp -L "$install_dir/letsencrypt/live/$server_name/fullchain.pem" "$install_dir/certs/current.crt"
|
|
cp -L "$install_dir/letsencrypt/live/$server_name/privkey.pem" "$install_dir/certs/current.key"
|
|
chmod 0644 "$install_dir/certs/current.crt"
|
|
chmod 0600 "$install_dir/certs/current.key"
|
|
cd "$install_dir"
|
|
docker compose exec -T nginx-dev nginx -s reload || docker compose restart nginx-dev
|
|
fi
|
|
RENEW_EOT
|
|
sudo chmod 0755 /usr/local/sbin/homelab-edge-renew-certs.sh
|
|
|
|
sudo tee /etc/systemd/system/homelab-edge-renew-certs.service >/dev/null <<'SERVICE_EOT'
|
|
[Unit]
|
|
Description=Renew Homelab Edge TLS certificates
|
|
After=docker.service network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/sbin/homelab-edge-renew-certs.sh
|
|
SERVICE_EOT
|
|
|
|
sudo tee /etc/systemd/system/homelab-edge-renew-certs.timer >/dev/null <<'TIMER_EOT'
|
|
[Unit]
|
|
Description=Renew Homelab Edge TLS certificates twice daily
|
|
|
|
[Timer]
|
|
OnCalendar=*-*-* 03,15:17:00
|
|
RandomizedDelaySec=30m
|
|
Persistent=true
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
TIMER_EOT
|
|
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now homelab-edge-renew-certs.timer >/dev/null
|
|
}
|
|
|
|
check_edge_health() {
|
|
if ! curl "$@" >/dev/null; then
|
|
sudo docker compose ps || true
|
|
sudo docker compose logs --tail=80 nginx-dev || true
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
cleanup_legacy_edge_containers() {
|
|
local container
|
|
|
|
for container in nginx-dev haproxy-dev varnish-dev squid-dev; do
|
|
if sudo docker container inspect "$container" >/dev/null 2>&1; then
|
|
sudo docker rm -f "$container" >/dev/null
|
|
fi
|
|
done
|
|
}
|
|
|
|
cd "$install_dir"
|
|
cleanup_legacy_edge_containers
|
|
sudo docker compose pull
|
|
sudo docker compose up -d --remove-orphans
|
|
sudo docker compose ps
|
|
|
|
if [ "$enable_letsencrypt" = "true" ]; then
|
|
email_args="--register-unsafely-without-email"
|
|
if [ -n "$letsencrypt_email" ]; then
|
|
email_args="--email $letsencrypt_email"
|
|
fi
|
|
|
|
staging_args=""
|
|
if [ "$letsencrypt_staging" = "true" ]; then
|
|
staging_args="--staging"
|
|
fi
|
|
|
|
certbot_log="$(mktemp)"
|
|
if ! sudo docker run --rm \
|
|
-v "$install_dir/letsencrypt:/etc/letsencrypt" \
|
|
-v "$install_dir/certbot/www:/var/www/certbot" \
|
|
"$certbot_image" certonly \
|
|
--webroot \
|
|
-w /var/www/certbot \
|
|
-d "$server_name" \
|
|
--preferred-challenges http \
|
|
--agree-tos \
|
|
--non-interactive \
|
|
--keep-until-expiring \
|
|
$email_args \
|
|
$staging_args > "$certbot_log" 2>&1; then
|
|
cat "$certbot_log"
|
|
if grep -Eq "Certificate not yet due for renewal|no action taken" "$certbot_log" &&
|
|
sudo test -s "$install_dir/letsencrypt/live/$server_name/fullchain.pem" &&
|
|
sudo test -s "$install_dir/letsencrypt/live/$server_name/privkey.pem"; then
|
|
echo "Using existing Let's Encrypt certificate for $server_name"
|
|
else
|
|
rm -f "$certbot_log"
|
|
exit 1
|
|
fi
|
|
else
|
|
cat "$certbot_log"
|
|
fi
|
|
rm -f "$certbot_log"
|
|
|
|
deploy_current_certificate
|
|
sudo docker compose exec -T nginx-dev nginx -s reload || sudo docker compose restart nginx-dev
|
|
install_renewal_timer
|
|
check_edge_health -fsS --connect-timeout 10 --resolve "$server_name:443:127.0.0.1" "https://$server_name/edge-health"
|
|
else
|
|
sudo systemctl disable --now homelab-edge-renew-certs.timer >/dev/null 2>&1 || true
|
|
check_edge_health -kfsS --connect-timeout 10 https://127.0.0.1/edge-health
|
|
fi
|
|
EOT
|
|
]
|
|
}
|
|
}
|
|
|
|
output "edge_host" {
|
|
value = var.edge_host
|
|
}
|
|
|
|
output "edge_install_dir" {
|
|
value = var.edge_install_dir
|
|
}
|