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