#!/usr/bin/env bash # # install.sh — ReceiptNext one-command installer for bare-metal servers # # Usage: # curl -sL https://git.lohmar.co.uk/cclohmar/ReceiptNext/releases/download/v1.0.0/install.sh | bash # # Or from a local clone: # ./install.sh # # What it does: # 1. Creates receiptnext user if missing # 2. Creates /opt/receiptnext with templates/, static/, storage/ # 3. Installs binary to /usr/local/bin/receiptnext # 4. Creates /etc/receiptnext/.env from .env.example (if not exists) # 5. Installs systemd service # 6. Starts the service # 7. Shows status and instructions set -euo pipefail BINARY="receiptnext" INSTALL_DIR="/opt/${BINARY}" BIN_DIR="/usr/local/bin" ETC_DIR="/etc/${BINARY}" SERVICE_FILE="contrib/${BINARY}.service" LOG_FILE="/var/log/${BINARY}.log" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color info() { echo -e "${GREEN}[✓]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } error() { echo -e "${RED}[✗]${NC} $1"; } # Check if running as root if [ "$EUID" -ne 0 ]; then error "Please run as root: sudo ./install.sh" exit 1 fi echo "" echo " ╔═══════════════════════════════════════╗" echo " ║ ReceiptNext Installer ║" echo " ║ AI-Powered Expense Tracker ║" echo " ╚═══════════════════════════════════════╝" echo "" # ── Step 1: Build or download binary ────────────────────────────── if [ -f "./${BINARY}" ]; then info "Binary found locally" elif [ -f "go.mod" ]; then info "Building from source..." if ! command -v go &>/dev/null; then error "Go is required to build from source. Install go 1.22+ and re-run." exit 1 fi go build -ldflags="-s -w" -o "${BINARY}" . info "Build complete" else # Try to download the latest release TAG=$(curl -s https://git.lohmar.co.uk/api/v1/repos/cclohmar/ReceiptNext/releases/latest \ | python3 -c "import json,sys; print(json.load(sys.stdin).get('tag_name','v1.0.0'))" 2>/dev/null || echo "v1.0.0") ARCH=$(uname -m) case "$ARCH" in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; *) error "Unsupported architecture: $ARCH"; exit 1 ;; esac URL="https://git.lohmar.co.uk/cclohmar/ReceiptNext/releases/download/${TAG}/${BINARY}-linux-${ARCH}" info "Downloading ${URL}..." curl -sL -o "${BINARY}" "${URL}" info "Download complete" fi chmod +x "${BINARY}" # ── Step 2: Create system user ──────────────────────────────────── if ! id -u ${BINARY} &>/dev/null 2>&1; then useradd -r -s /bin/false -d "${INSTALL_DIR}" ${BINARY} info "Created system user '${BINARY}'" fi # ── Step 3: Create install directory ────────────────────────────── mkdir -p "${INSTALL_DIR}"/{templates,static/css,static/icons,storage} # Copy templates and static assets cp -r templates/* "${INSTALL_DIR}/templates/" cp -r static/* "${INSTALL_DIR}/static/" cp -r storage/. "${INSTALL_DIR}/storage/" 2>/dev/null || true # ── Step 4: Install binary ──────────────────────────────────────── cp "${BINARY}" "${BIN_DIR}/${BINARY}" chmod +x "${BIN_DIR}/${BINARY}" info "Installed binary to ${BIN_DIR}/${BINARY}" # ── Step 5: Create config directory ─────────────────────────────── mkdir -p "${ETC_DIR}" if [ ! -f "${ETC_DIR}/.env" ]; then if [ -f ".env.example" ]; then cp .env.example "${ETC_DIR}/.env" info "Created ${ETC_DIR}/.env — edit it with your credentials" else warn "No .env.example found — create ${ETC_DIR}/.env manually" fi else info "${ETC_DIR}/.env already exists — keeping existing config" fi # ── Step 6: Install systemd service ─────────────────────────────── if [ -f "${SERVICE_FILE}" ]; then cp "${SERVICE_FILE}" /etc/systemd/system/ systemctl daemon-reload systemctl enable ${BINARY} info "Systemd service installed and enabled" fi # ── Step 7: Set permissions ─────────────────────────────────────── chown -R ${BINARY}:${BINARY} "${INSTALL_DIR}" chown ${BINARY}:${BINARY} "${ETC_DIR}/.env" 2>/dev/null || true touch "${LOG_FILE}" && chown ${BINARY}:${BINARY} "${LOG_FILE}" # ── Step 8: Start service ───────────────────────────────────────── systemctl start ${BINARY} || warn "Service failed to start — check 'systemctl status ${BINARY}'" sleep 2 echo "" echo " ╔═══════════════════════════════════════╗" echo " ║ Installation Complete! ║" echo " ╚═══════════════════════════════════════╝" echo "" echo " Config: ${ETC_DIR}/.env" echo " Binary: ${BIN_DIR}/${BINARY}" echo " Data: ${INSTALL_DIR}" echo " Logs: ${LOG_FILE}" echo " Service: systemctl status ${BINARY}" echo " Restart: systemctl restart ${BINARY}" echo " Log tail: journalctl -u ${BINARY} -f" echo "" if systemctl is-active --quiet ${BINARY}; then info "ReceiptNext is running!" echo " Open http://YOUR_SERVER_IP:8080 in your browser" echo "" echo " First steps:" echo " 1. Edit ${ETC_DIR}/.env with your SMTP + AI credentials" echo " 2. Restart: systemctl restart ${BINARY}" echo "" else warn "Service is not running. Check: systemctl status ${BINARY}" fi