https://dev.kronoz.win/r/marzneshin.git
1#!/usr/bin/env bash
2set -e
3
4APP_NAME="marzneshin"
5NODE_NAME="marznode"
6CONFIG_DIR="/etc/opt/$APP_NAME"
7DATA_DIR="/var/lib/$APP_NAME"
8NODE_DATA_DIR="/var/lib/$NODE_NAME"
9COMPOSE_FILE="$CONFIG_DIR/docker-compose.yml"
10
11
12colorized_echo() {
13 local color=$1
14 local text=$2
15
16 case $color in
17 "red")
18 printf "\e[91m${text}\e[0m\n";;
19 "green")
20 printf "\e[92m${text}\e[0m\n";;
21 "yellow")
22 printf "\e[93m${text}\e[0m\n";;
23 "blue")
24 printf "\e[94m${text}\e[0m\n";;
25 "magenta")
26 printf "\e[95m${text}\e[0m\n";;
27 "cyan")
28 printf "\e[96m${text}\e[0m\n";;
29 *)
30 echo "${text}"
31 ;;
32 esac
33}
34
35check_running_as_root() {
36 if [ "$(id -u)" != "0" ]; then
37 colorized_echo red "This command must be run as root."
38 exit 1
39 fi
40}
41
42detect_os() {
43 # Detect the operating system
44 if [ -f /etc/lsb-release ]; then
45 OS=$(lsb_release -si)
46 elif [ -f /etc/os-release ]; then
47 OS=$(awk -F= '/^NAME/{print $2}' /etc/os-release | tr -d '"')
48 elif [ -f /etc/redhat-release ]; then
49 OS=$(cat /etc/redhat-release | awk '{print $1}')
50 elif [ -f /etc/arch-release ]; then
51 OS="Arch"
52 else
53 colorized_echo red "Unsupported operating system"
54 exit 1
55 fi
56}
57
58detect_and_update_package_manager() {
59 colorized_echo blue "Updating package manager"
60 if [[ "$OS" == "Ubuntu"* ]] || [[ "$OS" == "Debian"* ]]; then
61 PKG_MANAGER="apt-get"
62 $PKG_MANAGER update
63 elif [[ "$OS" == "CentOS"* ]] || [[ "$OS" == "AlmaLinux"* ]]; then
64 PKG_MANAGER="yum"
65 $PKG_MANAGER update -y
66 $PKG_MANAGER install -y epel-release
67 elif [ "$OS" == "Fedora"* ]; then
68 PKG_MANAGER="dnf"
69 $PKG_MANAGER update
70 elif [ "$OS" == "Arch" ]; then
71 PKG_MANAGER="pacman"
72 $PKG_MANAGER -Sy
73 else
74 colorized_echo red "Unsupported operating system"
75 exit 1
76 fi
77}
78
79detect_compose() {
80 # Check if docker compose command exists
81 if docker compose >/dev/null 2>&1; then
82 COMPOSE='docker compose'
83 elif docker-compose >/dev/null 2>&1; then
84 COMPOSE='docker-compose'
85 else
86 colorized_echo red "docker compose not found"
87 exit 1
88 fi
89}
90
91install_package () {
92 if [ -z $PKG_MANAGER ]; then
93 detect_and_update_package_manager
94 fi
95
96 PACKAGE=$1
97 colorized_echo blue "Installing $PACKAGE"
98 if [[ "$OS" == "Ubuntu"* ]] || [[ "$OS" == "Debian"* ]]; then
99 $PKG_MANAGER -y install "$PACKAGE"
100 elif [[ "$OS" == "CentOS"* ]] || [[ "$OS" == "AlmaLinux"* ]]; then
101 $PKG_MANAGER install -y "$PACKAGE"
102 elif [ "$OS" == "Fedora"* ]; then
103 $PKG_MANAGER install -y "$PACKAGE"
104 elif [ "$OS" == "Arch" ]; then
105 $PKG_MANAGER -S --noconfirm "$PACKAGE"
106 else
107 colorized_echo red "Unsupported operating system"
108 exit 1
109 fi
110}
111
112install_docker() {
113 # Install Docker and Docker Compose using the official installation script
114 colorized_echo blue "Installing Docker"
115 curl -fsSL https://get.docker.com | sh
116 colorized_echo green "Docker installed successfully"
117}
118
119install_marzneshin_script() {
120 FETCH_REPO="khodedawsh/marzneshin"
121 SCRIPT_URL="https://github.com/$FETCH_REPO/raw/master/script.sh"
122 colorized_echo blue "Installing marzneshin script"
123 curl -sSL $SCRIPT_URL | install -m 755 /dev/stdin /usr/local/bin/marzneshin
124 colorized_echo green "marzneshin script installed successfully"
125}
126
127install_marzneshin() {
128 # Fetch releases
129 FILES_URL_PREFIX="https://raw.githubusercontent.com/khodedawsh/marzneshin/master"
130
131 mkdir -p "$DATA_DIR"
132 mkdir -p "$CONFIG_DIR"
133
134 colorized_echo blue "Fetching compose file"
135 curl -sL "$FILES_URL_PREFIX/docker-compose.yml" -o "$CONFIG_DIR/docker-compose.yml"
136 colorized_echo green "File saved in $CONFIG_DIR/docker-compose.yml"
137
138 colorized_echo blue "Fetching .env file"
139 curl -sL "$FILES_URL_PREFIX/.env.example" -o "$CONFIG_DIR/.env"
140 sed -i 's/^# \(SQLALCHEMY_DATABASE_URL = .*\)$/\1/' "$CONFIG_DIR/.env"
141 sed -i 's~\(SQLALCHEMY_DATABASE_URL = \).*~\1"sqlite:///'$DATA_DIR'/db.sqlite3"~' "$CONFIG_DIR/.env"
142 colorized_echo green "File saved in $CONFIG_DIR/.env"
143
144 colorized_echo green "Marzneshin files downloaded successfully"
145}
146
147install_marznode_xray_config() {
148 mkdir -p "$NODE_DATA_DIR"
149 curl -sL "https://raw.githubusercontent.com/khodedawsh/marznode/master/xray_config.json" -o "$NODE_DATA_DIR/xray_config.json"
150 colorized_echo green "Sample xray config downloaded for marznode"
151}
152
153uninstall_marzneshin_script() {
154 if [ -f "/usr/local/bin/marzneshin" ]; then
155 colorized_echo yellow "Removing marzneshin script"
156 rm "/usr/local/bin/marzneshin"
157 fi
158}
159
160uninstall_marzneshin() {
161 if [ -d "$CONFIG_DIR" ]; then
162 colorized_echo yellow "Removing directory: $CONFIG_DIR"
163 rm -r "$CONFIG_DIR"
164 fi
165}
166
167uninstall_marzneshin_docker_images() {
168 images=$(docker images | grep marzneshin | awk '{print $3}')
169
170 if [ -n "$images" ]; then
171 colorized_echo yellow "Removing Docker images of Marzneshin"
172 for image in $images; do
173 if docker rmi "$image" >/dev/null 2>&1; then
174 colorized_echo yellow "Image $image removed"
175 fi
176 done
177 fi
178}
179
180uninstall_marzneshin_data_files() {
181 if [ -d "$DATA_DIR" ]; then
182 colorized_echo yellow "Removing directory: $DATA_DIR"
183 rm -r "$DATA_DIR"
184 fi
185}
186
187uninstall_marznode_data_files() {
188 if [ -d "$NODE_DATA_DIR" ]; then
189 colorized_echo yellow "Removing directory: $NODE_DATA_DIR"
190 rm -r "$NODE_DATA_DIR"
191 fi
192}
193
194
195up_marzneshin() {
196 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" up -d --remove-orphans
197}
198
199down_marzneshin() {
200 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" down
201}
202
203show_marzneshin_logs() {
204 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" logs
205}
206
207follow_marzneshin_logs() {
208 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" logs -f
209}
210
211marzneshin_cli() {
212 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" exec -e CLI_PROG_NAME="marzneshin cli" marzneshin /app/marzneshin-cli.py "$@"
213}
214
215
216update_marzneshin_script() {
217 FETCH_REPO="khodedawsh/marzneshin"
218 SCRIPT_URL="https://github.com/$FETCH_REPO/raw/master/script.sh"
219 colorized_echo blue "Updating marzneshin script"
220 curl -sSL $SCRIPT_URL | install -m 755 /dev/stdin /usr/local/bin/marzneshin
221 colorized_echo green "marzneshin script updated successfully"
222}
223
224update_marzneshin() {
225 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" pull
226}
227
228is_marzneshin_installed() {
229 if [ -d $CONFIG_DIR ]; then
230 return 0
231 else
232 return 1
233 fi
234}
235
236is_marzneshin_up() {
237 if [ -z "$($COMPOSE -f $COMPOSE_FILE ps -q -a)" ]; then
238 return 1
239 else
240 return 0
241 fi
242}
243
244install_command() {
245 check_running_as_root
246 # Check if marzneshin is already installed
247 if is_marzneshin_installed; then
248 colorized_echo red "Marzneshin is already installed at $CONFIG_DIR"
249 read -p "Do you want to override the previous installation? (y/n) "
250 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
251 colorized_echo red "Aborted installation"
252 exit 1
253 fi
254 fi
255 detect_os
256 if ! command -v jq >/dev/null 2>&1; then
257 install_package jq
258 fi
259 if ! command -v curl >/dev/null 2>&1; then
260 install_package curl
261 fi
262 if ! command -v docker >/dev/null 2>&1; then
263 install_docker
264 fi
265 detect_compose
266 install_marzneshin_script
267 install_marzneshin
268 install_marznode_xray_config
269 up_marzneshin
270 follow_marzneshin_logs
271}
272
273uninstall_command() {
274 check_running_as_root
275 # Check if marzneshin is installed
276 if ! is_marzneshin_installed; then
277 colorized_echo red "Marzneshin's not installed!"
278 exit 1
279 fi
280
281 read -p "Do you really want to uninstall Marzneshin? (y/n) "
282 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
283 colorized_echo red "Aborted"
284 exit 1
285 fi
286
287 detect_compose
288 if is_marzneshin_up; then
289 down_marzneshin
290 fi
291 uninstall_marzneshin_script
292 uninstall_marzneshin
293 uninstall_marzneshin_docker_images
294
295 read -p "Do you want to remove marzneshin & marznode data files too ($NODE_DATA_DIR, $DATA_DIR)? (y/n) "
296 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
297 colorized_echo green "Marzneshin uninstalled successfully"
298 else
299 uninstall_marzneshin_data_files
300 uninstall_marznode_data_files
301 colorized_echo green "Marzneshin uninstalled successfully"
302 fi
303}
304
305up_command() {
306 help() {
307 colorized_echo red "Usage: $0 up [options]"
308 echo ""
309 echo "OPTIONS:"
310 echo " -h, --help display this help message"
311 echo " -n, --no-logs do not follow logs after starting"
312 }
313
314 local no_logs=false
315 while [[ "$#" -gt 0 ]]; do
316 case "$1" in
317 -n|--no-logs)
318 no_logs=true
319 ;;
320 -h|--help)
321 help
322 exit 0
323 ;;
324 *)
325 echo "Error: Invalid option: $1" >&2
326 help
327 exit 0
328 ;;
329 esac
330 shift
331 done
332
333 # Check if marzneshin is installed
334 if ! is_marzneshin_installed; then
335 colorized_echo red "Marzneshin is not installed!"
336 exit 1
337 fi
338
339 detect_compose
340
341 if is_marzneshin_up; then
342 colorized_echo red "Marzneshin is already up"
343 exit 1
344 fi
345
346 up_marzneshin
347 if [ "$no_logs" = false ]; then
348 follow_marzneshin_logs
349 fi
350}
351
352down_command() {
353
354 # Check if marzneshin is installed
355 if ! is_marzneshin_installed; then
356 colorized_echo red "Marzneshin's not installed!"
357 exit 1
358 fi
359
360 detect_compose
361
362 if ! is_marzneshin_up; then
363 colorized_echo red "Marzneshin's already down"
364 exit 1
365 fi
366
367 down_marzneshin
368}
369
370restart_command() {
371 help() {
372 colorized_echo red "Usage: $0 restart [options]"
373 echo
374 echo "OPTIONS:"
375 echo " -h, --help display this help message"
376 echo " -n, --no-logs do not follow logs after starting"
377 }
378
379 local no_logs=false
380 while [[ "$#" -gt 0 ]]; do
381 case "$1" in
382 -n|--no-logs)
383 no_logs=true
384 ;;
385 -h|--help)
386 help
387 exit 0
388 ;;
389 *)
390 echo "Error: Invalid option: $1" >&2
391 help
392 exit 0
393 ;;
394 esac
395 shift
396 done
397
398 # Check if marzneshin is installed
399 if ! is_marzneshin_installed; then
400 colorized_echo red "Marzneshin's not installed!"
401 exit 1
402 fi
403
404 detect_compose
405
406 down_marzneshin
407 up_marzneshin
408 if [ "$no_logs" = false ]; then
409 follow_marzneshin_logs
410 fi
411}
412
413status_command() {
414
415 # Check if marzneshin is installed
416 if ! is_marzneshin_installed; then
417 echo -n "Status: "
418 colorized_echo red "Not Installed"
419 exit 1
420 fi
421
422 detect_compose
423
424 if ! is_marzneshin_up; then
425 echo -n "Status: "
426 colorized_echo blue "Down"
427 exit 1
428 fi
429
430 echo -n "Status: "
431 colorized_echo green "Up"
432
433 json=$($COMPOSE -f $COMPOSE_FILE ps -a --format=json)
434 services=$(echo "$json" | jq -r 'if type == "array" then .[] else . end | .Service')
435 states=$(echo "$json" | jq -r 'if type == "array" then .[] else . end | .State')
436 # Print out the service names and statuses
437 for i in $(seq 0 $(expr $(echo $services | wc -w) - 1)); do
438 service=$(echo $services | cut -d' ' -f $(expr $i + 1))
439 state=$(echo $states | cut -d' ' -f $(expr $i + 1))
440 echo -n "- $service: "
441 if [ "$state" == "running" ]; then
442 colorized_echo green $state
443 else
444 colorized_echo red $state
445 fi
446 done
447}
448
449logs_command() {
450 help() {
451 colorized_echo red "Usage: marzneshin logs [options]"
452 echo ""
453 echo "OPTIONS:"
454 echo " -h, --help display this help message"
455 echo " -n, --no-follow do not show follow logs"
456 }
457
458 local no_follow=false
459 while [[ "$#" -gt 0 ]]; do
460 case "$1" in
461 -n|--no-follow)
462 no_follow=true
463 ;;
464 -h|--help)
465 help
466 exit 0
467 ;;
468 *)
469 echo "Error: Invalid option: $1" >&2
470 help
471 exit 0
472 ;;
473 esac
474 shift
475 done
476
477 # Check if marzneshin is installed
478 if ! is_marzneshin_installed; then
479 colorized_echo red "Marzneshin is not installed!"
480 exit 1
481 fi
482
483 detect_compose
484
485 if ! is_marzneshin_up; then
486 colorized_echo red "Marzneshin is not up."
487 exit 1
488 fi
489
490 if [ "$no_follow" = true ]; then
491 show_marzneshin_logs
492 else
493 follow_marzneshin_logs
494 fi
495}
496
497cli_command() {
498 # Check if marzneshin is installed
499 if ! is_marzneshin_installed; then
500 colorized_echo red "Marzneshin is not installed!"
501 exit 1
502 fi
503
504 detect_compose
505
506 if ! is_marzneshin_up; then
507 colorized_echo red "Marzneshin is not up."
508 exit 1
509 fi
510
511 marzneshin_cli "$@"
512}
513
514update_command() {
515 check_running_as_root
516 # Check if marzneshin is installed
517 if ! is_marzneshin_installed; then
518 colorized_echo red "Marzneshin is not installed!"
519 exit 1
520 fi
521
522 detect_compose
523
524 update_marzneshin_script
525 colorized_echo blue "Pulling latest version"
526 update_marzneshin
527
528 colorized_echo blue "Restarting Marzneshin's services"
529 down_marzneshin
530 up_marzneshin
531
532 colorized_echo blue "Marzneshin updated successfully"
533}
534
535
536usage() {
537 colorized_echo red "Usage: $0 [command]"
538 echo
539 echo "Commands:"
540 echo " up Start services"
541 echo " down Stop services"
542 echo " restart Restart services"
543 echo " status Show status"
544 echo " logs Show logs"
545 echo " cli Marzneshin command-line interface"
546 echo " install Install Marzneshin"
547 echo " update Update latest version"
548 echo " uninstall Uninstall Marzneshin"
549 echo " install-script Install Marzneshin script"
550 echo
551}
552
553case "$1" in
554 up)
555 shift; up_command "$@";;
556 down)
557 shift; down_command "$@";;
558 restart)
559 shift; restart_command "$@";;
560 status)
561 shift; status_command "$@";;
562 logs)
563 shift; logs_command "$@";;
564 cli)
565 shift; cli_command "$@";;
566 install)
567 shift; install_command "$@";;
568 update)
569 shift; update_command "$@";;
570 uninstall)
571 shift; uninstall_command "$@";;
572 install-script)
573 shift; install_marzneshin_script "$@";;
574 *)
575 usage;;
576esac