Files
volumen/install.sh
T

179 lines
5.0 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
#
# volumen one-shot installer for Linux + systemd.
#
# Run from a cloned repository as root:
# sudo ./install.sh
#
# The Ruby toolchain is installed automatically from the distro repositories on
# Fedora and openEuler; on other distributions the script prints guidance and
# expects Ruby >= 3.3 with a C toolchain to be present already.
#
# FreeBSD uses rc.d instead of systemd — see docs/deployment.md.
set -euo pipefail
VOLUMEN_USER="volumen"
CONFIG_DIR="/etc/volumen"
CONFIG_FILE="${CONFIG_DIR}/config.toml"
DATA_DIR="/var/lib/volumen"
CONTENT_DIR="${DATA_DIR}/posts"
USERS_FILE="${DATA_DIR}/users.toml"
SERVICE_FILE="/etc/systemd/system/volumen.service"
MIN_RUBY="3.3"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_DIR="${SCRIPT_DIR}"
log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33mWARN:\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; }
require_root() {
[ "$(id -u)" -eq 0 ] || die "Run as root: sudo ./install.sh"
}
detect_distro() {
[ -r /etc/os-release ] || { printf 'unknown'; return; }
# shellcheck disable=SC1091
. /etc/os-release
printf '%s' "$(printf '%s' "${ID:-unknown}" | tr '[:upper:]' '[:lower:]')"
}
install_toolchain() {
case "$1" in
fedora)
log "Installing Ruby toolchain via dnf (Fedora)…"
dnf install -y ruby ruby-devel gcc gcc-c++ make redhat-rpm-config openssl-devel
;;
openeuler)
log "Installing Ruby toolchain via dnf (openEuler)…"
dnf install -y ruby ruby-devel gcc gcc-c++ make openssl-devel
;;
*)
warn "Automatic toolchain install is wired only for Fedora and openEuler."
cat >&2 <<'EOF'
Install Ruby >= 3.3 and a C toolchain manually, then re-run this script:
Debian/Ubuntu: apt install ruby-full build-essential libssl-dev
Arch: pacman -S ruby base-devel openssl
openSUSE: zypper install ruby ruby-devel gcc make libopenssl-devel
EOF
;;
esac
}
check_ruby() {
command -v ruby >/dev/null 2>&1 || die "Ruby not found; install Ruby >= ${MIN_RUBY} and re-run."
local version
version="$(ruby -e 'print RUBY_VERSION')"
if ! MIN="$MIN_RUBY" ruby -e 'exit(Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(ENV["MIN"]))'; then
die "Ruby ${version} is too old; volumen needs >= ${MIN_RUBY}."
fi
log "Ruby ${version} OK."
}
ensure_bundler() {
if ! command -v bundle >/dev/null 2>&1; then
log "Installing bundler…"
gem install --no-document bundler
fi
}
create_user() {
if id "$VOLUMEN_USER" >/dev/null 2>&1; then
log "User ${VOLUMEN_USER} already exists."
else
log "Creating system user ${VOLUMEN_USER}…"
useradd --system --home "$DATA_DIR" --shell /usr/sbin/nologin "$VOLUMEN_USER"
fi
}
create_dirs() {
log "Creating ${CONFIG_DIR} and ${CONTENT_DIR}…"
mkdir -p "$CONFIG_DIR" "$CONTENT_DIR"
chown -R "$VOLUMEN_USER:$VOLUMEN_USER" "$DATA_DIR"
}
install_gems() {
log "Installing gem dependencies…"
( cd "$APP_DIR" && bundle install )
}
generate_config() {
if [ -f "$CONFIG_FILE" ]; then
log "Config ${CONFIG_FILE} already exists; leaving it untouched."
return
fi
log "Generating ${CONFIG_FILE}…"
( cd "$APP_DIR" && bundle exec ruby -Ilib -rvolumen/config \
-e 'Volumen::Config.generate_default(ARGV[0])' "$CONFIG_FILE" )
sed -i 's/^host = .*/host = "127.0.0.1"/' "$CONFIG_FILE"
sed -i "s#^content_dir = .*#content_dir = \"${CONTENT_DIR}\"#" "$CONFIG_FILE"
sed -i "s#^users_file = .*#users_file = \"${USERS_FILE}\"#" "$CONFIG_FILE"
chown "$VOLUMEN_USER:$VOLUMEN_USER" "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
}
install_service() {
log "Installing systemd unit ${SERVICE_FILE}…"
cat > "$SERVICE_FILE" <<EOF
[Unit]
Description=volumen blog engine
After=network.target
[Service]
User=${VOLUMEN_USER}
Group=${VOLUMEN_USER}
WorkingDirectory=${APP_DIR}
ExecStart=$(command -v bundle) exec exe/volumen serve --config ${CONFIG_FILE} --content ${CONTENT_DIR}
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=${DATA_DIR}
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable volumen
}
final_notes() {
cat <<EOF
volumen is installed and the service is enabled (not started yet).
Next steps:
1. Create the first admin password (you will log in as user "admin"):
cd ${APP_DIR}
sudo -u ${VOLUMEN_USER} $(command -v bundle) exec exe/volumen hash-password
Paste the printed hash into ${CONFIG_FILE} under [admin] password_hash.
2. (Recommended) set a stable admin.session_key in the config:
openssl rand -hex 64
3. Start the service:
sudo systemctl start volumen
4. Put nginx in front of 127.0.0.1:9090 — see docs/deployment.md.
EOF
}
main() {
require_root
local distro
distro="$(detect_distro)"
log "Detected distribution: ${distro}"
install_toolchain "$distro"
check_ruby
ensure_bundler
create_user
create_dirs
install_gems
generate_config
install_service
final_notes
}
main "$@"