#!/usr/bin/env bash # Origin file: https://github.com/Gozargah/Marzban-scripts/raw/master/marzban.sh set -e INSTALL_DIR="/opt" if [ -z "$APP_NAME" ]; then APP_NAME="marzban" fi APP_DIR="$INSTALL_DIR/$APP_NAME" DATA_DIR="/var/lib/$APP_NAME" COMPOSE_FILE="$APP_DIR/docker-compose.yml" colorized_echo() { local color=$1 local text=$2 echo "${text}" } check_running_as_root() { if [ "$(id -u)" != "0" ]; then colorized_echo red "This command must be run as root." exit 1 fi } detect_os() { # Detect the operating system if [ -f /etc/lsb-release ]; then OS=$(lsb_release -si) elif [ -f /etc/os-release ]; then OS=$(awk -F= '/^NAME/{print $2}' /etc/os-release | tr -d '"') elif [ -f /etc/redhat-release ]; then OS=$(cat /etc/redhat-release | awk '{print $1}') elif [ -f /etc/arch-release ]; then OS="Arch" else colorized_echo red "Unsupported operating system" exit 1 fi } detect_and_update_package_manager() { colorized_echo blue "Updating package manager" if [[ "$OS" == "Ubuntu"* ]] || [[ "$OS" == "Debian"* ]]; then PKG_MANAGER="apt-get" $PKG_MANAGER update elif [[ "$OS" == "CentOS"* ]]; then PKG_MANAGER="yum" $PKG_MANAGER update -y $PKG_MANAGER epel-release -y elif [ "$OS" == "Fedora"* ]; then PKG_MANAGER="dnf" $PKG_MANAGER update elif [ "$OS" == "Arch" ]; then PKG_MANAGER="pacman" $PKG_MANAGER -Sy else colorized_echo red "Unsupported operating system" exit 1 fi } detect_compose() { # Check if docker compose command exists if docker compose >/dev/null 2>&1; then COMPOSE='docker compose' elif docker-compose >/dev/null 2>&1; then COMPOSE='docker-compose' else colorized_echo red "docker compose not found" exit 1 fi } install_package () { if [ -z $PKG_MANAGER ]; then detect_and_update_package_manager fi PACKAGE=$1 colorized_echo blue "Installing $PACKAGE" if [[ "$OS" == "Ubuntu"* ]] || [[ "$OS" == "Debian"* ]]; then $PKG_MANAGER -y install "$PACKAGE" elif [[ "$OS" == "CentOS"* ]]; then $PKG_MANAGER install -y "$PACKAGE" elif [ "$OS" == "Fedora"* ]; then $PKG_MANAGER install -y "$PACKAGE" elif [ "$OS" == "Arch" ]; then $PKG_MANAGER -S --noconfirm "$PACKAGE" else colorized_echo red "Unsupported operating system" exit 1 fi } install_docker() { # Install Docker and Docker Compose using the official installation script colorized_echo blue "Installing Docker" curl -fsSL https://get.docker.com | sh colorized_echo green "Docker installed successfully" } install_marzban_script() { FETCH_REPO="Gozargah/Marzban-scripts" SCRIPT_URL="https://github.com/$FETCH_REPO/raw/master/marzban.sh" colorized_echo blue "Installing marzban script" curl -sSL $SCRIPT_URL | install -m 755 /dev/stdin /usr/local/bin/marzban colorized_echo green "marzban script installed successfully" } install_marzban() { # Fetch releases FILES_URL_PREFIX="https://raw.githubusercontent.com/Gozargah/Marzban/master" mkdir -p "$DATA_DIR" mkdir -p "$APP_DIR" colorized_echo blue "Fetching compose file" curl -sL "$FILES_URL_PREFIX/docker-compose.yml" -o "$APP_DIR/docker-compose.yml" colorized_echo green "File saved in $APP_DIR/docker-compose.yml" colorized_echo blue "Fetching .env file" curl -sL "$FILES_URL_PREFIX/.env.example" -o "$APP_DIR/.env" sed -i 's/^# \(XRAY_JSON = .*\)$/\1/' "$APP_DIR/.env" sed -i 's/^# \(SQLALCHEMY_DATABASE_URL = .*\)$/\1/' "$APP_DIR/.env" sed -i 's~\(XRAY_JSON = \).*~\1"/var/lib/marzban/xray_config.json"~' "$APP_DIR/.env" sed -i 's~\(SQLALCHEMY_DATABASE_URL = \).*~\1"sqlite:////var/lib/marzban/db.sqlite3"~' "$APP_DIR/.env" [ -z "$SUDO_USERNAME" ] || echo "SUDO_USERNAME=$SUDO_USERNAME" >> "$APP_DIR/.env" [ -z "$SUDO_PASSWORD" ] || echo "SUDO_PASSWORD=$SUDO_PASSWORD" >> "$APP_DIR/.env" colorized_echo green "File saved in $APP_DIR/.env" colorized_echo blue "Fetching xray config file" curl -sL "$FILES_URL_PREFIX/xray_config.json" -o "$DATA_DIR/xray_config.json" colorized_echo green "File saved in $DATA_DIR/xray_config.json" colorized_echo green "Marzban's files downloaded successfully" } uninstall_marzban_script() { if [ -f "/usr/local/bin/marzban" ]; then colorized_echo yellow "Removing marzban script" rm "/usr/local/bin/marzban" fi } uninstall_marzban() { if [ -d "$APP_DIR" ]; then colorized_echo yellow "Removing directory: $APP_DIR" rm -r "$APP_DIR" fi } uninstall_marzban_docker_images() { images=$(docker images | grep marzban | awk '{print $3}') if [ -n "$images" ]; then colorized_echo yellow "Removing Docker images of Marzban" for image in $images; do if docker rmi "$image" >/dev/null 2>&1; then colorized_echo yellow "Image $image removed" fi done fi } uninstall_marzban_data_files() { if [ -d "$DATA_DIR" ]; then colorized_echo yellow "Removing directory: $DATA_DIR" rm -r "$DATA_DIR" fi } up_marzban() { $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" up -d --remove-orphans } down_marzban() { $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" down } show_marzban_logs() { $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" logs } follow_marzban_logs() { $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" logs -f } marzban_cli() { $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" exec -e CLI_PROG_NAME="marzban cli" marzban marzban-cli "$@" } update_marzban_script() { FETCH_REPO="Gozargah/Marzban-scripts" SCRIPT_URL="https://github.com/$FETCH_REPO/raw/master/marzban.sh" colorized_echo blue "Updating marzban script" curl -sSL $SCRIPT_URL | install -m 755 /dev/stdin /usr/local/bin/marzban colorized_echo green "marzban script updated successfully" } update_marzban() { $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" pull } is_marzban_installed() { if [ -d $APP_DIR ]; then return 0 else return 1 fi } is_marzban_up() { if [ -z "$($COMPOSE -f $COMPOSE_FILE ps -q -a)" ]; then return 1 else return 0 fi } install_command() { check_running_as_root # Check if marzban is already installed if is_marzban_installed; then colorized_echo red "Marzban is already installed at $APP_DIR" colorized_echo red "If you want to reinstall it, please run: '$0 uninstall' before" colorized_echo red "Aborted installation" exit 0 fi detect_os if ! command -v jq >/dev/null 2>&1; then install_package jq fi if ! command -v curl >/dev/null 2>&1; then install_package curl fi if ! command -v docker >/dev/null 2>&1; then install_docker fi detect_compose install_marzban_script install_marzban up_marzban show_marzban_logs } uninstall_command() { check_running_as_root # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi read -p "Do you really want to uninstall Marzban? (y/n) " if [[ ! $REPLY =~ ^[Yy]$ ]]; then colorized_echo red "Aborted" exit 1 fi detect_compose if is_marzban_up; then down_marzban fi uninstall_marzban_script uninstall_marzban uninstall_marzban_docker_images read -p "Do you want to remove Marzban's data files too ($DATA_DIR)? (y/n) " if [[ ! $REPLY =~ ^[Yy]$ ]]; then colorized_echo green "Marzban uninstalled successfully" else uninstall_marzban_data_files colorized_echo green "Marzban uninstalled successfully" fi } up_command() { help() { colorized_echo red "Usage: marzban up [options]" echo "" echo "OPTIONS:" echo " -h, --help display this help message" echo " -n, --no-logs do not follow logs after starting" } local no_logs=false while [[ "$#" -gt 0 ]]; do case "$1" in -n|--no-logs) no_logs=true ;; -h|--help) help exit 0 ;; *) echo "Error: Invalid option: $1" >&2 help exit 0 ;; esac shift done # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi detect_compose if is_marzban_up; then colorized_echo red "Marzban's already up" exit 1 fi up_marzban if [ "$no_logs" = false ]; then follow_marzban_logs fi } down_command() { # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi detect_compose if ! is_marzban_up; then colorized_echo red "Marzban's already down" exit 1 fi down_marzban } restart_command() { help() { colorized_echo red "Usage: marzban restart [options]" echo echo "OPTIONS:" echo " -h, --help display this help message" echo " -n, --no-logs do not follow logs after starting" } local no_logs=false while [[ "$#" -gt 0 ]]; do case "$1" in -n|--no-logs) no_logs=true ;; -h|--help) help exit 0 ;; *) echo "Error: Invalid option: $1" >&2 help exit 0 ;; esac shift done # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi detect_compose down_marzban up_marzban if [ "$no_logs" = false ]; then follow_marzban_logs fi } status_command() { # Check if marzban is installed if ! is_marzban_installed; then echo -n "Status: " colorized_echo red "Not Installed" exit 1 fi detect_compose if ! is_marzban_up; then echo -n "Status: " colorized_echo blue "Down" exit 1 fi echo -n "Status: " colorized_echo green "Up" json=$($COMPOSE -f $COMPOSE_FILE ps -a --format=json) services=$(echo $json | jq -r '.[] | .Service') states=$(echo $json | jq -r '.[] | .State') # Print out the service names and statuses for i in $(seq 0 $(expr $(echo $services | wc -w) - 1)); do service=$(echo $services | cut -d' ' -f $(expr $i + 1)) state=$(echo $states | cut -d' ' -f $(expr $i + 1)) echo -n "- $service: " if [ "$state" == "running" ]; then colorized_echo green $state else colorized_echo red $state fi done } logs_command() { help() { colorized_echo red "Usage: marzban logs [options]" echo "" echo "OPTIONS:" echo " -h, --help display this help message" echo " -n, --no-follow do not show follow logs" } local no_follow=false while [[ "$#" -gt 0 ]]; do case "$1" in -n|--no-follow) no_follow=true ;; -h|--help) help exit 0 ;; *) echo "Error: Invalid option: $1" >&2 help exit 0 ;; esac shift done # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi detect_compose if ! is_marzban_up; then colorized_echo red "Marzban is not up." exit 1 fi if [ "$no_follow" = true ]; then show_marzban_logs else follow_marzban_logs fi } cli_command() { # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi detect_compose if ! is_marzban_up; then colorized_echo red "Marzban is not up." exit 1 fi marzban_cli "$@" } update_command() { check_running_as_root # Check if marzban is installed if ! is_marzban_installed; then colorized_echo red "Marzban's not installed!" exit 1 fi detect_compose update_marzban_script colorized_echo blue "Pulling latest version" update_marzban colorized_echo blue "Restarting Marzban's services" down_marzban up_marzban colorized_echo blue "Marzban updated successfully" } usage() { colorized_echo red "Usage: marzban [command]" echo echo "Commands:" echo " up Start services" echo " down Stop services" echo " restart Restart services" echo " status Show status" echo " logs Show logs" echo " cli Marzban CLI" echo " install Install Marzban" echo " update Update latest version" echo " uninstall Uninstall Marzban" echo } case "$1" in up) shift; up_command "$@";; down) shift; down_command "$@";; restart) shift; restart_command "$@";; status) shift; status_command "$@";; logs) shift; logs_command "$@";; cli) shift; cli_command "$@";; install) shift; install_command "$@";; update) shift; update_command "$@";; uninstall) shift; uninstall_command "$@";; *) usage;; esac