Files
SingBox-Gopanel/scripts/install.sh
CN-JS-HuiBai 1ed31b9292
All checks were successful
build / build (api, amd64, linux) (push) Successful in -47s
build / build (api, arm64, linux) (push) Successful in -48s
build / build (api.exe, amd64, windows) (push) Successful in -47s
first commit
2026-04-17 09:49:16 +08:00

211 lines
4.8 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
APP_NAME="singbox-gopanel"
SERVICE_NAME="singbox-gopanel"
INSTALL_DIR="/opt/${APP_NAME}"
RUN_USER="${SUDO_USER:-${USER:-root}}"
SKIP_SERVICE="false"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGE_DIR="${SCRIPT_DIR}"
BIN_NAME="api"
usage() {
cat <<EOF
Usage: install.sh [options]
Options:
--install-dir <dir> Install directory, default: ${INSTALL_DIR}
--service-name <name> systemd service name, default: ${SERVICE_NAME}
--run-user <user> Runtime user, default: ${RUN_USER}
--package-dir <dir> Package directory, default: ${PACKAGE_DIR}
--skip-service Skip systemd service installation
-h, --help Show this help
Expected package layout:
${BIN_NAME}
frontend/
docs/
README.md
.env.example (optional)
Example:
sudo bash ./install.sh --install-dir /opt/singbox-gopanel --run-user root
EOF
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--install-dir)
INSTALL_DIR="$2"
shift 2
;;
--service-name)
SERVICE_NAME="$2"
shift 2
;;
--run-user)
RUN_USER="$2"
shift 2
;;
--package-dir)
PACKAGE_DIR="$2"
shift 2
;;
--skip-service)
SKIP_SERVICE="true"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "error: unknown option: $1" >&2
usage
exit 1
;;
esac
done
}
ensure_root() {
if [[ "${EUID}" -ne 0 ]]; then
echo "error: please run as root or via sudo" >&2
exit 1
fi
}
ensure_run_user() {
if ! id "${RUN_USER}" >/dev/null 2>&1; then
echo "error: run user does not exist: ${RUN_USER}" >&2
exit 1
fi
}
ensure_package_layout() {
if [[ ! -f "${PACKAGE_DIR}/${BIN_NAME}" ]]; then
echo "error: binary not found: ${PACKAGE_DIR}/${BIN_NAME}" >&2
exit 1
fi
if [[ ! -d "${PACKAGE_DIR}/frontend" ]]; then
echo "error: frontend directory not found: ${PACKAGE_DIR}/frontend" >&2
exit 1
fi
if [[ ! -d "${PACKAGE_DIR}/docs" ]]; then
echo "error: docs directory not found: ${PACKAGE_DIR}/docs" >&2
exit 1
fi
}
prepare_dirs() {
mkdir -p "${INSTALL_DIR}"
mkdir -p "${INSTALL_DIR}/frontend"
mkdir -p "${INSTALL_DIR}/docs"
}
copy_runtime_files() {
echo "copying package files into ${INSTALL_DIR}..."
install -m 0755 "${PACKAGE_DIR}/${BIN_NAME}" "${INSTALL_DIR}/${BIN_NAME}"
rm -rf "${INSTALL_DIR}/frontend"
mkdir -p "${INSTALL_DIR}/frontend"
cp -R "${PACKAGE_DIR}/frontend/." "${INSTALL_DIR}/frontend/"
rm -rf "${INSTALL_DIR}/docs"
mkdir -p "${INSTALL_DIR}/docs"
cp -R "${PACKAGE_DIR}/docs/." "${INSTALL_DIR}/docs/"
if [[ -f "${PACKAGE_DIR}/README.md" ]]; then
cp -f "${PACKAGE_DIR}/README.md" "${INSTALL_DIR}/README.md"
fi
if [[ -f "${PACKAGE_DIR}/.env.example" ]]; then
cp -f "${PACKAGE_DIR}/.env.example" "${INSTALL_DIR}/.env.example"
fi
if [[ -f "${PACKAGE_DIR}/.env" && ! -f "${INSTALL_DIR}/.env" ]]; then
cp -f "${PACKAGE_DIR}/.env" "${INSTALL_DIR}/.env"
fi
if [[ ! -f "${INSTALL_DIR}/.env" && -f "${INSTALL_DIR}/.env.example" ]]; then
cp -f "${INSTALL_DIR}/.env.example" "${INSTALL_DIR}/.env"
echo "created ${INSTALL_DIR}/.env from .env.example"
fi
}
install_service() {
if [[ "${SKIP_SERVICE}" == "true" ]]; then
echo "skip service enabled"
return
fi
if ! command -v systemctl >/dev/null 2>&1; then
echo "systemctl not found, skipping service installation"
return
fi
cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=SingBox GoPanel API
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=${RUN_USER}
WorkingDirectory=${INSTALL_DIR}
EnvironmentFile=-${INSTALL_DIR}/.env
ExecStart=${INSTALL_DIR}/${BIN_NAME}
Restart=always
RestartSec=5
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "${SERVICE_NAME}"
systemctl restart "${SERVICE_NAME}"
}
print_summary() {
cat <<EOF
Install complete.
Package dir: ${PACKAGE_DIR}
Install directory: ${INSTALL_DIR}
Binary: ${INSTALL_DIR}/${BIN_NAME}
Frontend: ${INSTALL_DIR}/frontend
Docs: ${INSTALL_DIR}/docs
Service name: ${SERVICE_NAME}
Next steps:
1. Edit ${INSTALL_DIR}/.env if needed
2. Check service status: systemctl status ${SERVICE_NAME}
3. Tail logs: journalctl -u ${SERVICE_NAME} -f
EOF
}
main() {
parse_args "$@"
if [[ ! -f "${PACKAGE_DIR}/${BIN_NAME}" && -f "${SCRIPT_DIR}/../${BIN_NAME}" ]]; then
PACKAGE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
fi
ensure_root
ensure_run_user
ensure_package_layout
prepare_dirs
copy_runtime_files
chown -R "${RUN_USER}:${RUN_USER}" "${INSTALL_DIR}" || true
chmod +x "${INSTALL_DIR}/${BIN_NAME}" || true
install_service
print_summary
}
main "$@"