NextExpense/install.sh
cclohmar f50048e833 chore: rename to ReceiptNext + deployment scripts
- Full rename: module path, imports, directory structure
- install.sh: one-command bare-metal deployment
- contrib/receiptnext.service: systemd service file
- Makefile: build, install, manage service
- .gitenv updated to ReceiptNext
- New Releases page on git.lohmar.co.uk/cclohmar/ReceiptNext
2026-05-30 14:20:49 +00:00

153 lines
5.9 KiB
Bash

#!/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