Compare commits
No commits in common. "7325976ebd84033ced98f13aa8b5d2713e136563" and "f47c4918a6dae02ae755fe241a34ff65ff6b2ace" have entirely different histories.
7325976ebd
...
f47c4918a6
95
README.md
95
README.md
|
|
@ -1,94 +1,3 @@
|
||||||
# Bonfire Automated Installer
|
# bonfirestarter
|
||||||
|
|
||||||
This repository provides a single script that installs, configures, and deploys the [Bonfire federated platform](https://bonfirenetworks.org/) on a fresh Ubuntu 24.04 server with Nginx and Let’s Encrypt SSL.
|
Attempt at an installation and configuration script on "bare metal" for the Fediverse enabled social networking app Bonfire.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Automated installation of dependencies (Postgres, Elixir, Node.js, Nginx, Certbot).
|
|
||||||
- Prompts for domain, email, and database password.
|
|
||||||
- Automatic DNS/FQDN validation (checks A/AAAA records).
|
|
||||||
- Configures Bonfire as a `systemd` service.
|
|
||||||
- HTTPS enabled via Let’s Encrypt.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- Fresh Ubuntu 22.04+ or Debian 12+ server.
|
|
||||||
- A fully qualified domain name (FQDN) pointing to the server’s IP.
|
|
||||||
- Root or sudo access.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### 1. Download the installer
|
|
||||||
```bash
|
|
||||||
git clone https://your-repo-url/bonfire-installer.git
|
|
||||||
cd bonfire-installer
|
|
||||||
chmod +x install_bonfire.sh
|
|
||||||
```
|
|
||||||
### 2 . Run the installer
|
|
||||||
```bash
|
|
||||||
sudo ./install_bonfire.sh
|
|
||||||
```
|
|
||||||
The script will:
|
|
||||||
- Prompt for your **domain name**, **email address**, and **database password**.
|
|
||||||
- Validate that your domain resolves correctly (A/AAAA DNS records).
|
|
||||||
- Install required system packages.
|
|
||||||
- Configure Postgres and Bonfire.
|
|
||||||
- Set up Nginx with SSL.
|
|
||||||
- Create a `systemd` service for Bonfire.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Start/Stop/Restart Bonfire
|
|
||||||
```bash
|
|
||||||
sudo systemctl start bonfire
|
|
||||||
sudo systemctl stop bonfire
|
|
||||||
sudo systemctl restart bonfire
|
|
||||||
sudo systemctl status bonfire
|
|
||||||
```
|
|
||||||
----------
|
|
||||||
### Verify Nginx + SSL
|
|
||||||
```bash
|
|
||||||
sudo nginx -t
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
```
|
|
||||||
### Access the App
|
|
||||||
Once installation is complete, open:
|
|
||||||
```http
|
|
||||||
https://yourdomain.com
|
|
||||||
```
|
|
||||||
## Updating Bonfire
|
|
||||||
When new versions are released:
|
|
||||||
```bash
|
|
||||||
cd /opt/bonfire
|
|
||||||
sudo -u bonfire git pull
|
|
||||||
sudo -u bonfire MIX_ENV=prod mix compile
|
|
||||||
sudo -u bonfire MIX_ENV=prod mix ecto.migrate
|
|
||||||
sudo systemctl restart bonfire
|
|
||||||
```
|
|
||||||
## Logs
|
|
||||||
View logs for troubleshooting:
|
|
||||||
```bash
|
|
||||||
journalctl -u bonfire -f
|
|
||||||
```
|
|
||||||
## Uninstall
|
|
||||||
To remove Bonfire and related services:
|
|
||||||
```bash
|
|
||||||
sudo systemctl stop bonfire
|
|
||||||
sudo systemctl disable bonfire
|
|
||||||
sudo rm -rf /opt/bonfire
|
|
||||||
sudo deluser --remove-home bonfire
|
|
||||||
sudo -u postgres dropdb bonfire
|
|
||||||
sudo -u postgres dropuser bonfire
|
|
||||||
sudo rm /etc/systemd/system/bonfire.service
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
```
|
|
||||||
## Notes
|
|
||||||
- Ensure your domain’s DNS records are properly configured **before** running the installer.
|
|
||||||
- The script is intended for production use on a dedicated server or VM.
|
|
||||||
- For staging/testing, you may adapt the script to use self-signed certificates instead of Let’s Encrypt.
|
|
||||||
|
|
@ -1,316 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# ============================
|
|
||||||
# Bonfire Bare-Metal Installer
|
|
||||||
# Ubuntu 24.04 LTS (Noble)
|
|
||||||
# ============================
|
|
||||||
|
|
||||||
echo "=== Bonfire Bare-Metal Installer (Ubuntu 24.04) ==="
|
|
||||||
|
|
||||||
# ---------- prompts ----------
|
|
||||||
read -rp "Enter your domain name (FQDN, e.g., example.com): " DOMAIN
|
|
||||||
while [[ -z "${DOMAIN}" ]]; do
|
|
||||||
echo "Domain cannot be empty."
|
|
||||||
read -rp "Enter your domain name: " DOMAIN
|
|
||||||
done
|
|
||||||
|
|
||||||
read -rp "Contact email for Let's Encrypt (e.g., admin@${DOMAIN}): " EMAIL
|
|
||||||
while [[ -z "${EMAIL}" ]]; do
|
|
||||||
echo "Email cannot be empty."
|
|
||||||
read -rp "Contact email for Let's Encrypt: " EMAIL
|
|
||||||
done
|
|
||||||
|
|
||||||
read -rp "Bonfire flavour [social|ember|community|cooperation] (default: social): " FLAVOUR
|
|
||||||
FLAVOUR=${FLAVOUR:-social}
|
|
||||||
|
|
||||||
read -rp "PostgreSQL username (default: bonfire_user): " DB_USER
|
|
||||||
DB_USER=${DB_USER:-bonfire_user}
|
|
||||||
DB_NAME="bonfire"
|
|
||||||
|
|
||||||
# we'll generate a random DB password
|
|
||||||
DB_PASSWORD="$(openssl rand -base64 24)"
|
|
||||||
|
|
||||||
# ---------- FQDN validation ----------
|
|
||||||
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
|
|
||||||
echo "❌ Invalid FQDN: ${DOMAIN}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ---------- DNS checks (A/AAAA must match this server) ----------
|
|
||||||
echo "=== Checking DNS for ${DOMAIN} ==="
|
|
||||||
# public IPv4
|
|
||||||
SERVER_V4="$(curl -4 -fsS https://api.ipify.org || true)"
|
|
||||||
# public IPv6 (may be empty if host lacks IPv6)
|
|
||||||
SERVER_V6="$(curl -6 -fsS https://api64.ipify.org || true)"
|
|
||||||
|
|
||||||
# need dig
|
|
||||||
if ! command -v dig >/dev/null 2>&1; then
|
|
||||||
echo "Installing dnsutils for DNS checks..."
|
|
||||||
sudo apt update && sudo apt install -y dnsutils
|
|
||||||
fi
|
|
||||||
|
|
||||||
DOMAIN_A="$(dig +short A "${DOMAIN}" | head -n1 || true)"
|
|
||||||
DOMAIN_AAAA="$(dig +short AAAA "${DOMAIN}" | head -n1 || true)"
|
|
||||||
|
|
||||||
echo "Server IPv4: ${SERVER_V4:-<none>}"
|
|
||||||
echo "Server IPv6: ${SERVER_V6:-<none>}"
|
|
||||||
echo "Domain A: ${DOMAIN_A:-<none>}"
|
|
||||||
echo "Domain AAAA: ${DOMAIN_AAAA:-<none>}"
|
|
||||||
|
|
||||||
MISMATCH=true
|
|
||||||
if [[ -n "${SERVER_V4}" && -n "${DOMAIN_A}" && "${SERVER_V4}" == "${DOMAIN_A}" ]]; then
|
|
||||||
MISMATCH=false
|
|
||||||
fi
|
|
||||||
if [[ -n "${SERVER_V6}" && -n "${DOMAIN_AAAA}" && "${SERVER_V6,,}" == "${DOMAIN_AAAA,,}" ]]; then
|
|
||||||
MISMATCH=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${MISMATCH}" == "true" ]]; then
|
|
||||||
echo "❌ DNS for ${DOMAIN} does not resolve to this server."
|
|
||||||
echo " Server IPv4: ${SERVER_V4:-<none>}, Domain A: ${DOMAIN_A:-<none>}"
|
|
||||||
echo " Server IPv6: ${SERVER_V6:-<none>}, Domain AAAA: ${DOMAIN_AAAA:-<none>}"
|
|
||||||
echo "➡️ Fix your DNS A/AAAA records, wait for propagation, then re-run."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ DNS looks good."
|
|
||||||
|
|
||||||
# ---------- system prep ----------
|
|
||||||
echo "=== Updating system packages ==="
|
|
||||||
sudo apt update && sudo apt -y upgrade
|
|
||||||
|
|
||||||
echo "=== Installing base tools ==="
|
|
||||||
sudo apt install -y \
|
|
||||||
curl git build-essential ca-certificates jq \
|
|
||||||
libssl-dev libffi-dev libncurses5-dev \
|
|
||||||
libwxgtk3.0-gtk3-dev libgl1-mesa-dev libglu1-mesa-dev \
|
|
||||||
libpng-dev libssh-dev unixodbc-dev pkg-config
|
|
||||||
|
|
||||||
echo "=== Installing 'just' command runner ==="
|
|
||||||
sudo apt install -y just
|
|
||||||
|
|
||||||
echo "=== Installing Node.js 20 + Yarn ==="
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
||||||
sudo apt install -y nodejs
|
|
||||||
npm install -g yarn
|
|
||||||
|
|
||||||
# ---------- PostgreSQL 17 + PostGIS ----------
|
|
||||||
echo "=== Installing PostgreSQL 17 + PostGIS ==="
|
|
||||||
echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt/ noble-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list >/dev/null
|
|
||||||
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /usr/share/keyrings/pgdg.gpg
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y postgresql-17 postgresql-17-postgis-3
|
|
||||||
|
|
||||||
echo "=== Creating PostgreSQL role & database ==="
|
|
||||||
sudo -u postgres psql -tAc "DO \$\$ BEGIN
|
|
||||||
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${DB_USER}') THEN
|
|
||||||
CREATE ROLE ${DB_USER} LOGIN PASSWORD '${DB_PASSWORD}';
|
|
||||||
END IF;
|
|
||||||
END \$\$;"
|
|
||||||
sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}'" | grep -q 1 || sudo -u postgres createdb -O "${DB_USER}" "${DB_NAME}"
|
|
||||||
sudo -u postgres psql -d "${DB_NAME}" -c "CREATE EXTENSION IF NOT EXISTS postgis;"
|
|
||||||
|
|
||||||
# ---------- asdf + mise (match .tool-versions) ----------
|
|
||||||
echo "=== Installing asdf (plugins: erlang, elixir) ==="
|
|
||||||
if [[ ! -d "$HOME/.asdf" ]]; then
|
|
||||||
git clone https://github.com/asdf-vm/asdf.git "$HOME/.asdf" --branch v0.14.0
|
|
||||||
fi
|
|
||||||
grep -q 'asdf.sh' "$HOME/.bashrc" || echo '. "$HOME/.asdf/asdf.sh"' >> "$HOME/.bashrc"
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source "$HOME/.asdf/asdf.sh" || true
|
|
||||||
asdf plugin-add erlang || true
|
|
||||||
asdf plugin-add elixir || true
|
|
||||||
|
|
||||||
echo "=== Installing mise ==="
|
|
||||||
curl -fsSL https://mise.jdx.dev/install.sh | sh
|
|
||||||
grep -q 'mise activate' "$HOME/.bashrc" || echo 'eval "$("$HOME/.local/bin/mise" activate bash)"' >> "$HOME/.bashrc"
|
|
||||||
eval "$("$HOME/.local/bin/mise" activate bash)" || true
|
|
||||||
|
|
||||||
# ---------- Bonfire clone & tool install ----------
|
|
||||||
echo "=== Cloning Bonfire repository ==="
|
|
||||||
cd "$HOME"
|
|
||||||
if [[ ! -d "bonfire" ]]; then
|
|
||||||
git clone --depth 1 https://github.com/bonfire-networks/bonfire-app.git bonfire
|
|
||||||
fi
|
|
||||||
cd bonfire
|
|
||||||
|
|
||||||
echo "=== Installing Erlang/Elixir via mise (from .tool-versions) ==="
|
|
||||||
"$HOME/.local/bin/mise" install
|
|
||||||
|
|
||||||
# ---------- Elixir bug-window check for Pathex ----------
|
|
||||||
WITH_PATHEX=1
|
|
||||||
if [[ -f ".tool-versions" ]]; then
|
|
||||||
ELIXIR_LINE="$(grep -E '^elixir[[:space:]]' .tool-versions || true)"
|
|
||||||
if [[ -n "${ELIXIR_LINE}" ]]; then
|
|
||||||
ELIXIR_VER="$(echo "${ELIXIR_LINE}" | awk '{print $2}')"
|
|
||||||
# strip possible 'ref:' etc; keep x.y.z
|
|
||||||
ELIXIR_VER_CLEAN="$(echo "${ELIXIR_VER}" | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' || true)"
|
|
||||||
if [[ -n "${ELIXIR_VER_CLEAN}" ]]; then
|
|
||||||
# compare versions: if >=1.17 and <1.17.3 => WITH_PATHEX=0
|
|
||||||
vcmp () { printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1; }
|
|
||||||
if [[ "$(vcmp "1.17.0" "${ELIXIR_VER_CLEAN}")" == "1.17.0" && "$(vcmp "${ELIXIR_VER_CLEAN}" "1.17.3")" == "${ELIXIR_VER_CLEAN}" && "${ELIXIR_VER_CLEAN}" != "1.17.3" ]]; then
|
|
||||||
WITH_PATHEX=0
|
|
||||||
echo "⚠️ Elixir ${ELIXIR_VER_CLEAN} falls in bug window (>=1.17,<1.17.3). Disabling Pathex (WITH_PATHEX=0)."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ---------- environment ----------
|
|
||||||
echo "=== Exporting environment ==="
|
|
||||||
grep -q 'FLAVOUR=' "$HOME/.bashrc" || {
|
|
||||||
echo "export FLAVOUR=${FLAVOUR}" >> "$HOME/.bashrc"
|
|
||||||
echo "export MIX_ENV=prod" >> "$HOME/.bashrc"
|
|
||||||
echo "export WITH_DOCKER=no" >> "$HOME/.bashrc"
|
|
||||||
}
|
|
||||||
export FLAVOUR="${FLAVOUR}"
|
|
||||||
export MIX_ENV=prod
|
|
||||||
export WITH_DOCKER=no
|
|
||||||
|
|
||||||
echo "=== Initializing config with 'just config' ==="
|
|
||||||
just config
|
|
||||||
|
|
||||||
echo "=== Writing .env (DB + SECRET_KEY_BASE + WITH_PATHEX=${WITH_PATHEX}) ==="
|
|
||||||
SECRET_KEY_BASE="$(openssl rand -hex 64)"
|
|
||||||
cat > .env <<EOF
|
|
||||||
DATABASE_URL=ecto://${DB_USER}:${DB_PASSWORD}@localhost/${DB_NAME}
|
|
||||||
SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
|
||||||
WITH_PATHEX=${WITH_PATHEX}
|
|
||||||
# PORT can be set (defaults to 4000)
|
|
||||||
# PORT=4000
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# ---------- build release ----------
|
|
||||||
echo "=== Running 'just setup-prod' and 'just rel-build' ==="
|
|
||||||
just setup-prod
|
|
||||||
just rel-build
|
|
||||||
|
|
||||||
# ---------- Nginx + Let's Encrypt ----------
|
|
||||||
echo "=== Installing Nginx + Certbot ==="
|
|
||||||
sudo apt install -y nginx certbot python3-certbot-nginx
|
|
||||||
|
|
||||||
SITE_AVAIL="/etc/nginx/sites-available/bonfire"
|
|
||||||
SITE_LINK="/etc/nginx/sites-enabled/bonfire"
|
|
||||||
APP_UPSTREAM="http://127.0.0.1:4000"
|
|
||||||
|
|
||||||
echo "=== Writing Nginx site config ==="
|
|
||||||
sudo tee "${SITE_AVAIL}" >/dev/null <<NGINX
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name ${DOMAIN};
|
|
||||||
|
|
||||||
# Proxy all requests to Phoenix (serves static as well)
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NGINX
|
|
||||||
|
|
||||||
sudo ln -sf "${SITE_AVAIL}" "${SITE_LINK}"
|
|
||||||
sudo nginx -t
|
|
||||||
sudo systemctl restart nginx
|
|
||||||
|
|
||||||
echo "=== Obtaining Let's Encrypt certificate ==="
|
|
||||||
sudo certbot --nginx -d "${DOMAIN}" --non-interactive --agree-tos -m "${EMAIL}"
|
|
||||||
|
|
||||||
echo "=== Enabling certbot auto-renew (systemd timer) ==="
|
|
||||||
sudo systemctl enable --now certbot.timer
|
|
||||||
|
|
||||||
# ---------- systemd service ----------
|
|
||||||
echo "=== Creating systemd service 'bonfire.service' ==="
|
|
||||||
SERVICE_FILE="/etc/systemd/system/bonfire.service"
|
|
||||||
RUN_USER="$(id -un)"
|
|
||||||
RUN_GROUP="$(id -gn)"
|
|
||||||
|
|
||||||
sudo tee "${SERVICE_FILE}" >/dev/null <<SYSTEMD
|
|
||||||
[Unit]
|
|
||||||
Description=Bonfire App
|
|
||||||
After=network-online.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=${RUN_USER}
|
|
||||||
Group=${RUN_GROUP}
|
|
||||||
WorkingDirectory=${HOME}/bonfire
|
|
||||||
EnvironmentFile=${HOME}/bonfire/.env
|
|
||||||
ExecStart=${HOME}/bonfire/_build/prod/rel/bonfire/bin/bonfire start daemon
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
SYSTEMD
|
|
||||||
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
sudo systemctl enable --now bonfire
|
|
||||||
|
|
||||||
# ---------- helper scripts ----------
|
|
||||||
echo "=== Creating helper scripts ==="
|
|
||||||
cat > "${HOME}/bonfire/reload-nginx.sh" <<'EOS'
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
sudo nginx -t
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
echo "Nginx reloaded."
|
|
||||||
EOS
|
|
||||||
chmod +x "${HOME}/bonfire/reload-nginx.sh"
|
|
||||||
|
|
||||||
cat > "${HOME}/bonfire/bonfire-deploy.sh" <<'EOS'
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
echo "Pulling latest code..."
|
|
||||||
git pull --ff-only
|
|
||||||
|
|
||||||
echo "Ensuring tool versions are installed (mise)..."
|
|
||||||
~/.local/bin/mise install
|
|
||||||
|
|
||||||
echo "Updating prod config..."
|
|
||||||
just setup-prod
|
|
||||||
|
|
||||||
echo "Building release..."
|
|
||||||
just rel-build
|
|
||||||
|
|
||||||
echo "Restarting Bonfire..."
|
|
||||||
sudo systemctl restart bonfire
|
|
||||||
|
|
||||||
echo "Reloading Nginx..."
|
|
||||||
./reload-nginx.sh
|
|
||||||
|
|
||||||
echo "Deploy complete."
|
|
||||||
EOS
|
|
||||||
chmod +x "${HOME}/bonfire/bonfire-deploy.sh"
|
|
||||||
|
|
||||||
# ---------- done ----------
|
|
||||||
echo
|
|
||||||
echo "=== Bonfire setup complete! 🎉 ==="
|
|
||||||
echo "Site: https://${DOMAIN}"
|
|
||||||
echo
|
|
||||||
echo "Systemd service controls:"
|
|
||||||
echo " sudo systemctl status bonfire"
|
|
||||||
echo " sudo systemctl restart bonfire"
|
|
||||||
echo " sudo systemctl stop bonfire"
|
|
||||||
echo
|
|
||||||
echo "Database credentials:"
|
|
||||||
echo " DB_USER: ${DB_USER}"
|
|
||||||
echo " DB_PASSWORD: ${DB_PASSWORD}"
|
|
||||||
echo " DB_NAME: ${DB_NAME}"
|
|
||||||
echo
|
|
||||||
echo "Deploy updates with:"
|
|
||||||
echo " ${HOME}/bonfire/bonfire-deploy.sh"
|
|
||||||
echo "Reload Nginx with:"
|
|
||||||
echo " ${HOME}/bonfire/reload-nginx.sh"
|
|
||||||
echo
|
|
||||||
echo "Certbot auto-renewal is enabled. To force renew:"
|
|
||||||
echo " sudo certbot renew && sudo systemctl reload nginx"
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue