538 lines
18 KiB
Bash
538 lines
18 KiB
Bash
#!/usr/bin/env bash
|
|
# bonfire_turnkey_asdf_fixed.sh
|
|
# All-in-one Bonfire installer using ASDF-managed Erlang/Elixir/Node (fixed: early curl/gnupg + pgdg key)
|
|
# Target: Ubuntu 24.04 / Debian 12+
|
|
#
|
|
# Run as root:
|
|
# sudo bash ./bonfire_turnkey_asdf_fixed.sh
|
|
#
|
|
# Notes:
|
|
# - Building Erlang/Elixir with asdf may take a long time on first run.
|
|
# - By default the script checks DNS A/AAAA for the provided domain; use --skip-dns-check to bypass.
|
|
# - This script attempts to be idempotent where reasonable.
|
|
set -euo pipefail
|
|
|
|
### ---------------------------
|
|
### Configuration defaults
|
|
### ---------------------------
|
|
APP_USER="bonfire"
|
|
APP_HOME="/opt/${APP_USER}"
|
|
APP_DIR="${APP_HOME}/app"
|
|
APP_PORT="4000"
|
|
PG_DB="bonfire"
|
|
PG_USER_DEFAULT="bonfire_user"
|
|
PG_VER_PREFERRED="17"
|
|
ASDF_VERSION="v0.14.0"
|
|
KERL_CONFIGURE_OPTIONS="--without-javac --without-wx"
|
|
SKIP_DNS_CHECK=0
|
|
|
|
### ---------------------------
|
|
### Helpers
|
|
### ---------------------------
|
|
log(){ printf "\n\033[1;36m==> %s\033[0m\n" "$*"; }
|
|
info(){ printf "\033[1;32m[info]\033[0m %s\n" "$*"; }
|
|
warn(){ printf "\033[1;33m[warn]\033[0m %s\n" "$*"; }
|
|
err(){ printf "\033[1;31m[error]\033[0m %s\n" "$*"; }
|
|
die(){ err "$*"; exit 1; }
|
|
|
|
require_root(){
|
|
if [[ $EUID -ne 0 ]]; then
|
|
die "This script must be run as root (sudo)."
|
|
fi
|
|
}
|
|
require_root
|
|
|
|
### ---------------------------
|
|
### CLI args
|
|
### ---------------------------
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--skip-dns-check) SKIP_DNS_CHECK=1; shift;;
|
|
*) die "Unknown argument: $1";;
|
|
esac
|
|
done
|
|
|
|
### ---------------------------
|
|
### Interactive prompts
|
|
### ---------------------------
|
|
read -rp "Enter your domain (FQDN, e.g. bonfire.example.com): " DOMAIN
|
|
while [[ -z "$DOMAIN" ]]; do read -rp "Domain cannot be empty. Enter domain: " DOMAIN; done
|
|
|
|
read -rp "Contact email for Let's Encrypt (admin@${DOMAIN}): " EMAIL
|
|
while [[ -z "$EMAIL" ]]; do read -rp "Email cannot be empty. Enter contact email: " EMAIL; done
|
|
|
|
read -rp "Bonfire flavour [social|ember|community|cooperation] (default: social): " FLAVOUR
|
|
FLAVOUR=${FLAVOUR:-social}
|
|
|
|
read -rp "PostgreSQL role to create (default: ${PG_USER_DEFAULT}): " PG_USER
|
|
PG_USER=${PG_USER:-$PG_USER_DEFAULT}
|
|
PG_PASS="$(openssl rand -base64 24)"
|
|
|
|
log "Inputs summary:"
|
|
info "Domain: ${DOMAIN}"
|
|
info "Email: ${EMAIL}"
|
|
info "Flavour: ${FLAVOUR}"
|
|
info "Postgres role: ${PG_USER} (password auto-generated)"
|
|
|
|
### ---------------------------
|
|
### Validate FQDN (basic)
|
|
### ---------------------------
|
|
FQDN_REGEX='^([a-zA-Z0-9](-*[a-zA-Z0-9])*)(\.([a-zA-Z0-9](-*[a-zA-Z0-9])*))*\.[a-zA-Z]{2,}$'
|
|
if [[ ! "$DOMAIN" =~ $FQDN_REGEX ]]; then
|
|
die "Invalid FQDN: $DOMAIN"
|
|
fi
|
|
|
|
### ---------------------------
|
|
### System update & ensure curl/gnupg early
|
|
### ---------------------------
|
|
log "APT update & ensure curl/gnupg are present (required early for repos)"
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -y
|
|
apt-get upgrade -y
|
|
|
|
# Ensure curl / gnupg are present early for repo keys
|
|
apt-get install -y --no-install-recommends curl wget gnupg gpg-agent dirmngr lsb-release apt-transport-https ca-certificates || true
|
|
|
|
### ---------------------------
|
|
### Install build deps (may include some heavy packages needed for asdf builds)
|
|
### ---------------------------
|
|
log "Installing build dependencies (Erlang/Elixir builds need several packages)"
|
|
apt-get install -y --no-install-recommends \
|
|
build-essential automake autoconf m4 libncurses5-dev libncursesw5-dev \
|
|
libssl-dev libreadline-dev zlib1g-dev pkg-config unzip \
|
|
libxml2-utils xsltproc fop libxslt1.1 libxslt1-dev \
|
|
libwxgtk-webview3.2-dev libglu1-mesa-dev libgl1-mesa-dev \
|
|
libpng-dev libssh-dev unixodbc-dev default-jdk rsync jq dnsutils git || true
|
|
|
|
# optional: try to install just if in apt repos
|
|
if ! command -v just >/dev/null 2>&1; then
|
|
if apt-cache show just >/dev/null 2>&1; then
|
|
apt-get install -y just || true
|
|
fi
|
|
fi
|
|
|
|
### ---------------------------
|
|
### PostgreSQL repository key setup (PGDG) - idempotent
|
|
### ---------------------------
|
|
# -------------------------
|
|
# PGDG key + repo (idempotent, modern Ubuntu/Debian)
|
|
# -------------------------
|
|
PG_KEY_URL="https://www.postgresql.org/media/keys/ACCC4CF8.asc"
|
|
TRUSTED_KEY="/etc/apt/trusted.gpg.d/postgresql.gpg"
|
|
CODENAME="$(lsb_release -cs || echo noble)"
|
|
LIST_FILE="/etc/apt/sources.list.d/pgdg.list"
|
|
|
|
# ensure curl & gpg are present
|
|
apt-get update -y
|
|
apt-get install -y --no-install-recommends curl gnupg lsb-release apt-transport-https ca-certificates || true
|
|
|
|
# import/dearmor the key if missing
|
|
if [[ ! -f "${TRUSTED_KEY}" ]]; then
|
|
info "Importing PostgreSQL signing key to ${TRUSTED_KEY}..."
|
|
curl -fsSL "${PG_KEY_URL}" | gpg --dearmor -o "${TRUSTED_KEY}" \
|
|
|| { rm -f "${TRUSTED_KEY}"; die "Failed to fetch/dearmor PGDG key"; }
|
|
chmod 644 "${TRUSTED_KEY}"
|
|
chown root:root "${TRUSTED_KEY}"
|
|
else
|
|
info "PGDG key already present at ${TRUSTED_KEY}; skipping import."
|
|
fi
|
|
|
|
# write the repo list (idempotent)
|
|
echo "deb http://apt.postgresql.org/pub/repos/apt ${CODENAME}-pgdg main" > "${LIST_FILE}"
|
|
chmod 644 "${LIST_FILE}"
|
|
info "PGDG APT entry written to ${LIST_FILE}"
|
|
|
|
# update package lists
|
|
apt-get update -y || die "apt-get update failed after adding PGDG repo"
|
|
# -------------------------
|
|
|
|
### ---------------------------
|
|
### Install PostgreSQL + PostGIS
|
|
### ---------------------------
|
|
log "Installing PostgreSQL and PostGIS (attempting preferred ${PG_VER_PREFERRED})"
|
|
if apt-cache policy "postgresql-${PG_VER_PREFERRED}" | grep -q Candidate; then
|
|
apt-get install -y "postgresql-${PG_VER_PREFERRED}" "postgresql-${PG_VER_PREFERRED}-postgis-3" postgis || true
|
|
else
|
|
apt-get install -y postgresql postgis postgresql-contrib || true
|
|
fi
|
|
systemctl enable --now postgresql || true
|
|
|
|
### ---------------------------
|
|
### Set locale to UTF-8 (avoid Elixir latin1 warning)
|
|
### ---------------------------
|
|
log "Ensuring UTF-8 locale"
|
|
apt-get install -y locales || true
|
|
if ! grep -q "en_US.UTF-8 UTF-8" /etc/locale.gen 2>/dev/null; then
|
|
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
|
|
fi
|
|
locale-gen en_US.UTF-8 >/dev/null || true
|
|
update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
|
|
export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
|
|
export ELIXIR_ERL_OPTIONS="+fnu"
|
|
|
|
### ---------------------------
|
|
### Create bonfire user and set ownership
|
|
### ---------------------------
|
|
log "Creating system user '${APP_USER}' and preparing ${APP_HOME}"
|
|
if id -u "${APP_USER}" >/dev/null 2>&1; then
|
|
info "User ${APP_USER} already exists"
|
|
else
|
|
adduser --system --group --home "${APP_HOME}" --shell /bin/bash "${APP_USER}" || true
|
|
fi
|
|
mkdir -p "${APP_HOME}"
|
|
chown -R "${APP_USER}:${APP_USER}" "${APP_HOME}"
|
|
chmod 750 "${APP_HOME}"
|
|
|
|
# limited sudo for helper scripts (reload nginx, systemctl)
|
|
echo "${APP_USER} ALL=(ALL) NOPASSWD:/usr/sbin/nginx,/bin/systemctl" > "/etc/sudoers.d/${APP_USER}"
|
|
chmod 0440 "/etc/sudoers.d/${APP_USER}"
|
|
|
|
### ---------------------------
|
|
### Install ASDF for bonfire user
|
|
### ---------------------------
|
|
log "Installing asdf for ${APP_USER} if missing"
|
|
if [[ ! -d "${APP_HOME}/.asdf" ]]; then
|
|
sudo -u "${APP_USER}" bash -lc "git clone https://github.com/asdf-vm/asdf.git ${APP_HOME}/.asdf --branch ${ASDF_VERSION}"
|
|
fi
|
|
|
|
# ensure .bashrc loads asdf
|
|
if ! sudo -u "${APP_USER}" bash -lc "grep -q 'asdf.sh' ${APP_HOME}/.bashrc" >/dev/null 2>&1; then
|
|
cat >> "${APP_HOME}/.bashrc" <<'ASDFRC'
|
|
# ASDF
|
|
. "$HOME/.asdf/asdf.sh"
|
|
. "$HOME/.asdf/completions/asdf.bash"
|
|
ASDFRC
|
|
chown "${APP_USER}:${APP_USER}" "${APP_HOME}/.bashrc"
|
|
fi
|
|
|
|
# create local bin dir (nodejs plugin helper uses it)
|
|
sudo -u "${APP_USER}" bash -lc "mkdir -p ${APP_HOME}/.local/bin && chmod 755 ${APP_HOME}/.local/bin"
|
|
|
|
### ---------------------------
|
|
### Clone Bonfire repository
|
|
### ---------------------------
|
|
log "Cloning Bonfire repository into ${APP_DIR}"
|
|
if [[ ! -d "${APP_DIR}" ]]; then
|
|
sudo -u "${APP_USER}" git clone --depth 1 https://github.com/bonfire-networks/bonfire-app.git "${APP_DIR}"
|
|
else
|
|
info "Repository already present; updating..."
|
|
sudo -u "${APP_USER}" bash -lc "cd '${APP_DIR}' && git fetch --depth 1 origin && git reset --hard origin/HEAD"
|
|
fi
|
|
|
|
### ---------------------------
|
|
### Install ASDF plugins & runtimes as bonfire user
|
|
### ---------------------------
|
|
log "Installing ASDF plugins (erlang, elixir, nodejs) and runtimes (may be slow)"
|
|
sudo -u "${APP_USER}" bash -lc "
|
|
set -euo pipefail
|
|
export HOME='${APP_HOME}'
|
|
. \"\$HOME/.asdf/asdf.sh\"
|
|
|
|
asdf plugin add erlang || true
|
|
asdf plugin add elixir || true
|
|
asdf plugin add nodejs || true
|
|
|
|
# nodejs key import helper (if present)
|
|
if [[ -f \"\$HOME/.asdf/plugins/nodejs/bin/import-release-team-keyring\" ]]; then
|
|
bash \"\$HOME/.asdf/plugins/nodejs/bin/import-release-team-keyring\" || true
|
|
fi
|
|
|
|
cd '${APP_DIR}'
|
|
if [[ -f .tool-versions ]]; then
|
|
export KERL_CONFIGURE_OPTIONS=\"${KERL_CONFIGURE_OPTIONS}\"
|
|
asdf install || true
|
|
else
|
|
export KERL_CONFIGURE_OPTIONS=\"${KERL_CONFIGURE_OPTIONS}\"
|
|
EL_VER=\$(asdf list-all elixir | tail -n1 || true)
|
|
ERL_VER=\$(asdf list-all erlang | tail -n1 || true)
|
|
NODE_VER=\$(asdf list-all nodejs | tail -n1 || true)
|
|
if [[ -n \"\$ERL_VER\" ]]; then asdf install erlang \"\$ERL_VER\" || true; asdf global erlang \"\$ERL_VER\"; fi
|
|
if [[ -n \"\$EL_VER\" ]]; then asdf install elixir \"\$EL_VER\" || true; asdf global elixir \"\$EL_VER\"; fi
|
|
if [[ -n \"\$NODE_VER\" ]]; then asdf install nodejs \"\$NODE_VER\" || true; asdf global nodejs \"\$NODE_VER\"; fi
|
|
fi
|
|
|
|
mix local.hex --force || true
|
|
mix local.rebar --force || true
|
|
|
|
echo '[info] ASDF runtimes installed (or attempted).'
|
|
"
|
|
|
|
### ---------------------------
|
|
### Verify mix is available
|
|
### ---------------------------
|
|
if ! sudo -u "${APP_USER}" bash -lc ". ${APP_HOME}/.asdf/asdf.sh && command -v mix >/dev/null 2>&1"; then
|
|
die "mix not available for ${APP_USER}. Check ASDF install logs above."
|
|
fi
|
|
|
|
### ---------------------------
|
|
### DNS validation (unless skipped)
|
|
### ---------------------------
|
|
if [[ "${SKIP_DNS_CHECK}" -eq 0 ]]; then
|
|
log "Checking DNS A/AAAA records for ${DOMAIN}"
|
|
SERVER_V4="$(curl -4 -fsS https://api.ipify.org || true)"
|
|
SERVER_V6="$(curl -6 -fsS https://api64.ipify.org || true)"
|
|
DOMAIN_A="$(dig +short A "${DOMAIN}" | head -n1 || true)"
|
|
DOMAIN_AAAA="$(dig +short AAAA "${DOMAIN}" | head -n1 || true)"
|
|
echo " Server IPv4: ${SERVER_V4:-<none>} Domain A: ${DOMAIN_A:-<none>}"
|
|
echo " Server IPv6: ${SERVER_V6:-<none>} Domain AAAA: ${DOMAIN_AAAA:-<none>}"
|
|
DNS_OK=false
|
|
if [[ -n "${SERVER_V4}" && "${SERVER_V4}" == "${DOMAIN_A}" ]]; then DNS_OK=true; fi
|
|
if [[ -n "${SERVER_V6}" && -n "${DOMAIN_AAAA}" && "${SERVER_V6,,}" == "${DOMAIN_AAAA,,}" ]]; then DNS_OK=true; fi
|
|
if [[ "${DNS_OK}" != "true" ]]; then
|
|
die "DNS for ${DOMAIN} does not point to this server's public IP. Fix DNS or re-run with --skip-dns-check."
|
|
fi
|
|
fi
|
|
|
|
### ---------------------------
|
|
### PostgreSQL role / DB / extensions
|
|
### ---------------------------
|
|
log "Configuring PostgreSQL role/database and enabling PostGIS & citext"
|
|
sudo -u postgres psql -v ON_ERROR_STOP=1 <<PSQL || die "postgres setup failed"
|
|
DO \$\$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${PG_USER}') THEN
|
|
CREATE ROLE ${PG_USER} LOGIN PASSWORD '${PG_PASS}';
|
|
END IF;
|
|
END
|
|
\$\$;
|
|
PSQL
|
|
|
|
if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${PG_DB}'" | grep -q 1; then
|
|
sudo -u postgres createdb -O "${PG_USER}" "${PG_DB}"
|
|
fi
|
|
|
|
sudo -u postgres psql -d "${PG_DB}" -v ON_ERROR_STOP=1 -c "CREATE EXTENSION IF NOT EXISTS postgis;" || die "Failed enabling postgis"
|
|
sudo -u postgres psql -d "${PG_DB}" -v ON_ERROR_STOP=1 -c "CREATE EXTENSION IF NOT EXISTS citext;" || warn "Could not enable citext (may require superuser privileges)."
|
|
|
|
### ---------------------------
|
|
### Build Bonfire (as bonfire user)
|
|
### ---------------------------
|
|
log "Writing .env and building Bonfire (this can take many minutes)"
|
|
# ensure webroot exists for ACME challenge
|
|
mkdir -p /var/www/html
|
|
chown -R "${APP_USER}:${APP_USER}" /var/www/html
|
|
|
|
sudo -u "${APP_USER}" bash -lc "
|
|
set -euo pipefail
|
|
export HOME='${APP_HOME}'
|
|
. \"\$HOME/.asdf/asdf.sh\" || true
|
|
export FLAVOUR='${FLAVOUR}'
|
|
export MIX_ENV=prod
|
|
export WITH_DOCKER=no
|
|
cd '${APP_DIR}'
|
|
|
|
if command -v just >/dev/null 2>&1; then
|
|
just config || true
|
|
fi
|
|
|
|
SECRET_KEY_BASE=\$(openssl rand -hex 64)
|
|
SIGNING_SALT=\$(openssl rand -hex 16)
|
|
ENCRYPTION_SALT=\$(openssl rand -hex 16)
|
|
MEILI_MASTER_KEY=\$(openssl rand -hex 32)
|
|
|
|
cat > .env <<EOF_ENV
|
|
FLAVOUR=${FLAVOUR}
|
|
HOSTNAME=${DOMAIN}
|
|
|
|
DATABASE_URL=ecto://${PG_USER}:${PG_PASS}@localhost/${PG_DB}
|
|
|
|
SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
|
SIGNING_SALT=${SIGNING_SALT}
|
|
ENCRYPTION_SALT=${ENCRYPTION_SALT}
|
|
MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
|
|
|
|
WITH_PATHEX=1
|
|
# PORT=4000
|
|
EOF_ENV
|
|
|
|
# Disable Pathex if Elixir bug-window
|
|
if command -v elixir >/dev/null 2>&1; then
|
|
ELV=\$(elixir -v | sed -n 's/.*Elixir \\([0-9]\\+\\.[0-9]\\+\\.[0-9]\\+\\).*/\\1/p' || true)
|
|
if printf '%s\n' 1.17.0 1.17.1 1.17.2 | grep -qx \"\$ELV\"; then
|
|
sed -i 's/^WITH_PATHEX=.*/WITH_PATHEX=0/' .env || true
|
|
echo '[warn] Elixir in bug-window; disabled WITH_PATHEX in .env'
|
|
fi
|
|
fi
|
|
|
|
mix local.hex --force || true
|
|
mix local.rebar --force || true
|
|
|
|
mix deps.get --only prod || mix deps.get || true
|
|
# Assets
|
|
if [[ -d assets ]]; then
|
|
cd assets
|
|
if command -v yarn >/dev/null 2>&1; then
|
|
yarn install --frozen-lockfile || yarn install || true
|
|
NODE_ENV=production yarn build || true
|
|
else
|
|
npm ci || npm install || true
|
|
NODE_ENV=production npm run build || true
|
|
fi
|
|
cd -
|
|
fi
|
|
|
|
if command -v just >/dev/null 2>&1; then
|
|
just setup-prod || true
|
|
just rel-build || true
|
|
else
|
|
MIX_ENV=prod mix compile
|
|
MIX_ENV=prod mix assets.deploy || true
|
|
MIX_ENV=prod mix ecto.setup || true
|
|
MIX_ENV=prod mix release
|
|
fi
|
|
|
|
echo '[info] Bonfire build attempted (see output above).'
|
|
"
|
|
|
|
# verify release binary
|
|
if [[ ! -x "${APP_DIR}/_build/prod/rel/bonfire/bin/bonfire" ]]; then
|
|
die "Release binary missing at ${APP_DIR}/_build/prod/rel/bonfire/bin/bonfire — check the build output above."
|
|
fi
|
|
|
|
### ---------------------------
|
|
### Nginx config + certbot
|
|
### ---------------------------
|
|
log "Writing nginx site config and reloading"
|
|
SITE_AVAIL="/etc/nginx/sites-available/bonfire"
|
|
SITE_LINK="/etc/nginx/sites-enabled/bonfire"
|
|
APP_UPSTREAM="http://127.0.0.1:${APP_PORT}"
|
|
|
|
cat > "${SITE_AVAIL}" <<NGINXCONF
|
|
server {
|
|
listen 80;
|
|
server_name ${DOMAIN};
|
|
|
|
# ACME challenge path
|
|
location ^~ /.well-known/acme-challenge/ {
|
|
root /var/www/html;
|
|
default_type text/plain;
|
|
}
|
|
|
|
location /live/websocket {
|
|
proxy_pass ${APP_UPSTREAM};
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade \$http_upgrade;
|
|
proxy_set_header Connection \"upgrade\";
|
|
proxy_set_header Host \$host;
|
|
}
|
|
|
|
location / {
|
|
proxy_pass ${APP_UPSTREAM};
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host \$host;
|
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto \$scheme;
|
|
proxy_set_header Upgrade \$http_upgrade;
|
|
proxy_set_header Connection \"upgrade\";
|
|
}
|
|
}
|
|
NGINXCONF
|
|
|
|
ln -sf "${SITE_AVAIL}" "${SITE_LINK}"
|
|
nginx -t || die "nginx config test failed"
|
|
systemctl restart nginx
|
|
|
|
log "Attempting to obtain Let's Encrypt certificate via certbot"
|
|
if ! certbot --nginx -d "${DOMAIN}" --non-interactive --agree-tos -m "${EMAIL}"; then
|
|
warn "Certbot failed to obtain certificate. Check DNS/ports and run: certbot --nginx -d ${DOMAIN} manually."
|
|
fi
|
|
systemctl enable --now certbot.timer || true
|
|
|
|
### ---------------------------
|
|
### systemd unit
|
|
### ---------------------------
|
|
log "Writing systemd service unit for bonfire"
|
|
SERVICE_PATH="/etc/systemd/system/bonfire.service"
|
|
cat > "${SERVICE_PATH}" <<SYSTEMD
|
|
[Unit]
|
|
Description=Bonfire App
|
|
After=network-online.target postgresql.service
|
|
Wants=network-online.target postgresql.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=${APP_USER}
|
|
Group=${APP_USER}
|
|
WorkingDirectory=${APP_DIR}
|
|
EnvironmentFile=${APP_DIR}/.env
|
|
Environment=LANG=en_US.UTF-8
|
|
Environment=LC_ALL=en_US.UTF-8
|
|
Environment=ELIXIR_ERL_OPTIONS=+fnu
|
|
ExecStart=${APP_DIR}/_build/prod/rel/bonfire/bin/bonfire daemon
|
|
Restart=always
|
|
RestartSec=5
|
|
LimitNOFILE=65536
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
SYSTEMD
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable --now bonfire || warn "systemd enable/start returned non-zero; check journalctl -u bonfire"
|
|
|
|
### ---------------------------
|
|
### Helper scripts (bonfire user)
|
|
### ---------------------------
|
|
log "Installing helper scripts into ${APP_DIR}"
|
|
sudo -u "${APP_USER}" bash -lc "cat > '${APP_DIR}/reload-nginx.sh' <<'EOS'
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
echo 'Nginx reloaded.'
|
|
EOS
|
|
chmod +x '${APP_DIR}/reload-nginx.sh' || true"
|
|
|
|
sudo -u "${APP_USER}" bash -lc "cat > '${APP_DIR}/bonfire-deploy.sh' <<'EOS'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
cd \"\$(dirname \"\$0\")\"
|
|
. \"\$HOME/.asdf/asdf.sh\" 2>/dev/null || true
|
|
echo 'Pulling latest code...'
|
|
git pull --ff-only || true
|
|
echo 'Running production setup and rebuild...'
|
|
just setup-prod || true
|
|
just rel-build || true
|
|
echo 'Restarting service...'
|
|
sudo systemctl restart bonfire || true
|
|
echo 'Reloading nginx...'
|
|
./reload-nginx.sh || true
|
|
echo 'Deploy complete.'
|
|
EOS
|
|
chmod +x '${APP_DIR}/bonfire-deploy.sh' || true"
|
|
|
|
### ---------------------------
|
|
### Final summary
|
|
### ---------------------------
|
|
log "Done (or attempted). Summary:"
|
|
cat <<EOF
|
|
|
|
Bonfire URL: https://${DOMAIN}
|
|
|
|
Systemd:
|
|
sudo systemctl status bonfire
|
|
sudo journalctl -u bonfire -f
|
|
|
|
Database:
|
|
DB_NAME: ${PG_DB}
|
|
DB_USER: ${PG_USER}
|
|
DB_PASSWORD: ${PG_PASS}
|
|
|
|
To run CLI as bonfire user:
|
|
sudo -u ${APP_USER} -H bash -c "cd ${APP_DIR} && bash"
|
|
|
|
Useful commands:
|
|
sudo -u ${APP_USER} -H bash -c 'cd ${APP_DIR} && just rel-build'
|
|
sudo systemctl restart bonfire
|
|
sudo systemctl status bonfire
|
|
journalctl -u bonfire -b --no-pager
|
|
|
|
If something failed: inspect the build output above and the journal:
|
|
journalctl -u bonfire -b --no-pager
|
|
tail -n 200 /var/log/syslog
|
|
|
|
EOF
|
|
|
|
exit 0
|
|
|