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 COMPOSE_FILES_URL="https://raw.githubusercontent.com/marzneshin/marzneshin-deploy/master"
131 database=$1
132 nightly=$2
133
134 mkdir -p "$DATA_DIR"
135 mkdir -p "$CONFIG_DIR"
136
137 colorized_echo blue "Fetching compose file"
138 curl -sL "$COMPOSE_FILES_URL/docker-compose-$database.yml" -o "$CONFIG_DIR/docker-compose.yml"
139 colorized_echo green "File saved in $CONFIG_DIR/docker-compose.yml"
140 if [ "$nightly" = true ]; then
141 colorized_echo red "setting compose tag to nightly."
142 sed -ri "s/(dawsh\/marzneshin:)latest/\1nightly/g" $CONFIG_DIR/docker-compose.yml
143 fi
144
145 colorized_echo blue "Fetching example .env file"
146 curl -sL "$FILES_URL_PREFIX/.env.example" -o "$CONFIG_DIR/.env"
147 colorized_echo green "File saved in $CONFIG_DIR/.env"
148
149 colorized_echo green "Marzneshin files downloaded successfully"
150}
151
152install_marznode_xray_config() {
153 mkdir -p "$NODE_DATA_DIR"
154 curl -sL "https://raw.githubusercontent.com/khodedawsh/marznode/master/xray_config.json" -o "$NODE_DATA_DIR/xray_config.json"
155 colorized_echo green "Sample xray config downloaded for marznode"
156}
157
158uninstall_marzneshin_script() {
159 if [ -f "/usr/local/bin/marzneshin" ]; then
160 colorized_echo yellow "Removing marzneshin script"
161 rm "/usr/local/bin/marzneshin"
162 fi
163}
164
165uninstall_marzneshin() {
166 if [ -d "$CONFIG_DIR" ]; then
167 colorized_echo yellow "Removing directory: $CONFIG_DIR"
168 rm -r "$CONFIG_DIR"
169 fi
170}
171
172uninstall_marzneshin_docker_images() {
173 images=$(docker images | grep marzneshin | awk '{print $3}')
174
175 if [ -n "$images" ]; then
176 colorized_echo yellow "Removing Docker images of Marzneshin"
177 for image in $images; do
178 if docker rmi "$image" >/dev/null 2>&1; then
179 colorized_echo yellow "Image $image removed"
180 fi
181 done
182 fi
183}
184
185uninstall_marzneshin_data_files() {
186 if [ -d "$DATA_DIR" ]; then
187 colorized_echo yellow "Removing directory: $DATA_DIR"
188 rm -r "$DATA_DIR"
189 fi
190}
191
192uninstall_marznode_data_files() {
193 if [ -d "$NODE_DATA_DIR" ]; then
194 colorized_echo yellow "Removing directory: $NODE_DATA_DIR"
195 rm -r "$NODE_DATA_DIR"
196 fi
197}
198
199
200up_marzneshin() {
201 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" up -d --remove-orphans
202}
203
204down_marzneshin() {
205 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" down
206}
207
208show_marzneshin_logs() {
209 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" logs
210}
211
212follow_marzneshin_logs() {
213 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" logs -f
214}
215
216marzneshin_cli() {
217 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" exec -e CLI_PROG_NAME="marzneshin cli" marzneshin /app/marzneshin-cli.py "$@"
218}
219
220
221update_marzneshin_script() {
222 FETCH_REPO="khodedawsh/marzneshin"
223 SCRIPT_URL="https://github.com/$FETCH_REPO/raw/master/script.sh"
224 colorized_echo blue "Updating marzneshin script"
225 curl -sSL $SCRIPT_URL | install -m 755 /dev/stdin /usr/local/bin/marzneshin
226 colorized_echo green "marzneshin script updated successfully"
227}
228
229update_marzneshin() {
230 $COMPOSE -f $COMPOSE_FILE -p "$APP_NAME" pull
231}
232
233is_marzneshin_installed() {
234 if [ -d $CONFIG_DIR ]; then
235 return 0
236 else
237 return 1
238 fi
239}
240
241is_marzneshin_up() {
242 if [ -z "$($COMPOSE -f $COMPOSE_FILE ps -q -a)" ]; then
243 return 1
244 else
245 return 0
246 fi
247}
248
249install_command() {
250 check_running_as_root
251 # Check if marzneshin is already installed
252 if is_marzneshin_installed; then
253 colorized_echo red "Marzneshin is already installed at $CONFIG_DIR"
254 read -p "Do you want to override the previous installation? (y/n) "
255 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
256 colorized_echo red "Aborted installation"
257 exit 1
258 fi
259 fi
260 detect_os
261 if ! command -v jq >/dev/null 2>&1; then
262 install_package jq
263 fi
264 if ! command -v curl >/dev/null 2>&1; then
265 install_package curl
266 fi
267 if ! command -v docker >/dev/null 2>&1; then
268 install_docker
269 fi
270
271 database="sqlite"
272 nightly=false
273
274 while [[ "$#" -gt 0 ]]; do
275 case $1 in
276 -d|--database)
277 database="$2"
278 if [[ ! $database =~ ^(sqlite|mariadb|mysql)$ ]]; then
279 echo "database could only be sqlite, mysql and mariadb."
280 exit 1
281 fi
282 shift
283 ;;
284 -n|--nightly)
285 nightly=true
286 ;;
287 *)
288 echo "Unknown option: $1"
289 exit 1
290 ;;
291 esac
292 shift
293 done
294
295 detect_compose
296 install_marzneshin_script
297 install_marzneshin $database $nightly
298 install_marznode_xray_config
299 up_marzneshin
300 follow_marzneshin_logs
301}
302
303uninstall_command() {
304 check_running_as_root
305 # Check if marzneshin is installed
306 if ! is_marzneshin_installed; then
307 colorized_echo red "Marzneshin's not installed!"
308 exit 1
309 fi
310
311 read -p "Do you really want to uninstall Marzneshin? (y/n) "
312 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
313 colorized_echo red "Aborted"
314 exit 1
315 fi
316
317 detect_compose
318 if is_marzneshin_up; then
319 down_marzneshin
320 fi
321 uninstall_marzneshin_script
322 uninstall_marzneshin
323 uninstall_marzneshin_docker_images
324
325 read -p "Do you want to remove marzneshin & marznode data files too ($NODE_DATA_DIR, $DATA_DIR)? (y/n) "
326 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
327 colorized_echo green "Marzneshin uninstalled successfully"
328 else
329 uninstall_marzneshin_data_files
330 uninstall_marznode_data_files
331 colorized_echo green "Marzneshin uninstalled successfully"
332 fi
333}
334
335up_command() {
336 help() {
337 colorized_echo red "Usage: $0 up [options]"
338 echo ""
339 echo "OPTIONS:"
340 echo " -h, --help display this help message"
341 echo " -n, --no-logs do not follow logs after starting"
342 }
343
344 local no_logs=false
345 while [[ "$#" -gt 0 ]]; do
346 case "$1" in
347 -n|--no-logs)
348 no_logs=true
349 ;;
350 -h|--help)
351 help
352 exit 0
353 ;;
354 *)
355 echo "Error: Invalid option: $1" >&2
356 help
357 exit 0
358 ;;
359 esac
360 shift
361 done
362
363 # Check if marzneshin is installed
364 if ! is_marzneshin_installed; then
365 colorized_echo red "Marzneshin is not installed!"
366 exit 1
367 fi
368
369 detect_compose
370
371 if is_marzneshin_up; then
372 colorized_echo red "Marzneshin is already up"
373 exit 1
374 fi
375
376 up_marzneshin
377 if [ "$no_logs" = false ]; then
378 follow_marzneshin_logs
379 fi
380}
381
382down_command() {
383
384 # Check if marzneshin is installed
385 if ! is_marzneshin_installed; then
386 colorized_echo red "Marzneshin's not installed!"
387 exit 1
388 fi
389
390 detect_compose
391
392 if ! is_marzneshin_up; then
393 colorized_echo red "Marzneshin's already down"
394 exit 1
395 fi
396
397 down_marzneshin
398}
399
400restart_command() {
401 help() {
402 colorized_echo red "Usage: $0 restart [options]"
403 echo
404 echo "OPTIONS:"
405 echo " -h, --help display this help message"
406 echo " -n, --no-logs do not follow logs after starting"
407 }
408
409 local no_logs=false
410 while [[ "$#" -gt 0 ]]; do
411 case "$1" in
412 -n|--no-logs)
413 no_logs=true
414 ;;
415 -h|--help)
416 help
417 exit 0
418 ;;
419 *)
420 echo "Error: Invalid option: $1" >&2
421 help
422 exit 0
423 ;;
424 esac
425 shift
426 done
427
428 # Check if marzneshin is installed
429 if ! is_marzneshin_installed; then
430 colorized_echo red "Marzneshin's not installed!"
431 exit 1
432 fi
433
434 detect_compose
435
436 down_marzneshin
437 up_marzneshin
438 if [ "$no_logs" = false ]; then
439 follow_marzneshin_logs
440 fi
441}
442
443status_command() {
444
445 # Check if marzneshin is installed
446 if ! is_marzneshin_installed; then
447 echo -n "Status: "
448 colorized_echo red "Not Installed"
449 exit 1
450 fi
451
452 detect_compose
453
454 if ! is_marzneshin_up; then
455 echo -n "Status: "
456 colorized_echo blue "Down"
457 exit 1
458 fi
459
460 echo -n "Status: "
461 colorized_echo green "Up"
462
463 json=$($COMPOSE -f $COMPOSE_FILE ps -a --format=json)
464 services=$(echo "$json" | jq -r 'if type == "array" then .[] else . end | .Service')
465 states=$(echo "$json" | jq -r 'if type == "array" then .[] else . end | .State')
466 # Print out the service names and statuses
467 for i in $(seq 0 $(expr $(echo $services | wc -w) - 1)); do
468 service=$(echo $services | cut -d' ' -f $(expr $i + 1))
469 state=$(echo $states | cut -d' ' -f $(expr $i + 1))
470 echo -n "- $service: "
471 if [ "$state" == "running" ]; then
472 colorized_echo green $state
473 else
474 colorized_echo red $state
475 fi
476 done
477}
478
479logs_command() {
480 help() {
481 colorized_echo red "Usage: marzneshin logs [options]"
482 echo ""
483 echo "OPTIONS:"
484 echo " -h, --help display this help message"
485 echo " -n, --no-follow do not show follow logs"
486 }
487
488 local no_follow=false
489 while [[ "$#" -gt 0 ]]; do
490 case "$1" in
491 -n|--no-follow)
492 no_follow=true
493 ;;
494 -h|--help)
495 help
496 exit 0
497 ;;
498 *)
499 echo "Error: Invalid option: $1" >&2
500 help
501 exit 0
502 ;;
503 esac
504 shift
505 done
506
507 # Check if marzneshin is installed
508 if ! is_marzneshin_installed; then
509 colorized_echo red "Marzneshin is not installed!"
510 exit 1
511 fi
512
513 detect_compose
514
515 if ! is_marzneshin_up; then
516 colorized_echo red "Marzneshin is not up."
517 exit 1
518 fi
519
520 if [ "$no_follow" = true ]; then
521 show_marzneshin_logs
522 else
523 follow_marzneshin_logs
524 fi
525}
526
527cli_command() {
528 # Check if marzneshin is installed
529 if ! is_marzneshin_installed; then
530 colorized_echo red "Marzneshin is not installed!"
531 exit 1
532 fi
533
534 detect_compose
535
536 if ! is_marzneshin_up; then
537 colorized_echo red "Marzneshin is not up."
538 exit 1
539 fi
540
541 marzneshin_cli "$@"
542}
543
544update_command() {
545 check_running_as_root
546 # Check if marzneshin is installed
547 if ! is_marzneshin_installed; then
548 colorized_echo red "Marzneshin is not installed!"
549 exit 1
550 fi
551
552 detect_compose
553
554 update_marzneshin_script
555 colorized_echo blue "Pulling latest version"
556 update_marzneshin
557
558 colorized_echo blue "Restarting Marzneshin's services"
559 down_marzneshin
560 up_marzneshin
561
562 colorized_echo blue "Marzneshin updated successfully"
563}
564
565
566usage() {
567 colorized_echo red "Usage: $0 [command]"
568 echo
569 echo "Commands:"
570 echo " up Start services"
571 echo " down Stop services"
572 echo " restart Restart services"
573 echo " status Show status"
574 echo " logs Show logs"
575 echo " cli Marzneshin command-line interface"
576 echo " install Install Marzneshin"
577 echo " update Update latest version"
578 echo " uninstall Uninstall Marzneshin"
579 echo " install-script Install Marzneshin script"
580 echo
581}
582
583case "$1" in
584 up)
585 shift; up_command "$@";;
586 down)
587 shift; down_command "$@";;
588 restart)
589 shift; restart_command "$@";;
590 status)
591 shift; status_command "$@";;
592 logs)
593 shift; logs_command "$@";;
594 cli)
595 shift; cli_command "$@";;
596 install)
597 shift; install_command "$@";;
598 update)
599 shift; update_command "$@";;
600 uninstall)
601 shift; uninstall_command "$@";;
602 install-script)
603 shift; install_marzneshin_script "$@";;
604 *)
605 usage;;
606esac