191 lines
6.1 KiB
Bash
Executable File
191 lines
6.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
if [[ ${EUID} -ne 0 ]]; then
|
|
echo "Run this installer with sudo." >&2
|
|
exit 1
|
|
fi
|
|
|
|
readonly SOURCE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly PUBLIC_KEY_FILE="${1:-}"
|
|
readonly NGINX_LINK="/etc/nginx/sites-enabled/eusrr"
|
|
readonly UPSTREAM_FILE="/etc/nginx/conf.d/eusrr-active-upstreams.conf"
|
|
|
|
if [[ -z ${PUBLIC_KEY_FILE} || ! -f ${PUBLIC_KEY_FILE} ]]; then
|
|
echo "Usage: $0 /path/to/gitea-runner.pub" >&2
|
|
exit 2
|
|
fi
|
|
if ! id deploy >/dev/null 2>&1; then
|
|
echo "The deploy system account does not exist." >&2
|
|
exit 3
|
|
fi
|
|
if [[ ! -d ${SOURCE_DIR}/systemd ]]; then
|
|
echo "Systemd templates are missing from ${SOURCE_DIR}." >&2
|
|
exit 4
|
|
fi
|
|
|
|
read -r key_type key_body _ <"${PUBLIC_KEY_FILE}"
|
|
if [[ ${key_type} != "ssh-ed25519" || -z ${key_body:-} ]]; then
|
|
echo "Expected an Ed25519 public key." >&2
|
|
exit 5
|
|
fi
|
|
|
|
nginx_config="$(readlink -f "${NGINX_LINK}")"
|
|
nginx_backup="${nginx_config}.bak.blue-green.$(date -u +%Y%m%dT%H%M%SZ)"
|
|
cp -a "${nginx_config}" "${nginx_backup}"
|
|
upstream_existed=0
|
|
upstream_backup=""
|
|
if [[ -f ${UPSTREAM_FILE} ]]; then
|
|
upstream_existed=1
|
|
upstream_backup="${UPSTREAM_FILE}.bak.$(date -u +%Y%m%dT%H%M%SZ)"
|
|
cp -a "${UPSTREAM_FILE}" "${upstream_backup}"
|
|
fi
|
|
|
|
install_complete=0
|
|
temporary_files=()
|
|
cleanup() {
|
|
local status=$?
|
|
for file in "${temporary_files[@]:-}"; do
|
|
[[ -n ${file} ]] && rm -f "${file}"
|
|
done
|
|
if [[ ${install_complete} -eq 0 ]]; then
|
|
cp -a "${nginx_backup}" "${nginx_config}"
|
|
if [[ ${upstream_existed} -eq 1 ]]; then
|
|
cp -a "${upstream_backup}" "${UPSTREAM_FILE}"
|
|
else
|
|
rm -f "${UPSTREAM_FILE}"
|
|
fi
|
|
nginx -t >/dev/null 2>&1 && systemctl reload nginx || true
|
|
fi
|
|
exit "${status}"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
install -o root -g root -m 0755 "${SOURCE_DIR}/eusrr-deploy" /usr/local/sbin/eusrr-deploy
|
|
install -o root -g root -m 0755 "${SOURCE_DIR}/eusrr-deploy-ssh" /usr/local/sbin/eusrr-deploy-ssh
|
|
for unit in "${SOURCE_DIR}"/systemd/*.service; do
|
|
install -o root -g root -m 0644 "${unit}" "/etc/systemd/system/$(basename "${unit}")"
|
|
done
|
|
|
|
install -d -o deploy -g eusrr -m 2775 /srv/eusrr-releases /srv/eusrr-slots
|
|
install -d -o deploy -g www-data -m 0755 /srv/eusrr-shared /srv/eusrr-shared/next-static
|
|
if [[ -d /srv/eusrr/frontend/.next/static ]]; then
|
|
rsync -a /srv/eusrr/frontend/.next/static/ /srv/eusrr-shared/next-static/
|
|
fi
|
|
chown -R deploy:www-data /srv/eusrr-shared
|
|
find /srv/eusrr-shared -type d -exec chmod 0755 {} +
|
|
find /srv/eusrr-shared -type f -exec chmod 0644 {} +
|
|
|
|
ln -sfn /srv/eusrr /srv/eusrr-current.new
|
|
mv -Tf /srv/eusrr-current.new /srv/eusrr-current
|
|
|
|
if [[ ! -f ${UPSTREAM_FILE} ]]; then
|
|
cat >"${UPSTREAM_FILE}" <<'EOF'
|
|
upstream eusrr_backend {
|
|
server 127.0.0.1:9000;
|
|
keepalive 32;
|
|
}
|
|
|
|
upstream eusrr_frontend {
|
|
server 127.0.0.1:3000;
|
|
keepalive 32;
|
|
}
|
|
EOF
|
|
chmod 0644 "${UPSTREAM_FILE}"
|
|
fi
|
|
|
|
NGINX_CONFIG="${nginx_config}" python3 <<'PY'
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
path = Path(os.environ["NGINX_CONFIG"])
|
|
text = path.read_text(encoding="utf-8")
|
|
|
|
next_static = re.compile(
|
|
r"^ location /_next/static/ \{\n.*?^ \}",
|
|
flags=re.MULTILINE | re.DOTALL,
|
|
)
|
|
replacement = """ location /_next/static/ {
|
|
alias /srv/eusrr-shared/next-static/;
|
|
autoindex off;
|
|
expires 365d;
|
|
add_header Cache-Control \"public, immutable\";
|
|
}"""
|
|
text, static_blocks = next_static.subn(replacement, text)
|
|
if static_blocks not in (0, 2):
|
|
raise SystemExit(f"Expected zero or two Next.js static blocks, found {static_blocks}")
|
|
|
|
text = text.replace("proxy_pass http://127.0.0.1:9000;", "proxy_pass http://eusrr_backend;")
|
|
text = text.replace("proxy_pass http://127.0.0.1:3000;", "proxy_pass http://eusrr_frontend;")
|
|
text = text.replace(
|
|
"alias /srv/eusrr/backend/staticfiles/;",
|
|
"alias /srv/eusrr-current/backend/staticfiles/;",
|
|
)
|
|
|
|
required = (
|
|
"proxy_pass http://eusrr_backend;",
|
|
"proxy_pass http://eusrr_frontend;",
|
|
"alias /srv/eusrr-shared/next-static/;",
|
|
"alias /srv/eusrr-current/backend/staticfiles/;",
|
|
)
|
|
for marker in required:
|
|
if marker not in text:
|
|
raise SystemExit(f"Nginx transformation marker is missing: {marker}")
|
|
if "proxy_pass http://127.0.0.1:9000;" in text or "proxy_pass http://127.0.0.1:3000;" in text:
|
|
raise SystemExit("Legacy direct upstreams remain in Nginx configuration")
|
|
|
|
path.write_text(text, encoding="utf-8")
|
|
PY
|
|
|
|
install -d -o root -g root -m 0755 /etc/eusrr/slots /var/lib/eusrr-deploy
|
|
cat >/etc/eusrr/slots/blue.env <<'EOF'
|
|
BACKEND_PORT=9001
|
|
PORT=3001
|
|
HOSTNAME=127.0.0.1
|
|
EOF
|
|
cat >/etc/eusrr/slots/green.env <<'EOF'
|
|
BACKEND_PORT=9002
|
|
PORT=3002
|
|
HOSTNAME=127.0.0.1
|
|
EOF
|
|
chmod 0644 /etc/eusrr/slots/blue.env /etc/eusrr/slots/green.env
|
|
if [[ ! -f /var/lib/eusrr-deploy/active-slot ]]; then
|
|
printf '%s\n' legacy >/var/lib/eusrr-deploy/active-slot
|
|
fi
|
|
|
|
install -d -o deploy -g deploy -m 0755 /var/log/celery
|
|
install -d -o deploy -g deploy -m 0700 /var/backups/eusrr/deploy
|
|
touch /var/log/eusrr-deploy.log
|
|
chown root:root /var/log/eusrr-deploy.log
|
|
chmod 0600 /var/log/eusrr-deploy.log
|
|
|
|
sudoers_tmp="$(mktemp)"
|
|
temporary_files+=("${sudoers_tmp}")
|
|
printf '%s\n' 'deploy ALL=(root) NOPASSWD: /usr/local/sbin/eusrr-deploy *' >"${sudoers_tmp}"
|
|
chmod 0440 "${sudoers_tmp}"
|
|
visudo -cf "${sudoers_tmp}" >/dev/null
|
|
install -o root -g root -m 0440 "${sudoers_tmp}" /etc/sudoers.d/eusrr-deploy
|
|
|
|
deploy_home="$(getent passwd deploy | cut -d: -f6)"
|
|
install -d -o deploy -g deploy -m 0700 "${deploy_home}/.ssh"
|
|
authorized_keys="${deploy_home}/.ssh/authorized_keys"
|
|
touch "${authorized_keys}"
|
|
chown deploy:deploy "${authorized_keys}"
|
|
chmod 0600 "${authorized_keys}"
|
|
filtered_keys="$(mktemp)"
|
|
temporary_files+=("${filtered_keys}")
|
|
grep -v ' eusrr-gitea-runner$' "${authorized_keys}" >"${filtered_keys}" || true
|
|
printf '%s %s %s %s\n' \
|
|
'command="/usr/local/sbin/eusrr-deploy-ssh",restrict' \
|
|
"${key_type}" "${key_body}" 'eusrr-gitea-runner' >>"${filtered_keys}"
|
|
install -o deploy -g deploy -m 0600 "${filtered_keys}" "${authorized_keys}"
|
|
|
|
systemctl daemon-reload
|
|
nginx -t
|
|
systemctl reload nginx
|
|
sudo -u deploy sudo -n /usr/local/sbin/eusrr-deploy --self-test
|
|
|
|
install_complete=1
|
|
echo "Restricted blue-green Gitea deployment installed successfully."
|