7484a0e034
- Dual-mode operation: standalone + c2itall integrated (env var detection)
- SSH keys moved to ~/.ssh/c2deploy_ph-{id} with per-deployment known_hosts
- Ansible output streaming with filtered console + full log capture
- Deployment management menu: discover, SSH, teardown existing deployments
- Cert setup script (setup-cert.sh) deployed to servers for post-DNS LE certs
- Matrix hardening: unique secrets, SSRF protection, rate limits, nginx security headers
- Base hardening: fail2ban systemd backend (Debian 12), SSH limits, nginx jails
- Add-matrix-user helper script deployed to all Matrix servers
- .env support for standalone credential storage
- Config key rename: deploy_id → deployment_id (with backward compat)
- Provider cleanup playbooks for teardown
- Test suite with 50 tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
121 lines
4.4 KiB
Django/Jinja
121 lines
4.4 KiB
Django/Jinja
#!/usr/bin/env bash
|
|
# Phantom — Let's Encrypt Certificate Setup
|
|
# Deployed by phantom to {{ ansible_host | default('this server') }}
|
|
# Run this script after DNS has propagated to this server's IP.
|
|
set -euo pipefail
|
|
|
|
DOMAIN="{{ _tls_domain }}"
|
|
SERVER_IP=$(hostname -I | awk '{print $1}')
|
|
|
|
echo "============================================"
|
|
echo " Phantom — Certificate Setup"
|
|
echo "============================================"
|
|
echo " Domain: ${DOMAIN}"
|
|
echo " Server IP: ${SERVER_IP}"
|
|
echo ""
|
|
|
|
# ── DNS Validation ──────────────────────────────────────────────────────
|
|
echo "[*] Checking DNS resolution for ${DOMAIN}..."
|
|
DNS_IP=$(dig +short "${DOMAIN}" @1.1.1.1 2>/dev/null | tail -1)
|
|
|
|
if [ -z "${DNS_IP}" ]; then
|
|
echo "[-] DNS lookup failed — ${DOMAIN} does not resolve."
|
|
echo " Point your DNS A record to: ${SERVER_IP}"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${DNS_IP}" != "${SERVER_IP}" ]; then
|
|
echo "[-] DNS mismatch!"
|
|
echo " ${DOMAIN} resolves to: ${DNS_IP}"
|
|
echo " This server's IP: ${SERVER_IP}"
|
|
echo " Update your DNS A record to point to ${SERVER_IP}"
|
|
exit 1
|
|
fi
|
|
|
|
echo "[+] DNS OK — ${DOMAIN} → ${DNS_IP}"
|
|
|
|
# ── HTTP Reachability Check ─────────────────────────────────────────────
|
|
echo "[*] Verifying HTTP reachability..."
|
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://${DOMAIN}/" --max-time 10 2>/dev/null || echo "000")
|
|
|
|
if [ "${HTTP_CODE}" = "000" ]; then
|
|
echo "[!] Warning: HTTP request to ${DOMAIN} failed (timeout or connection refused)"
|
|
echo " Certbot may fail if port 80 is not reachable."
|
|
read -rp " Continue anyway? [y/N] " CONT
|
|
[ "${CONT}" = "y" ] || exit 1
|
|
else
|
|
echo "[+] HTTP reachable (status ${HTTP_CODE})"
|
|
fi
|
|
|
|
# ── Certbot ─────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "[*] Running certbot for ${DOMAIN}..."
|
|
|
|
# Check if nginx is running — use webroot if so, standalone otherwise
|
|
if systemctl is-active --quiet nginx 2>/dev/null; then
|
|
echo " Using webroot mode (nginx running)"
|
|
mkdir -p /var/www/certbot
|
|
certbot certonly --webroot -w /var/www/certbot \
|
|
-d "${DOMAIN}" \
|
|
--non-interactive \
|
|
--agree-tos \
|
|
{% if certbot_email is defined and certbot_email %}
|
|
--email "{{ certbot_email }}" \
|
|
{% else %}
|
|
--register-unsafely-without-email \
|
|
{% endif %}
|
|
--force-renewal
|
|
else
|
|
echo " Using standalone mode (nginx not running)"
|
|
certbot certonly --standalone \
|
|
-d "${DOMAIN}" \
|
|
--non-interactive \
|
|
--agree-tos \
|
|
{% if certbot_email is defined and certbot_email %}
|
|
--email "{{ certbot_email }}" \
|
|
{% else %}
|
|
--register-unsafely-without-email \
|
|
{% endif %}
|
|
--force-renewal
|
|
fi
|
|
|
|
if [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then
|
|
echo "[-] Certbot failed — certificate not found."
|
|
exit 1
|
|
fi
|
|
|
|
echo "[+] Certificate obtained successfully."
|
|
|
|
# ── Update nginx to use LE cert ─────────────────────────────────────────
|
|
echo "[*] Updating nginx configuration..."
|
|
|
|
SELF_CERT="/etc/ssl/certs/${DOMAIN}-selfsigned.crt"
|
|
SELF_KEY="/etc/ssl/private/${DOMAIN}-selfsigned.key"
|
|
LE_CERT="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
|
|
LE_KEY="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
|
|
|
|
# Replace self-signed cert paths with LE cert paths in all nginx configs
|
|
for CONF in /etc/nginx/sites-enabled/* /etc/nginx/conf.d/*; do
|
|
[ -f "${CONF}" ] || continue
|
|
if grep -q "${SELF_CERT}" "${CONF}" 2>/dev/null; then
|
|
sed -i "s|${SELF_CERT}|${LE_CERT}|g" "${CONF}"
|
|
sed -i "s|${SELF_KEY}|${LE_KEY}|g" "${CONF}"
|
|
echo " Updated: ${CONF}"
|
|
fi
|
|
done
|
|
|
|
# Test and reload nginx
|
|
if nginx -t 2>/dev/null; then
|
|
systemctl reload nginx
|
|
echo "[+] nginx reloaded with Let's Encrypt certificate."
|
|
else
|
|
echo "[-] nginx config test failed — check configuration manually."
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo " Certificate setup complete!"
|
|
echo " Domain: https://${DOMAIN}"
|
|
echo "============================================"
|