From 748e7a3d828b3f5e9e7477301fd0a8cdb8f4d7f1 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 16 Jul 2026 22:08:15 +0800 Subject: [PATCH 01/40] perf: update web redirect --- config_init/nginx/lb_http_server.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_init/nginx/lb_http_server.conf b/config_init/nginx/lb_http_server.conf index ef12af4..b6318b3 100644 --- a/config_init/nginx/lb_http_server.conf +++ b/config_init/nginx/lb_http_server.conf @@ -8,7 +8,7 @@ server { listen 80; # listen [::]:80; # server_name demo.jumpserver.org; # 取消注释并自行修改成你自己的域名 - return 307 https://$server_name$request_uri; + return 307 https://$host$request_uri; } server { From f6a75d3f22060ff9aa27432c2c64ab4652879de4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 16 Jul 2026 22:08:15 +0800 Subject: [PATCH 02/40] perf: update web redirect --- config_init/nginx/lb_http_server.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_init/nginx/lb_http_server.conf b/config_init/nginx/lb_http_server.conf index ef12af4..b6318b3 100644 --- a/config_init/nginx/lb_http_server.conf +++ b/config_init/nginx/lb_http_server.conf @@ -8,7 +8,7 @@ server { listen 80; # listen [::]:80; # server_name demo.jumpserver.org; # 取消注释并自行修改成你自己的域名 - return 307 https://$server_name$request_uri; + return 307 https://$host$request_uri; } server { From 93acb06ccaa07dde03d25a229590632cfcb9de80 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 16 Jul 2026 23:00:12 +0800 Subject: [PATCH 03/40] perf: update use lb --- scripts/gists/service.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index 91083ad..5aef6c9 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -173,7 +173,7 @@ function get_docker_compose_cmd_line() { fi fi - if [[ "${use_lb}" == "1" ]]; then + if [[ "${use_lb}" == "1" && -n "${https_port}" ]]; then cmd+=" -f compose/web.https.yml" fi From d552f9d9fd340656ecb43f08242994bb04ec2eed Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 16 Jul 2026 23:00:12 +0800 Subject: [PATCH 04/40] perf: update use lb --- scripts/gists/service.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index 91083ad..5aef6c9 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -173,7 +173,7 @@ function get_docker_compose_cmd_line() { fi fi - if [[ "${use_lb}" == "1" ]]; then + if [[ "${use_lb}" == "1" && -n "${https_port}" ]]; then cmd+=" -f compose/web.https.yml" fi From 81bcc2e9d3200de62c86b2f588afc6e84f46ee40 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 21 Jul 2026 16:42:47 +0800 Subject: [PATCH 05/40] perf: update config add redis --- jmsctl.sh | 2 +- scripts/gists/conf.sh | 68 +++++++------------------------------------ 2 files changed, 12 insertions(+), 58 deletions(-) diff --git a/jmsctl.sh b/jmsctl.sh index 32c1b2c..d113f87 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -32,7 +32,7 @@ function check_config_file() { if [[ ! -f "./compose/.env" ]]; then ln -s "${CONFIG_FILE}" ./compose/.env fi - gen_safe_config + gen_safe_config >/dev/null } function pre_check() { diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 2f7c8b9..992368d 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -1,15 +1,4 @@ - -function is_confirm() { - read -r confirmed - if [[ "${confirmed}" == "y" || "${confirmed}" == "Y" || ${confirmed} == "" ]]; then - return 0 - else - return 1 - fi -} - - function has_config() { key=$1 if grep "^[ \t]*${key}=" "${CONFIG_FILE}" &>/dev/null; then @@ -33,19 +22,12 @@ function get_config() { echo "${value}" } -function get_env_value() { - key=$1 - default=${2-''} - value="${!key}" - echo "${value}" -} - function get_config_or_env() { key=$1 value='' default=${2-''} - value=$(get_env_value "$key") + value="${!key}" if [[ -z "$value" && -f "${CONFIG_FILE}" ]];then value=$(get_config "$key") fi @@ -56,50 +38,25 @@ function get_config_or_env() { echo "${value}" } -CONFIG_SAFE_EXCLUDES="DB_HOST DB_PORT DB_PASSWORD REDIS_PASSWORD" - -function is_config_excluded() { - local key=$1 - local excluded - - for excluded in ${CONFIG_SAFE_EXCLUDES}; do - if [[ "${key}" == "${excluded}" ]]; then - return 0 - fi - done - return 1 -} +CONFIG_SAFE_EXCLUDES="DB_HOST DB_PORT DB_PASSWORD" function gen_safe_config() { local base_config_file=${CONFIG_FILE} local output_file=${CONFIG_SAFE_FILE} local tmp_file="${output_file}.tmp.$$" - local line key value + local excluded mkdir -p "${CONFIG_DIR}" - : >"${tmp_file}" - if [[ -f "${base_config_file}" ]]; then - while IFS= read -r line || [[ -n "${line}" ]]; do - [[ -z "${line}" || "${line}" =~ ^[[:space:]]*# ]] && continue - [[ "${line}" != *"="* ]] && continue - - key="${line%%=*}" - key="${key#"${key%%[![:space:]]*}"}" - key="${key%"${key##*[![:space:]]}"}" - is_config_excluded "${key}" && continue - - value="${line#*=}" - value="${value#"${value%%[![:space:]]*}"}" - echo "${key}=${value}" >>"${tmp_file}" - done <"${base_config_file}" - fi - - if [[ -s "${tmp_file}" ]]; then - sort -o "${tmp_file}" "${tmp_file}" + cp "${base_config_file}" "${tmp_file}" + for excluded in ${CONFIG_SAFE_EXCLUDES}; do + sed_in_place "/^[[:space:]]*${excluded}=/d" "${tmp_file}" + done + else + : >"${tmp_file}" fi - if [[ -f "${output_file}" ]] && cmp -s "${tmp_file}" <(sort "${output_file}"); then + if [[ -f "${output_file}" ]] && cmp -s "${tmp_file}" "${output_file}"; then rm -f "${tmp_file}" echo "${output_file}" return @@ -126,7 +83,6 @@ function set_config() { has=$(has_config "${key}") if [[ ${has} == "0" ]]; then echo "${key}=${value}" >>"${CONFIG_FILE}" - gen_safe_config >/dev/null return fi @@ -136,7 +92,6 @@ function set_config() { fi sed_in_place "s,^[ \t]*${key}=.*$,${key}=${value},g" "${CONFIG_FILE}" - gen_safe_config >/dev/null } function disable_config() { @@ -145,7 +100,6 @@ function disable_config() { has=$(has_config "${key}") if [[ ${has} == "1" ]]; then sed_in_place "s,^[ \t]*${key}=.*$,# ${key}=,g" "${CONFIG_FILE}" - gen_safe_config >/dev/null fi } @@ -228,7 +182,7 @@ function prepare_config() { sed_in_place "s/# ignore-warnings ARM64-COW-BUG/ignore-warnings ARM64-COW-BUG/g" "${CONFIG_DIR}/redis/redis.conf" fi - gen_safe_config + gen_safe_config >/dev/null } function ensure_core_data_symlink() { From f6f07bc1bf9618d25b967eb9b9d03f68222e080b Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 21 Jul 2026 17:55:10 +0800 Subject: [PATCH 06/40] perf: update koko ssh port --- config-example.txt | 4 ++-- scripts/1_config_jumpserver.sh | 8 ++++---- scripts/4_install_jumpserver.sh | 2 +- scripts/7_upgrade.sh | 28 ++++++++++++++++++++++++++-- scripts/config.sh | 8 ++++---- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/config-example.txt b/config-example.txt index 3b8a2b1..d21b0e5 100644 --- a/config-example.txt +++ b/config-example.txt @@ -136,8 +136,8 @@ JUMPSERVER_ENABLE_FONT_SMOOTHING=true ################################# XPack Configuration ################################# # XPack package, invalid setting in open source version # -SSH_PORT=2222 -RDP_PORT=3389 +KOKO_SSH_PORT=2222 +RAZOR_RDP_PORT=3389 XRDP_PORT=3390 MAGNUS_MYSQL_PORT=33061 MAGNUS_MARIADB_PORT=33062 diff --git a/scripts/1_config_jumpserver.sh b/scripts/1_config_jumpserver.sh index 2a2d7d8..2e45eae 100644 --- a/scripts/1_config_jumpserver.sh +++ b/scripts/1_config_jumpserver.sh @@ -213,8 +213,8 @@ function set_redis() { function set_service() { echo_yellow "\n5. $(gettext 'Configure External Access')" http_port=$(get_config HTTP_PORT) - ssh_port=$(get_config SSH_PORT) - rdp_port=$(get_config RDP_PORT) + ssh_port=$(get_config KOKO_SSH_PORT) + rdp_port=$(get_config RAZOR_RDP_PORT) use_xpack=$(get_config_or_env USE_XPACK) confirm="n" read_from_input confirm "$(gettext 'Do you need to customize the JumpServer external port')?" "y/n" "${confirm}" @@ -224,9 +224,9 @@ function set_service() { if [[ "${use_xpack}" == "1" ]]; then read_from_input ssh_port "$(gettext 'JumpServer ssh port')" "" "${ssh_port}" - set_config SSH_PORT "${ssh_port}" + set_config KOKO_SSH_PORT "${ssh_port}" read_from_input rdp_port "$(gettext 'JumpServer rdp port')" "" "${rdp_port}" - set_config RDP_PORT "${rdp_port}" + set_config RAZOR_RDP_PORT "${rdp_port}" fi fi } diff --git a/scripts/4_install_jumpserver.sh b/scripts/4_install_jumpserver.sh index c8c18f7..185a880 100644 --- a/scripts/4_install_jumpserver.sh +++ b/scripts/4_install_jumpserver.sh @@ -49,7 +49,7 @@ function post_install() { http_port=$(get_config HTTP_PORT) https_port=$(get_config HTTPS_PORT) server_name=$(get_config SERVER_NAME) - ssh_port=$(get_config SSH_PORT) + ssh_port=$(get_config KOKO_SSH_PORT) use_xpack=$(get_config_or_env USE_XPACK) echo_yellow "1. $(gettext 'You can use the following command to start, and then visit')" diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index fe1a14d..a03a117 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -37,6 +37,29 @@ function check_and_set_config() { fi } +function migrate_compat_config() { + local new_key=$1 + local old_key=$2 + local default_value=$3 + local new_value old_value + + new_value=$(get_config "${new_key}") + if [[ -n "${new_value}" ]]; then + return + fi + + old_value=$(get_config "${old_key}") + if [[ -n "${old_value}" ]]; then + set_config "${new_key}" "${old_value}" + return + fi + + if [[ -n "${default_value}" ]]; then + set_config "${new_key}" "${default_value}" + fi + +} + function upgrade_config() { if check_root; then check_docker_start @@ -70,7 +93,6 @@ function upgrade_config() { # XPACK use_xpack=$(get_config_or_env USE_XPACK) if [[ "${use_xpack}" == "1" ]]; then - check_and_set_config "RDP_PORT" "3389" check_and_set_config "XRDP_PORT" "3390" check_and_set_config "MAGNUS_MYSQL_PORT" "33061" check_and_set_config "MAGNUS_MARIADB_PORT" "33062" @@ -156,7 +178,9 @@ function migrate_data_folder() { } function migrate_config() { - prepare_config + # prepare_config + migrate_compat_config "KOKO_SSH_PORT" "SSH_PORT" "2222" + migrate_compat_config "RAZOR_RDP_PORT" "RDP_PORT" "3389" } function update_config_if_need() { diff --git a/scripts/config.sh b/scripts/config.sh index 43eaf94..b67855e 100644 --- a/scripts/config.sh +++ b/scripts/config.sh @@ -71,9 +71,9 @@ function set_port() { fi if [[ "${use_xpack}" == "1" ]]; then if [[ "${koko_enable}" != "0" ]]; then - ssh_port=$(get_config SSH_PORT) + ssh_port=$(get_config KOKO_SSH_PORT) read_from_input ssh_port "$(gettext 'Please enter SSH PORT')" "" "${ssh_port}" - set_config SSH_PORT "${ssh_port}" + set_config KOKO_SSH_PORT "${ssh_port}" fi if [[ "${magnus_enable}" != "0" ]]; then magnus_mysql_port=$(get_config MAGNUS_MYSQL_PORT) @@ -98,9 +98,9 @@ function set_port() { set_config XRDP_PORT "${xrdp_port}" fi if [[ "${razor_enable}" != "0" ]]; then - rdp_port=$(get_config RDP_PORT) + rdp_port=$(get_config RAZOR_RDP_PORT) read_from_input rdp_port "$(gettext 'Please enter RAZOR PORT')" "" "${rdp_port}" - set_config RDP_PORT "${rdp_port}" + set_config RAZOR_RDP_PORT "${rdp_port}" fi if [[ "${magnus_enable}" != "0" ]]; then magnus_oracle_port=$(get_config MAGNUS_ORACLE_PORT) From be2ca97e2bd4166ed3b88d4e1e677c716d9e76ac Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 21 Jul 2026 18:27:42 +0800 Subject: [PATCH 07/40] perf: migrate config drop old value --- scripts/7_upgrade.sh | 2 ++ scripts/gists/conf.sh | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index a03a117..362685f 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -45,12 +45,14 @@ function migrate_compat_config() { new_value=$(get_config "${new_key}") if [[ -n "${new_value}" ]]; then + remove_config "${old_key}" return fi old_value=$(get_config "${old_key}") if [[ -n "${old_value}" ]]; then set_config "${new_key}" "${old_value}" + remove_config "${old_key}" return fi diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 992368d..d035f44 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -94,6 +94,15 @@ function set_config() { sed_in_place "s,^[ \t]*${key}=.*$,${key}=${value},g" "${CONFIG_FILE}" } +function remove_config() { + key=$1 + + has=$(has_config "${key}") + if [[ ${has} == "1" ]]; then + sed_in_place "/^[ \t]*${key}=.*$/d" "${CONFIG_FILE}" + fi +} + function disable_config() { key=$1 From f2defff38aaa5c1bfa0422779c0682497916a070 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Tue, 7 Jul 2026 12:44:05 +0800 Subject: [PATCH 08/40] perf: openbao --- compose/openbao.yml | 60 ++++++++++++ config-example.txt | 33 +++++++ config_init/openbao/bootstrap.sh | 162 +++++++++++++++++++++++++++++++ config_init/openbao/server.hcl | 16 +++ jmsctl.sh | 3 + scripts/0_prepare.sh | 4 + scripts/1_config_jumpserver.sh | 1 + scripts/7_upgrade.sh | 1 + scripts/gists/conf.sh | 17 +++- scripts/gists/image.sh | 11 ++- scripts/gists/openbao.sh | 146 ++++++++++++++++++++++++++++ scripts/gists/service.sh | 5 +- scripts/utils.sh | 2 +- 13 files changed, 456 insertions(+), 5 deletions(-) create mode 100644 compose/openbao.yml create mode 100644 config_init/openbao/bootstrap.sh create mode 100644 config_init/openbao/server.hcl create mode 100644 scripts/gists/openbao.sh diff --git a/compose/openbao.yml b/compose/openbao.yml new file mode 100644 index 0000000..c440175 --- /dev/null +++ b/compose/openbao.yml @@ -0,0 +1,60 @@ +services: + core: + depends_on: + openbao-init: + condition: service_completed_successfully + + celery: + depends_on: + openbao-init: + condition: service_completed_successfully + + openbao: + image: ${OPENBAO_IMAGE:-openbao/openbao:2.6.0} + container_name: jms_openbao + hostname: openbao + # Start the image entrypoint as root so it can fix bind-mount ownership; + # the official entrypoint then launches bao via su-exec as openbao. + user: "0" + restart: always + command: server -config=/openbao/config/server.hcl + environment: + BAO_ADDR: http://127.0.0.1:8200 + VAULT_API_ADDR: ${OPENBAO_RAFT_API_ADDR:-http://openbao:8200} + VAULT_CLUSTER_ADDR: ${OPENBAO_RAFT_CLUSTER_ADDR:-http://openbao:8201} + VAULT_RAFT_NODE_ID: ${OPENBAO_RAFT_NODE_ID:-openbao} + TZ: ${TZ:-Asia/Shanghai} + volumes: + - ${CONFIG_DIR}/openbao/server.hcl:/openbao/config/server.hcl:ro + - ${VOLUME_DIR}/openbao/data:/openbao/file + ports: + - "${OPENBAO_UI_BIND:-127.0.0.1}:${OPENBAO_UI_PORT:-8200}:8200" + - "${OPENBAO_CLUSTER_BIND:-127.0.0.1}:${OPENBAO_CLUSTER_PORT:-8201}:8201" + healthcheck: + test: "bao status -address=http://127.0.0.1:8200" + interval: 10s + timeout: 5s + retries: 3 + start_period: 10s + networks: + - net + + openbao-init: + image: ${OPENBAO_IMAGE:-openbao/openbao:2.6.0} + container_name: jms_openbao_init + hostname: openbao-init + # The one-shot initializer writes root-owned 0600 unseal material. + user: "0" + restart: "no" + command: sh /openbao/bootstrap/bootstrap.sh + env_file: + - ${CONFIG_FILE} + environment: + BAO_ADDR: http://openbao:8200 + TZ: ${TZ:-Asia/Shanghai} + volumes: + - ${CONFIG_DIR}/openbao:/openbao/bootstrap + depends_on: + - openbao + networks: + - net diff --git a/config-example.txt b/config-example.txt index d21b0e5..7f03a49 100644 --- a/config-example.txt +++ b/config-example.txt @@ -162,3 +162,36 @@ USE_LB=1 # TZ=Asia/Shanghai CURRENT_VERSION= + +################################# Vault Configuration ################################# +# OpenBao runs as an independent Docker service in this installer. JumpServer connects to OpenBao Server directly. +# OpenBao 作为独立 Docker 服务部署,JumpServer 直接访问 OpenBao Server。 +# +# Disabled by default. Set to true to enable Vault storage. When the backend is +# openbao and OPENBAO_EXTERNAL=false, the installer starts the built-in service. +# 默认关闭;设为 true 后启用 Vault。当后端为 openbao 且 OPENBAO_EXTERNAL=false 时,安装器启动内置服务。 +VAULT_ENABLED=false +VAULT_BACKEND=openbao +VAULT_OPENBAO_ADDR=http://openbao:8200 +VAULT_OPENBAO_MOUNT_POINT=pam +VAULT_OPENBAO_TOKEN= +VAULT_OPENBAO_TIMEOUT=10 + +# Set to true when VAULT_OPENBAO_ADDR points to an external OpenBao cluster or HA endpoint. +# 设置为 true 时,installer 不会启动内置 OpenBao,Core 仍使用上面的 Vault 配置连接外部服务。 +OPENBAO_EXTERNAL=false + +OPENBAO_RAFT_NODE_ID=openbao +OPENBAO_RAFT_API_ADDR=http://openbao:8200 +OPENBAO_RAFT_CLUSTER_ADDR=http://openbao:8201 +OPENBAO_RAFT_BOOTSTRAP=true +# Additional Raft nodes must set OPENBAO_RAFT_BOOTSTRAP=false and receive a +# protected copy of openbao/init.json from the bootstrap node before startup. +# OPENBAO_RAFT_RETRY_JOIN=http://openbao-1:8200,http://openbao-2:8200 + +OPENBAO_UNSEAL_KEY_SHARES=5 +OPENBAO_UNSEAL_KEY_THRESHOLD=3 +OPENBAO_UI_BIND=127.0.0.1 +OPENBAO_UI_PORT=8200 +OPENBAO_CLUSTER_BIND=127.0.0.1 +OPENBAO_CLUSTER_PORT=8201 diff --git a/config_init/openbao/bootstrap.sh b/config_init/openbao/bootstrap.sh new file mode 100644 index 0000000..e3a6f36 --- /dev/null +++ b/config_init/openbao/bootstrap.sh @@ -0,0 +1,162 @@ +#!/bin/sh +set -eu + +export BAO_ADDR="${BAO_ADDR:-http://openbao:8200}" + +MOUNT_POINT="${VAULT_OPENBAO_MOUNT_POINT:-pam}" +SERVICE_TOKEN="${VAULT_OPENBAO_TOKEN:-}" +RAFT_BOOTSTRAP="${OPENBAO_RAFT_BOOTSTRAP:-true}" +UNSEAL_KEY_SHARES="${OPENBAO_UNSEAL_KEY_SHARES:-5}" +UNSEAL_KEY_THRESHOLD="${OPENBAO_UNSEAL_KEY_THRESHOLD:-3}" +INIT_FILE="/openbao/bootstrap/init.json" +POLICY_FILE="/tmp/jumpserver-policy.hcl" +SERVICE_TOKEN_FILE="/openbao/bootstrap/jumpserver-token.json" + +wait_openbao() { + i=0 + while [ "$i" -lt 60 ]; do + if bao status >/tmp/openbao-status 2>&1; then + return 0 + fi + if grep -q "Initialized" /tmp/openbao-status 2>/dev/null; then + return 0 + fi + i=$((i + 1)) + sleep 1 + done + cat /tmp/openbao-status 2>/dev/null || true + echo "OpenBao is not reachable" + exit 1 +} + +json_value() { + key="$1" + tr -d '\n ' <"${INIT_FILE}" | sed -n "s/.*\"${key}\":\"\\([^\"]*\\)\".*/\\1/p" +} + +json_array_first() { + key="$1" + tr -d '\n ' <"${INIT_FILE}" | sed -n "s/.*\"${key}\":\\[\"\\([^\"]*\\)\".*/\\1/p" +} + +json_array_values() { + key="$1" + tr -d '\n ' <"${INIT_FILE}" | sed -n "s/.*\"${key}\":\\[\\([^]]*\\)\\].*/\\1/p" | tr ',' '\n' | sed 's/^"//;s/"$//' +} + +is_true() { + case "$1" in + 1|true|True|TRUE|yes|Yes|YES) return 0 ;; + *) return 1 ;; + esac +} + +is_initialized() { + bao status 2>/dev/null | grep -q "Initialized[[:space:]]*true" +} + +is_uninitialized() { + bao status 2>/dev/null | grep -q "Initialized[[:space:]]*false" +} + +is_sealed() { + bao status 2>/dev/null | grep -q "Sealed[[:space:]]*true" +} + +wait_unsealed() { + i=0 + while [ "$i" -lt 30 ]; do + if ! is_sealed; then + return 0 + fi + i=$((i + 1)) + sleep 1 + done + return 1 +} + +unseal_openbao() { + if ! is_sealed; then + return 0 + fi + + json_array_values unseal_keys_b64 | while IFS= read -r key; do + [ -z "${key}" ] && continue + if ! is_sealed; then + break + fi + bao operator unseal "${key}" >/dev/null + done + + if ! wait_unsealed; then + echo "OpenBao is still sealed after applying unseal keys from ${INIT_FILE}." + exit 1 + fi +} + +wait_openbao + +if is_uninitialized; then + if is_true "${RAFT_BOOTSTRAP}"; then + bao operator init -key-shares="${UNSEAL_KEY_SHARES}" -key-threshold="${UNSEAL_KEY_THRESHOLD}" -format=json >"${INIT_FILE}" + chmod 600 "${INIT_FILE}" 2>/dev/null || true + else + i=0 + while [ "$i" -lt 60 ]; do + is_initialized && break + i=$((i + 1)) + sleep 1 + done + if is_uninitialized; then + echo "OpenBao is not initialized. Set OPENBAO_RAFT_BOOTSTRAP=true on the first Raft node, or wait for retry_join to finish." + exit 1 + fi + fi +fi + +if [ ! -f "${INIT_FILE}" ]; then + echo "OpenBao is initialized, but ${INIT_FILE} is missing; cannot unseal automatically." + echo "On an additional Raft node, copy init.json from the bootstrap node to this node before startup." + exit 1 +fi + +ROOT_TOKEN="$(json_value root_token)" + +if [ -z "${ROOT_TOKEN}" ] || [ -z "$(json_array_first unseal_keys_b64)" ]; then + echo "Invalid OpenBao initialization file: ${INIT_FILE}" + exit 1 +fi + +unseal_openbao + +export BAO_TOKEN="${ROOT_TOKEN}" + +if ! bao secrets list -format=json | grep -q "\"${MOUNT_POINT}/\""; then + bao secrets enable -path="${MOUNT_POINT}" -version=2 kv +fi + +bao write "${MOUNT_POINT}/config" max_versions=20 >/dev/null + +cat >"${POLICY_FILE}" </dev/null + +if [ -n "${SERVICE_TOKEN}" ]; then + if ! bao token lookup "${SERVICE_TOKEN}" >/dev/null 2>&1; then + bao token create \ + -id="${SERVICE_TOKEN}" \ + -policy=jumpserver \ + -orphan \ + -no-default-policy \ + -format=json >"${SERVICE_TOKEN_FILE}" + chmod 600 "${SERVICE_TOKEN_FILE}" 2>/dev/null || true + fi +fi diff --git a/config_init/openbao/server.hcl b/config_init/openbao/server.hcl new file mode 100644 index 0000000..39957de --- /dev/null +++ b/config_init/openbao/server.hcl @@ -0,0 +1,16 @@ +ui = true +disable_mlock = true + +storage "raft" { + path = "/openbao/file" + node_id = "openbao" +} + +listener "tcp" { + address = "0.0.0.0:8200" + cluster_address = "0.0.0.0:8201" + tls_disable = true +} + +api_addr = "http://openbao:8200" +cluster_addr = "http://openbao:8201" diff --git a/jmsctl.sh b/jmsctl.sh index d113f87..668f6cf 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -80,6 +80,9 @@ function service_to_docker_name() { EXE="" function start() { + set_openbao || return 1 + gen_safe_config >/dev/null + EXE=$(get_docker_compose_cmd_line) ${EXE} up -d base_dir="${PROJECT_DIR}" diff --git a/scripts/0_prepare.sh b/scripts/0_prepare.sh index 5d84dd3..9fd1b7e 100644 --- a/scripts/0_prepare.sh +++ b/scripts/0_prepare.sh @@ -49,6 +49,10 @@ function prepare_image_files() { fi rm -f "${IMAGE_DIR}"/* + # The offline bundle must carry optional OpenBao even when it is disabled by + # default, so it can be enabled later without registry access. + local INCLUDE_OPENBAO_IMAGE=1 + export INCLUDE_OPENBAO_IMAGE pull_images images=$(get_images) diff --git a/scripts/1_config_jumpserver.sh b/scripts/1_config_jumpserver.sh index 2e45eae..eef9187 100644 --- a/scripts/1_config_jumpserver.sh +++ b/scripts/1_config_jumpserver.sh @@ -258,6 +258,7 @@ function main() { if set_redis; then echo_done fi + set_openbao || return 1 if set_service; then echo_done fi diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index 362685f..bceb317 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -191,6 +191,7 @@ function update_config_if_need() { migrate_coco_to_koko migrate_config upgrade_config + set_openbao || exit 1 clean_file } diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index d035f44..fa8d024 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -38,7 +38,19 @@ function get_config_or_env() { echo "${value}" } -CONFIG_SAFE_EXCLUDES="DB_HOST DB_PORT DB_PASSWORD" +CONFIG_SAFE_EXCLUDES="DB_HOST DB_PORT DB_PASSWORD REDIS_PASSWORD VAULT_OPENBAO_TOKEN" + +function is_config_excluded() { + local key=$1 + local excluded + + for excluded in ${CONFIG_SAFE_EXCLUDES}; do + if [[ "${key}" == "${excluded}" ]]; then + return 0 + fi + done + return 1 +} function gen_safe_config() { local base_config_file=${CONFIG_FILE} @@ -186,6 +198,9 @@ function prepare_config() { find "${CONFIG_DIR}" -type d -exec chmod 700 {} \; find "${CONFIG_DIR}" -type f -exec chmod 600 {} \; chmod 644 "${CONFIG_DIR}/redis/redis.conf" + if [[ -f "${CONFIG_DIR}/openbao/server.hcl" ]]; then + chmod 644 "${CONFIG_DIR}/openbao/server.hcl" + fi if [[ "$(uname -m)" == "aarch64" ]]; then sed_in_place "s/# ignore-warnings ARM64-COW-BUG/ignore-warnings ARM64-COW-BUG/g" "${CONFIG_DIR}/redis/redis.conf" diff --git a/scripts/gists/image.sh b/scripts/gists/image.sh index 66f90e7..9048024 100644 --- a/scripts/gists/image.sh +++ b/scripts/gists/image.sh @@ -25,6 +25,9 @@ function get_pull_images() { if [[ "${use_xpack}" == "1" ]]; then images+=("jumpserver/ansible-executor:latest") fi + if should_include_openbao_image; then + images+=("$(get_openbao_image)") + fi echo "${images[@]}" } @@ -47,6 +50,9 @@ function get_images() { if [[ "${use_xpack}" == "1" ]]; then images+=("${namespace}/ansible-executor:latest") fi + if should_include_openbao_image; then + images+=("$(get_openbao_image)") + fi echo "${images[@]}" } @@ -86,7 +92,9 @@ function get_image_full_path() { full_image_path="${image}" if [[ -n "${DOCKER_IMAGE_PREFIX}" ]]; then - if echo "${DOCKER_IMAGE_PREFIX}" | grep -q "/";then + if [[ "${image}" == */* && $(image_has_prefix "${image}") != "1" ]]; then + full_image_path="${image}" + elif echo "${DOCKER_IMAGE_PREFIX}" | grep -q "/";then app=$(echo "$image" | awk -F'/' '{ print $NF }') full_image_path="${DOCKER_IMAGE_PREFIX}/${app}" elif [[ $(image_has_prefix "${image}") != "1" ]]; then @@ -151,4 +159,3 @@ function pull_images() { trap - SIGINT SIGTERM } - diff --git a/scripts/gists/openbao.sh b/scripts/gists/openbao.sh new file mode 100644 index 0000000..66caa9e --- /dev/null +++ b/scripts/gists/openbao.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env bash + +function is_internal_openbao_enabled() { + local vault_enabled vault_backend openbao_external + + vault_enabled=$(get_config_or_env VAULT_ENABLED) + vault_backend=$(get_config_or_env VAULT_BACKEND) + openbao_external=$(get_config_or_env OPENBAO_EXTERNAL "false") + + case "${vault_enabled}" in + 1|true|True|TRUE) ;; + *) return 1 ;; + esac + [[ "${vault_backend}" == "openbao" ]] || return 1 + case "${openbao_external}" in + 1|true|True|TRUE) return 1 ;; + esac + return 0 +} + +function get_openbao_image() { + get_config_or_env OPENBAO_IMAGE "openbao/openbao:2.6.0" +} + +function should_include_openbao_image() { + case "${INCLUDE_OPENBAO_IMAGE:-}" in + 1|true|True|TRUE) return 0 ;; + esac + is_internal_openbao_enabled +} + +function set_openbao() { + local vault_enabled vault_backend openbao_external vault_addr vault_token + + vault_enabled=$(get_config VAULT_ENABLED "false") + vault_backend=$(get_config VAULT_BACKEND "openbao") + openbao_external=$(get_config OPENBAO_EXTERNAL "false") + + set_config VAULT_ENABLED "${vault_enabled}" + if [[ "${vault_enabled}" != "1" && "${vault_enabled}" != "true" && "${vault_enabled}" != "True" && "${vault_enabled}" != "TRUE" ]]; then + return + fi + if [[ "${vault_backend}" != "openbao" ]]; then + return + fi + + vault_addr=$(get_config VAULT_OPENBAO_ADDR) + vault_token=$(get_config VAULT_OPENBAO_TOKEN) + + if [[ "${openbao_external}" == "1" || "${openbao_external}" == "true" || "${openbao_external}" == "True" || "${openbao_external}" == "TRUE" ]]; then + if [[ -z "${vault_token}" ]]; then + log_error "$(gettext 'VAULT_OPENBAO_TOKEN is required when using external OpenBao')" + return 1 + fi + if [[ -z "${vault_addr}" || "${vault_addr}" == "http://openbao:8200" || "${vault_addr}" == "https://openbao:8200" ]]; then + log_error "$(gettext 'Set VAULT_OPENBAO_ADDR to the external OpenBao address')" + return 1 + fi + else + if [[ -z "${vault_addr}" ]]; then + vault_addr="http://openbao:8200" + fi + if [[ -z "${vault_token}" ]]; then + vault_token=$(random_str 48) + set_config VAULT_OPENBAO_TOKEN "${vault_token}" + fi + fi + + set_config VAULT_BACKEND openbao + set_config VAULT_OPENBAO_ADDR "${vault_addr}" + set_config VAULT_OPENBAO_MOUNT_POINT "$(get_config VAULT_OPENBAO_MOUNT_POINT pam)" + set_config VAULT_OPENBAO_TIMEOUT "$(get_config VAULT_OPENBAO_TIMEOUT 10)" + set_config OPENBAO_EXTERNAL "${openbao_external}" + + if [[ "${openbao_external}" == "1" || "${openbao_external}" == "true" || "${openbao_external}" == "True" || "${openbao_external}" == "TRUE" ]]; then + return 0 + fi + + set_config OPENBAO_RAFT_NODE_ID "$(get_config OPENBAO_RAFT_NODE_ID openbao)" + set_config OPENBAO_RAFT_API_ADDR "$(get_config OPENBAO_RAFT_API_ADDR http://openbao:8200)" + set_config OPENBAO_RAFT_CLUSTER_ADDR "$(get_config OPENBAO_RAFT_CLUSTER_ADDR http://openbao:8201)" + set_config OPENBAO_RAFT_BOOTSTRAP "$(get_config OPENBAO_RAFT_BOOTSTRAP true)" + set_config OPENBAO_UNSEAL_KEY_SHARES "$(get_config OPENBAO_UNSEAL_KEY_SHARES 5)" + set_config OPENBAO_UNSEAL_KEY_THRESHOLD "$(get_config OPENBAO_UNSEAL_KEY_THRESHOLD 3)" + set_openbao_bootstrap_script + set_openbao_server_config +} + +function set_openbao_bootstrap_script() { + local source_file target_file + + source_file="${PROJECT_DIR}/config_init/openbao/bootstrap.sh" + target_file="${CONFIG_DIR}/openbao/bootstrap.sh" + mkdir -p "${CONFIG_DIR}/openbao" + cp -f "${source_file}" "${target_file}" + chmod 600 "${target_file}" 2>/dev/null || true +} + +function set_openbao_server_config() { + local config_file data_path node_id api_addr cluster_addr retry_join addr + + config_file="${CONFIG_DIR}/openbao/server.hcl" + data_path="/openbao/file" + node_id=$(get_config OPENBAO_RAFT_NODE_ID openbao) + api_addr=$(get_config OPENBAO_RAFT_API_ADDR http://openbao:8200) + cluster_addr=$(get_config OPENBAO_RAFT_CLUSTER_ADDR http://openbao:8201) + retry_join=$(get_config OPENBAO_RAFT_RETRY_JOIN) + + mkdir -p "${CONFIG_DIR}/openbao" + + cat >"${config_file}" <>"${config_file}" <>"${config_file}" </dev/null || true +} diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index 5aef6c9..e54fe02 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -140,6 +140,9 @@ function get_docker_compose_services() { [[ "${use_es}" == "1" ]] && services+=" es" [[ "${use_minio}" == "1" ]] && services+=" minio" [[ "${use_loki}" == "1" ]] && services+=" loki" + if is_internal_openbao_enabled; then + services+=" openbao" + fi echo "${services}" } @@ -348,4 +351,4 @@ function installation_log() { version=$(get_current_version) url="https://community.fit2cloud.com/installation-analytics?product=${product}&type=${install_type}&version=${version}" curl --connect-timeout 5 -m 10 -k $url &>/dev/null -} \ No newline at end of file +} diff --git a/scripts/utils.sh b/scripts/utils.sh index 357492d..19ddb54 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -6,8 +6,8 @@ BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" . "${BASE_DIR}/const.sh" . "${BASE_DIR}/gists/common.sh" . "${BASE_DIR}/gists/conf.sh" +. "${BASE_DIR}/gists/openbao.sh" . "${BASE_DIR}/gists/image.sh" . "${BASE_DIR}/gists/service.sh" namespace=${NAMESPACE:-jumpserver} - From 857ed7cca8c9e92f31e668ddf8a4301a2c1cb434 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 21 Jul 2026 16:42:47 +0800 Subject: [PATCH 09/40] perf: update config add redis --- jmsctl.sh | 2 +- scripts/gists/conf.sh | 68 +++++++------------------------------------ 2 files changed, 12 insertions(+), 58 deletions(-) diff --git a/jmsctl.sh b/jmsctl.sh index 32c1b2c..d113f87 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -32,7 +32,7 @@ function check_config_file() { if [[ ! -f "./compose/.env" ]]; then ln -s "${CONFIG_FILE}" ./compose/.env fi - gen_safe_config + gen_safe_config >/dev/null } function pre_check() { diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 2f7c8b9..992368d 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -1,15 +1,4 @@ - -function is_confirm() { - read -r confirmed - if [[ "${confirmed}" == "y" || "${confirmed}" == "Y" || ${confirmed} == "" ]]; then - return 0 - else - return 1 - fi -} - - function has_config() { key=$1 if grep "^[ \t]*${key}=" "${CONFIG_FILE}" &>/dev/null; then @@ -33,19 +22,12 @@ function get_config() { echo "${value}" } -function get_env_value() { - key=$1 - default=${2-''} - value="${!key}" - echo "${value}" -} - function get_config_or_env() { key=$1 value='' default=${2-''} - value=$(get_env_value "$key") + value="${!key}" if [[ -z "$value" && -f "${CONFIG_FILE}" ]];then value=$(get_config "$key") fi @@ -56,50 +38,25 @@ function get_config_or_env() { echo "${value}" } -CONFIG_SAFE_EXCLUDES="DB_HOST DB_PORT DB_PASSWORD REDIS_PASSWORD" - -function is_config_excluded() { - local key=$1 - local excluded - - for excluded in ${CONFIG_SAFE_EXCLUDES}; do - if [[ "${key}" == "${excluded}" ]]; then - return 0 - fi - done - return 1 -} +CONFIG_SAFE_EXCLUDES="DB_HOST DB_PORT DB_PASSWORD" function gen_safe_config() { local base_config_file=${CONFIG_FILE} local output_file=${CONFIG_SAFE_FILE} local tmp_file="${output_file}.tmp.$$" - local line key value + local excluded mkdir -p "${CONFIG_DIR}" - : >"${tmp_file}" - if [[ -f "${base_config_file}" ]]; then - while IFS= read -r line || [[ -n "${line}" ]]; do - [[ -z "${line}" || "${line}" =~ ^[[:space:]]*# ]] && continue - [[ "${line}" != *"="* ]] && continue - - key="${line%%=*}" - key="${key#"${key%%[![:space:]]*}"}" - key="${key%"${key##*[![:space:]]}"}" - is_config_excluded "${key}" && continue - - value="${line#*=}" - value="${value#"${value%%[![:space:]]*}"}" - echo "${key}=${value}" >>"${tmp_file}" - done <"${base_config_file}" - fi - - if [[ -s "${tmp_file}" ]]; then - sort -o "${tmp_file}" "${tmp_file}" + cp "${base_config_file}" "${tmp_file}" + for excluded in ${CONFIG_SAFE_EXCLUDES}; do + sed_in_place "/^[[:space:]]*${excluded}=/d" "${tmp_file}" + done + else + : >"${tmp_file}" fi - if [[ -f "${output_file}" ]] && cmp -s "${tmp_file}" <(sort "${output_file}"); then + if [[ -f "${output_file}" ]] && cmp -s "${tmp_file}" "${output_file}"; then rm -f "${tmp_file}" echo "${output_file}" return @@ -126,7 +83,6 @@ function set_config() { has=$(has_config "${key}") if [[ ${has} == "0" ]]; then echo "${key}=${value}" >>"${CONFIG_FILE}" - gen_safe_config >/dev/null return fi @@ -136,7 +92,6 @@ function set_config() { fi sed_in_place "s,^[ \t]*${key}=.*$,${key}=${value},g" "${CONFIG_FILE}" - gen_safe_config >/dev/null } function disable_config() { @@ -145,7 +100,6 @@ function disable_config() { has=$(has_config "${key}") if [[ ${has} == "1" ]]; then sed_in_place "s,^[ \t]*${key}=.*$,# ${key}=,g" "${CONFIG_FILE}" - gen_safe_config >/dev/null fi } @@ -228,7 +182,7 @@ function prepare_config() { sed_in_place "s/# ignore-warnings ARM64-COW-BUG/ignore-warnings ARM64-COW-BUG/g" "${CONFIG_DIR}/redis/redis.conf" fi - gen_safe_config + gen_safe_config >/dev/null } function ensure_core_data_symlink() { From 7b57f45b599c3d40f6d5172b554cbe0e18c4b397 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 21 Jul 2026 17:55:10 +0800 Subject: [PATCH 10/40] perf: update koko ssh port --- config-example.txt | 4 ++-- scripts/1_config_jumpserver.sh | 8 ++++---- scripts/4_install_jumpserver.sh | 2 +- scripts/7_upgrade.sh | 28 ++++++++++++++++++++++++++-- scripts/config.sh | 8 ++++---- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/config-example.txt b/config-example.txt index 3b8a2b1..d21b0e5 100644 --- a/config-example.txt +++ b/config-example.txt @@ -136,8 +136,8 @@ JUMPSERVER_ENABLE_FONT_SMOOTHING=true ################################# XPack Configuration ################################# # XPack package, invalid setting in open source version # -SSH_PORT=2222 -RDP_PORT=3389 +KOKO_SSH_PORT=2222 +RAZOR_RDP_PORT=3389 XRDP_PORT=3390 MAGNUS_MYSQL_PORT=33061 MAGNUS_MARIADB_PORT=33062 diff --git a/scripts/1_config_jumpserver.sh b/scripts/1_config_jumpserver.sh index 2a2d7d8..2e45eae 100644 --- a/scripts/1_config_jumpserver.sh +++ b/scripts/1_config_jumpserver.sh @@ -213,8 +213,8 @@ function set_redis() { function set_service() { echo_yellow "\n5. $(gettext 'Configure External Access')" http_port=$(get_config HTTP_PORT) - ssh_port=$(get_config SSH_PORT) - rdp_port=$(get_config RDP_PORT) + ssh_port=$(get_config KOKO_SSH_PORT) + rdp_port=$(get_config RAZOR_RDP_PORT) use_xpack=$(get_config_or_env USE_XPACK) confirm="n" read_from_input confirm "$(gettext 'Do you need to customize the JumpServer external port')?" "y/n" "${confirm}" @@ -224,9 +224,9 @@ function set_service() { if [[ "${use_xpack}" == "1" ]]; then read_from_input ssh_port "$(gettext 'JumpServer ssh port')" "" "${ssh_port}" - set_config SSH_PORT "${ssh_port}" + set_config KOKO_SSH_PORT "${ssh_port}" read_from_input rdp_port "$(gettext 'JumpServer rdp port')" "" "${rdp_port}" - set_config RDP_PORT "${rdp_port}" + set_config RAZOR_RDP_PORT "${rdp_port}" fi fi } diff --git a/scripts/4_install_jumpserver.sh b/scripts/4_install_jumpserver.sh index c8c18f7..185a880 100644 --- a/scripts/4_install_jumpserver.sh +++ b/scripts/4_install_jumpserver.sh @@ -49,7 +49,7 @@ function post_install() { http_port=$(get_config HTTP_PORT) https_port=$(get_config HTTPS_PORT) server_name=$(get_config SERVER_NAME) - ssh_port=$(get_config SSH_PORT) + ssh_port=$(get_config KOKO_SSH_PORT) use_xpack=$(get_config_or_env USE_XPACK) echo_yellow "1. $(gettext 'You can use the following command to start, and then visit')" diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index fe1a14d..a03a117 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -37,6 +37,29 @@ function check_and_set_config() { fi } +function migrate_compat_config() { + local new_key=$1 + local old_key=$2 + local default_value=$3 + local new_value old_value + + new_value=$(get_config "${new_key}") + if [[ -n "${new_value}" ]]; then + return + fi + + old_value=$(get_config "${old_key}") + if [[ -n "${old_value}" ]]; then + set_config "${new_key}" "${old_value}" + return + fi + + if [[ -n "${default_value}" ]]; then + set_config "${new_key}" "${default_value}" + fi + +} + function upgrade_config() { if check_root; then check_docker_start @@ -70,7 +93,6 @@ function upgrade_config() { # XPACK use_xpack=$(get_config_or_env USE_XPACK) if [[ "${use_xpack}" == "1" ]]; then - check_and_set_config "RDP_PORT" "3389" check_and_set_config "XRDP_PORT" "3390" check_and_set_config "MAGNUS_MYSQL_PORT" "33061" check_and_set_config "MAGNUS_MARIADB_PORT" "33062" @@ -156,7 +178,9 @@ function migrate_data_folder() { } function migrate_config() { - prepare_config + # prepare_config + migrate_compat_config "KOKO_SSH_PORT" "SSH_PORT" "2222" + migrate_compat_config "RAZOR_RDP_PORT" "RDP_PORT" "3389" } function update_config_if_need() { diff --git a/scripts/config.sh b/scripts/config.sh index 43eaf94..b67855e 100644 --- a/scripts/config.sh +++ b/scripts/config.sh @@ -71,9 +71,9 @@ function set_port() { fi if [[ "${use_xpack}" == "1" ]]; then if [[ "${koko_enable}" != "0" ]]; then - ssh_port=$(get_config SSH_PORT) + ssh_port=$(get_config KOKO_SSH_PORT) read_from_input ssh_port "$(gettext 'Please enter SSH PORT')" "" "${ssh_port}" - set_config SSH_PORT "${ssh_port}" + set_config KOKO_SSH_PORT "${ssh_port}" fi if [[ "${magnus_enable}" != "0" ]]; then magnus_mysql_port=$(get_config MAGNUS_MYSQL_PORT) @@ -98,9 +98,9 @@ function set_port() { set_config XRDP_PORT "${xrdp_port}" fi if [[ "${razor_enable}" != "0" ]]; then - rdp_port=$(get_config RDP_PORT) + rdp_port=$(get_config RAZOR_RDP_PORT) read_from_input rdp_port "$(gettext 'Please enter RAZOR PORT')" "" "${rdp_port}" - set_config RDP_PORT "${rdp_port}" + set_config RAZOR_RDP_PORT "${rdp_port}" fi if [[ "${magnus_enable}" != "0" ]]; then magnus_oracle_port=$(get_config MAGNUS_ORACLE_PORT) From fd89cad4e804dce962f119c92fd1730faa410679 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 21 Jul 2026 18:27:42 +0800 Subject: [PATCH 11/40] perf: migrate config drop old value --- scripts/7_upgrade.sh | 2 ++ scripts/gists/conf.sh | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index a03a117..362685f 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -45,12 +45,14 @@ function migrate_compat_config() { new_value=$(get_config "${new_key}") if [[ -n "${new_value}" ]]; then + remove_config "${old_key}" return fi old_value=$(get_config "${old_key}") if [[ -n "${old_value}" ]]; then set_config "${new_key}" "${old_value}" + remove_config "${old_key}" return fi diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 992368d..d035f44 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -94,6 +94,15 @@ function set_config() { sed_in_place "s,^[ \t]*${key}=.*$,${key}=${value},g" "${CONFIG_FILE}" } +function remove_config() { + key=$1 + + has=$(has_config "${key}") + if [[ ${has} == "1" ]]; then + sed_in_place "/^[ \t]*${key}=.*$/d" "${CONFIG_FILE}" + fi +} + function disable_config() { key=$1 From 51dbb90fa0cc6f72cbc429cfdae0fb84f2966d60 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Fri, 24 Jul 2026 18:31:52 +0800 Subject: [PATCH 12/40] perf: kotl --- README.md | 18 ++++ config-example.txt | 5 + jmsctl.sh | 39 +++++--- scripts/0_prepare.sh | 6 +- scripts/4_install_jumpserver.sh | 12 +++ scripts/7_upgrade.sh | 9 ++ scripts/8_uninstall.sh | 3 +- scripts/gists/common.sh | 25 +++++ scripts/gists/image.sh | 6 ++ scripts/gists/kotl.sh | 166 ++++++++++++++++++++++++++++++++ scripts/utils.sh | 1 + 11 files changed, 271 insertions(+), 19 deletions(-) create mode 100644 scripts/gists/kotl.sh diff --git a/README.md b/README.md index 68d170a..7d18095 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,24 @@ $ ./jmsctl.sh tail ``` +## KOTL + +KOTL 作为宿主机 systemd 服务安装,不加入 Docker Compose。启用时请在 +`static.env` 或 `/opt/jumpserver/config/config.txt` 中设置: + +```bash +KOTL_ENABLED=1 +``` + +安装器会拉取 `${NAMESPACE:-jumpserver}/kotl:${VERSION}` artifact 镜像,从 +`/dist` 提取并执行 KOTL 自带的 `scripts/install.sh` 或 `scripts/upgrade.sh`。 +离线包也会自动包含该镜像。服务跟随 `jmsctl.sh start/stop/restart/status` +管理,日志可通过 `./jmsctl.sh tail kotl` 查看。启用时还会自动为 Core 配置 +`JDMC_ENABLED=1` 和 `/opt/jumpserver/data/unshare/kotl.sock`。 + +当前 KOTL 的宿主机路径固定使用 `/data/jumpserver`,因此启用时 +`VOLUME_DIR` 也必须保持为 `/data/jumpserver`。 + ## 配置文件说明 配置文件将会放在 /opt/jumpserver/config 中 diff --git a/config-example.txt b/config-example.txt index 7f03a49..54b95e5 100644 --- a/config-example.txt +++ b/config-example.txt @@ -129,6 +129,11 @@ DOMAINS= # CHEN_ENABLED=0 # WEB_ENABLED=0 +# KOTL is the host management console. It is distributed as an artifact image, +# then installed as a systemd service on the host instead of running in Compose. +# When enabled, the installer configures JDMC_ENABLED and JDMC_SOCK_PATH for Core. +KOTL_ENABLED=0 + # Lion enables font smoothing to optimize the experience # JUMPSERVER_ENABLE_FONT_SMOOTHING=true diff --git a/jmsctl.sh b/jmsctl.sh index 668f6cf..d6b8673 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -85,38 +85,35 @@ function start() { EXE=$(get_docker_compose_cmd_line) ${EXE} up -d - base_dir="${PROJECT_DIR}" - to="/opt/current/installer" - if [[ "$base_dir" == "$to" ]]; then - return - fi - mkdir -p /opt/current - echo "$base_dir" > /var/run/installer.lock - if [[ ! -L "$to" || "$(readlink -f "$to")" != "$base_dir" ]]; then - rm -f "$to" - ln -s "$base_dir" "$to" - fi - if [[ -e "$base_dir" && ! -e "$to" ]]; then - ln -s "$base_dir" "$to" - fi + ensure_current_installer_link || return 1 + start_kotl } function stop() { - if [[ "${target}" == "ignore_db" ]]; then + if [[ "${target}" == "kotl" ]]; then + stop_kotl + elif [[ "${target}" == "ignore_db" ]]; then + stop_kotl || return 1 cmd=$(get_docker_compose_cmd_line "ignore_db") ${cmd} down -v elif [[ -n "${target}" ]]; then ${EXE} stop "${target}" && ${EXE} rm -f "${target}" else + stop_kotl || return 1 ${EXE} down -v fi } function close() { if [[ -n "${target}" ]]; then + if [[ "${target}" == "kotl" ]]; then + stop_kotl + return + fi ${EXE} stop "${target}" return fi + stop_kotl || return 1 services=$(get_docker_compose_services ignore_db) for i in ${services}; do ${EXE} stop "${i}" @@ -132,6 +129,10 @@ function pull() { } function restart() { + if [[ "${target}" == "kotl" ]]; then + restart_kotl + return + fi stop echo -e "\n" @@ -246,10 +247,14 @@ function main() { ;; status) ${EXE} ps + status_kotl ;; down) if [[ -z "${target}" ]]; then + stop_kotl || exit 1 ${EXE} down -v + elif [[ "${target}" == "kotl" ]]; then + stop_kotl else ${EXE} stop "${target}" && ${EXE} rm -f "${target}" fi @@ -282,7 +287,9 @@ function main() { echo "${EXE}" ;; tail) - if [[ -z "${target}" ]]; then + if [[ "${target}" == "kotl" ]]; then + tail_kotl + elif [[ -z "${target}" ]]; then ${EXE} logs --tail 100 -f else docker_name=$(service_to_docker_name "${target}") diff --git a/scripts/0_prepare.sh b/scripts/0_prepare.sh index 9fd1b7e..91dde1a 100644 --- a/scripts/0_prepare.sh +++ b/scripts/0_prepare.sh @@ -49,10 +49,12 @@ function prepare_image_files() { fi rm -f "${IMAGE_DIR}"/* - # The offline bundle must carry optional OpenBao even when it is disabled by - # default, so it can be enabled later without registry access. + # The offline bundle must carry optional service images even when they are + # disabled by default, so they can be enabled later without registry access. local INCLUDE_OPENBAO_IMAGE=1 + local INCLUDE_KOTL_IMAGE=1 export INCLUDE_OPENBAO_IMAGE + export INCLUDE_KOTL_IMAGE pull_images images=$(get_images) diff --git a/scripts/4_install_jumpserver.sh b/scripts/4_install_jumpserver.sh index 185a880..0d2fcbb 100644 --- a/scripts/4_install_jumpserver.sh +++ b/scripts/4_install_jumpserver.sh @@ -99,6 +99,10 @@ function main() { if ! bash "${BASE_DIR}/1_config_jumpserver.sh"; then exit 1 fi + if ! configure_kotl; then + log_error "Failed to configure KOTL" + exit 1 + fi echo_green "\n>>> $(gettext 'Loading Docker Image')" if ! bash "${BASE_DIR}/3_load_images.sh"; then @@ -112,6 +116,14 @@ function main() { fi ensure_core_data_symlink || log_warn "Failed to prepare host core data symlink, continue installation" + ensure_current_installer_link || { + log_error "Failed to update /opt/current/installer" + exit 1 + } + install_kotl || { + log_error "Failed to install KOTL" + exit 1 + } installation_log "install" post_install diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index bceb317..8978d8c 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -192,6 +192,7 @@ function update_config_if_need() { migrate_config upgrade_config set_openbao || exit 1 + configure_kotl || exit 1 clean_file } @@ -371,6 +372,14 @@ function main() { upgrade_docker upgrade_compose ensure_core_data_symlink || log_warn "Failed to prepare host core data symlink, continue upgrade" + ensure_current_installer_link || { + log_error "Failed to update /opt/current/installer" + exit 1 + } + upgrade_kotl || { + log_error "Failed to upgrade KOTL" + exit 1 + } installation_log "upgrade" diff --git a/scripts/8_uninstall.sh b/scripts/8_uninstall.sh index 6c431db..6b0c916 100644 --- a/scripts/8_uninstall.sh +++ b/scripts/8_uninstall.sh @@ -98,6 +98,7 @@ function remove_jumpserver() { function main() { echo_yellow "\n>>> $(gettext 'Uninstall JumpServer')" stop_services + disable_kotl || log_warn "Failed to disable KOTL" installation_log "uninstall" remove_jmsctl remove_jumpserver @@ -105,4 +106,4 @@ function main() { remove_docker } -main \ No newline at end of file +main diff --git a/scripts/gists/common.sh b/scripts/gists/common.sh index f41759c..85bb234 100644 --- a/scripts/gists/common.sh +++ b/scripts/gists/common.sh @@ -179,3 +179,28 @@ function get_host_ip() { echo "${default_ip}" fi } + +function ensure_current_installer_link() { + local source_dir="${PROJECT_DIR}" + local current_dir="/opt/current" + local target="${current_dir}/installer" + + if [[ "${source_dir}" == "${target}" ]]; then + return 0 + fi + + mkdir -p "${current_dir}" || return 1 + echo "${source_dir}" > /var/run/installer.lock || return 1 + + if [[ -L "${target}" ]]; then + if [[ "$(readlink -f "${target}")" == "${source_dir}" ]]; then + return 0 + fi + rm -f "${target}" || return 1 + elif [[ -e "${target}" ]]; then + log_error "${target} exists and is not a symbolic link" + return 1 + fi + + ln -s "${source_dir}" "${target}" +} diff --git a/scripts/gists/image.sh b/scripts/gists/image.sh index 9048024..10eb18f 100644 --- a/scripts/gists/image.sh +++ b/scripts/gists/image.sh @@ -28,6 +28,9 @@ function get_pull_images() { if should_include_openbao_image; then images+=("$(get_openbao_image)") fi + if should_include_kotl_image; then + images+=("jumpserver/kotl:${VERSION}") + fi echo "${images[@]}" } @@ -53,6 +56,9 @@ function get_images() { if should_include_openbao_image; then images+=("$(get_openbao_image)") fi + if should_include_kotl_image; then + images+=("$(get_kotl_image)") + fi echo "${images[@]}" } diff --git a/scripts/gists/kotl.sh b/scripts/gists/kotl.sh new file mode 100644 index 0000000..eedf33e --- /dev/null +++ b/scripts/gists/kotl.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env bash + +KOTL_SERVICE_NAME=${KOTL_SERVICE_NAME:-kotl.service} +KOTL_CORE_SOCKET_PATH=${KOTL_CORE_SOCKET_PATH:-/opt/jumpserver/data/unshare/kotl.sock} + +function is_kotl_enabled() { + [[ "$(get_config_or_env KOTL_ENABLED 0)" == "1" ]] +} + +function should_include_kotl_image() { + case "${INCLUDE_KOTL_IMAGE:-}" in + 1|true|True|TRUE) return 0 ;; + esac + is_kotl_enabled +} + +function get_kotl_image() { + echo "${NAMESPACE:-jumpserver}/kotl:${VERSION}" +} + +function check_kotl_volume_dir() { + local volume_dir + + volume_dir=$(get_config_or_env VOLUME_DIR /data/jumpserver) + volume_dir=${volume_dir%/} + if [[ "${volume_dir}" != "/data/jumpserver" ]]; then + log_error "KOTL currently requires VOLUME_DIR=/data/jumpserver (got: ${volume_dir})" + return 1 + fi +} + +function configure_kotl() { + is_kotl_enabled || return 0 + check_kotl_volume_dir || return 1 + set_config JDMC_ENABLED 1 + set_config JDMC_SOCK_PATH "${KOTL_CORE_SOCKET_PATH}" + gen_safe_config >/dev/null +} + +function check_kotl_runtime() { + if ! command -v systemctl &>/dev/null; then + log_error "KOTL requires systemd, but systemctl was not found" + return 1 + fi +} + +function check_kotl_installed() { + [[ -x /opt/kotl/kotl && -f "/etc/systemd/system/${KOTL_SERVICE_NAME}" ]] +} + +function run_kotl_package_action() { + local action=$1 + local image + + image=$(get_kotl_image) + if ! docker image inspect "${image}" &>/dev/null; then + log_error "KOTL artifact image not found: ${image}" + return 1 + fi + + ( + local temp_dir container_id script_path + + if ! temp_dir=$(mktemp -d -t kotl-installer.XXXXXX); then + log_error "Failed to create a temporary directory for KOTL" + exit 1 + fi + container_id="" + function cleanup_kotl_package() { + if [[ -n "${container_id}" ]]; then + docker rm -f "${container_id}" &>/dev/null || true + fi + if [[ -n "${temp_dir}" && -d "${temp_dir}" ]]; then + rm -rf "${temp_dir}" + fi + } + trap cleanup_kotl_package EXIT + + if ! container_id=$(docker create "${image}" /__kotl_artifact_placeholder__); then + log_error "Failed to create a temporary container from ${image}" + exit 1 + fi + if ! docker cp "${container_id}:/dist/." "${temp_dir}/"; then + log_error "Failed to extract /dist from ${image}" + exit 1 + fi + + script_path="${temp_dir}/scripts/${action}.sh" + if [[ ! -f "${script_path}" ]]; then + log_error "KOTL package script not found: scripts/${action}.sh" + exit 1 + fi + + chmod +x "${script_path}" || exit 1 + cd "${temp_dir}" || exit 1 + bash "./scripts/${action}.sh" + ) +} + +function install_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + configure_kotl || return 1 + + if check_kotl_installed; then + echo_check "KOTL is already installed" + return 0 + fi + + echo_yellow "\n>>> Installing KOTL" + run_kotl_package_action install +} + +function upgrade_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + configure_kotl || return 1 + + echo_yellow "\n>>> Upgrading KOTL" + if check_kotl_installed; then + run_kotl_package_action upgrade + else + run_kotl_package_action install + fi +} + +function start_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + if ! check_kotl_installed; then + log_error "KOTL is enabled but not installed; run ./jmsctl.sh install first" + return 1 + fi + systemctl start "${KOTL_SERVICE_NAME}" +} + +function stop_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + systemctl stop "${KOTL_SERVICE_NAME}" +} + +function restart_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + systemctl restart "${KOTL_SERVICE_NAME}" +} + +function status_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + systemctl status "${KOTL_SERVICE_NAME}" --no-pager || true +} + +function tail_kotl() { + is_kotl_enabled || return 0 + check_kotl_runtime || return 1 + journalctl -u "${KOTL_SERVICE_NAME}" -n 100 -f -o cat +} + +function disable_kotl() { + check_kotl_installed || return 0 + check_kotl_runtime || return 1 + systemctl stop "${KOTL_SERVICE_NAME}" || true + systemctl disable "${KOTL_SERVICE_NAME}" +} diff --git a/scripts/utils.sh b/scripts/utils.sh index 19ddb54..d2e6769 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -7,6 +7,7 @@ BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" . "${BASE_DIR}/gists/common.sh" . "${BASE_DIR}/gists/conf.sh" . "${BASE_DIR}/gists/openbao.sh" +. "${BASE_DIR}/gists/kotl.sh" . "${BASE_DIR}/gists/image.sh" . "${BASE_DIR}/gists/service.sh" From 3ea61a6d4cea119cff9a8317ebd21e67ab36e281 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 27 Jul 2026 15:18:48 +0800 Subject: [PATCH 13/40] perf: openbao image --- compose/openbao.yml | 4 ++-- scripts/gists/openbao.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compose/openbao.yml b/compose/openbao.yml index c440175..b70507b 100644 --- a/compose/openbao.yml +++ b/compose/openbao.yml @@ -10,7 +10,7 @@ services: condition: service_completed_successfully openbao: - image: ${OPENBAO_IMAGE:-openbao/openbao:2.6.0} + image: openbao:2.6.0 container_name: jms_openbao hostname: openbao # Start the image entrypoint as root so it can fix bind-mount ownership; @@ -40,7 +40,7 @@ services: - net openbao-init: - image: ${OPENBAO_IMAGE:-openbao/openbao:2.6.0} + image: openbao:2.6.0 container_name: jms_openbao_init hostname: openbao-init # The one-shot initializer writes root-owned 0600 unseal material. diff --git a/scripts/gists/openbao.sh b/scripts/gists/openbao.sh index 66caa9e..63616aa 100644 --- a/scripts/gists/openbao.sh +++ b/scripts/gists/openbao.sh @@ -19,7 +19,7 @@ function is_internal_openbao_enabled() { } function get_openbao_image() { - get_config_or_env OPENBAO_IMAGE "openbao/openbao:2.6.0" + get_config_or_env OPENBAO_IMAGE "openbao:2.6.0" } function should_include_openbao_image() { From 53524c5a830286355535369dbe0ee6f057145a1a Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 27 Jul 2026 15:35:53 +0800 Subject: [PATCH 14/40] perf: registry open --- scripts/gists/image.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/gists/image.sh b/scripts/gists/image.sh index 10eb18f..2bd7035 100644 --- a/scripts/gists/image.sh +++ b/scripts/gists/image.sh @@ -71,6 +71,18 @@ function image_has_prefix() { fi } +function image_uses_mirror_prefix() { + image=$1 + + if [[ "${image}" != */* || $(image_has_prefix "${image}") == "1" ]]; then + echo "1" + elif [[ "${image}" == "openbao/openbao" || "${image}" == openbao/openbao:* || "${image}" == openbao/openbao@* ]]; then + echo "1" + else + echo "0" + fi +} + function check_image_exists() { image=$1 if docker image inspect -f '{{ .Id }}' "$image" &>/dev/null; then @@ -98,7 +110,7 @@ function get_image_full_path() { full_image_path="${image}" if [[ -n "${DOCKER_IMAGE_PREFIX}" ]]; then - if [[ "${image}" == */* && $(image_has_prefix "${image}") != "1" ]]; then + if [[ $(image_uses_mirror_prefix "${image}") != "1" ]]; then full_image_path="${image}" elif echo "${DOCKER_IMAGE_PREFIX}" | grep -q "/";then app=$(echo "$image" | awk -F'/' '{ print $NF }') From a91d1fe0bf6aba568fda2df454decc3a0e3bf3d0 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 27 Jul 2026 17:39:28 +0800 Subject: [PATCH 15/40] perf: add kotl web --- compose/web.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compose/web.yml b/compose/web.yml index 8276d3a..d8f507d 100644 --- a/compose/web.yml +++ b/compose/web.yml @@ -24,6 +24,7 @@ services: KAEL_ENABLED: ${KAEL_ENABLED:-0} RAZOR_ENABLED: ${RAZOR_ENABLED:-1} FACELIVE_ENABLED: ${FACELIVE_ENABLED:-0} + KOTL_ENABLED: ${KOTL_ENABLED:-0} BASIC_AUTH_PASSWORD: ${BASIC_AUTH_PASSWORD:-} volumes: - ${VOLUME_DIR}/core/data:/opt/jumpserver/data @@ -36,4 +37,6 @@ services: retries: 3 start_period: 90s networks: - - net \ No newline at end of file + - net + extra_hosts: + - "host.docker.internal:host-gateway" From 75b0da6463d93696dfc132cb90246b175911dbfe Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Tue, 28 Jul 2026 18:12:50 +0800 Subject: [PATCH 16/40] feat: fit new magnus port --- compose/magnus.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compose/magnus.yml b/compose/magnus.yml index c0cc1b5..58b48ec 100644 --- a/compose/magnus.yml +++ b/compose/magnus.yml @@ -9,13 +9,7 @@ services: env_file: - ${CONFIG_SAFE_FILE} ports: - - ${MAGNUS_MYSQL_PORT:-33061}:33061 - - ${MAGNUS_MARIADB_PORT:-33062}:33062 - - ${MAGNUS_REDIS_PORT:-63790}:63790 - - ${MAGNUS_POSTGRESQL_PORT:-54320}:54320 - - ${MAGNUS_SQLSERVER_PORT:-14330}:14330 - - ${MAGNUS_ORACLE_PORT:-15210}:15210 - - ${MAGNUS_MONGODB_PORT:-27018}:27018 + - ${MAGNUS_PORT:-5525}:5525 volumes: - ${CONFIG_DIR}/certs:/opt/magnus/data/certs - ${VOLUME_DIR}/magnus/data:/opt/magnus/data From e9925da484736f406397fb4447c2c315b8329dfb Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 29 Jul 2026 10:21:10 +0800 Subject: [PATCH 17/40] perf: add kotl enable --- README.md | 2 +- scripts/gists/kotl.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d18095..2ef952b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ KOTL_ENABLED=1 `/dist` 提取并执行 KOTL 自带的 `scripts/install.sh` 或 `scripts/upgrade.sh`。 离线包也会自动包含该镜像。服务跟随 `jmsctl.sh start/stop/restart/status` 管理,日志可通过 `./jmsctl.sh tail kotl` 查看。启用时还会自动为 Core 配置 -`JDMC_ENABLED=1` 和 `/opt/jumpserver/data/unshare/kotl.sock`。 +`KOTL_ENABLED=1`、`JDMC_ENABLED=1` 和 `/opt/jumpserver/data/unshare/kotl.sock`。 当前 KOTL 的宿主机路径固定使用 `/data/jumpserver`,因此启用时 `VOLUME_DIR` 也必须保持为 `/data/jumpserver`。 diff --git a/scripts/gists/kotl.sh b/scripts/gists/kotl.sh index eedf33e..190219c 100644 --- a/scripts/gists/kotl.sh +++ b/scripts/gists/kotl.sh @@ -32,6 +32,7 @@ function check_kotl_volume_dir() { function configure_kotl() { is_kotl_enabled || return 0 check_kotl_volume_dir || return 1 + set_config KOTL_ENABLED 1 set_config JDMC_ENABLED 1 set_config JDMC_SOCK_PATH "${KOTL_CORE_SOCKET_PATH}" gen_safe_config >/dev/null From 4b77b5a06720cfa9b6e55b942d983828820649fb Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 29 Jul 2026 10:30:40 +0800 Subject: [PATCH 18/40] fix: some upgrade issue --- scripts/7_upgrade.sh | 4 +++- scripts/gists/conf.sh | 9 +++++++-- scripts/gists/service.sh | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index 8978d8c..8aec8d2 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -180,7 +180,7 @@ function migrate_data_folder() { } function migrate_config() { - # prepare_config + prepare_jmsctl migrate_compat_config "KOKO_SSH_PORT" "SSH_PORT" "2222" migrate_compat_config "RAZOR_RDP_PORT" "RDP_PORT" "3389" } @@ -316,6 +316,8 @@ function upgrade_compose() { } function main() { + cd "${PROJECT_DIR}" || exit 1 + confirm="y" to_version="${VERSION}" if [[ -n "${target}" ]]; then diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index fa8d024..01b473b 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -136,14 +136,19 @@ function get_config_enabled() { } -function prepare_config() { - cd "${PROJECT_DIR}" || exit 1 +function prepare_jmsctl() { if check_root; then echo -e "#!/usr/bin/env bash\n#" > /usr/bin/jmsctl echo -e "cd ${PROJECT_DIR}" >> /usr/bin/jmsctl echo -e './jmsctl.sh $@' >> /usr/bin/jmsctl chmod 755 /usr/bin/jmsctl fi +} + + +function prepare_config() { + cd "${PROJECT_DIR}" || exit 1 + prepare_jmsctl echo_yellow "1. $(gettext 'Check Configuration File')" echo "$(gettext 'Path to Configuration file'): ${CONFIG_DIR}" diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index e54fe02..7a99c54 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -176,7 +176,7 @@ function get_docker_compose_cmd_line() { fi fi - if [[ "${use_lb}" == "1" && -n "${https_port}" ]]; then + if [[ "${use_lb}" == "1" || -n "${https_port}" ]]; then cmd+=" -f compose/web.https.yml" fi From 467580eab70872bd1a501fc3691ca603ddb2e5ad Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 29 Jul 2026 13:54:57 +0800 Subject: [PATCH 19/40] perf: change mysql5.7 to 8 --- compose/mysql.yml | 2 +- scripts/7_upgrade.sh | 4 ++-- scripts/gists/service.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compose/mysql.yml b/compose/mysql.yml index 5f5b0cd..dedbd95 100644 --- a/compose/mysql.yml +++ b/compose/mysql.yml @@ -1,6 +1,6 @@ services: mysql: - image: mysql:5.7-debian + image: mysql:8.0 container_name: jms_mysql restart: always command: --character-set-server=utf8 diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index 8aec8d2..202e4b2 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -83,8 +83,8 @@ function upgrade_config() { if docker image inspect -f '{{.Id}}' jumpserver/mariadb:10.6 &>/dev/null; then docker tag jumpserver/mariadb:10.6 mariadb:10.6 fi - if docker image inspect -f '{{.Id}}' jumpserver/mysql:5.7 &>/dev/null; then - docker tag jumpserver/mysql:5.7 mysql:5.7-debian + if docker image inspect -f '{{.Id}}' jumpserver/mysql:8.0 &>/dev/null; then + docker tag jumpserver/mysql:8.0 mysql:8.0 fi check_and_set_config "CURRENT_VERSION" "${VERSION}" check_and_set_config "CLIENT_MAX_BODY_SIZE" "4096m" diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index 7a99c54..e86e97a 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -84,7 +84,7 @@ function get_db_info() { case "${info_type}" in "image") if [[ "${mysql_data_exists}" == "1" ]]; then - echo "mysql:5.7-debian" + echo "mysql:8.0" elif [[ "${mariadb_data_exists}" == "1" ]]; then echo "mariadb:10.6" elif [[ "${postgres_data_exists}" == "1" ]]; then From 493c21cbd5f10f1b6f037fc33092093150b4f4ed Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 29 Jul 2026 14:13:00 +0800 Subject: [PATCH 20/40] perf: update mysql --- jmsctl.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jmsctl.sh b/jmsctl.sh index d6b8673..9cc1830 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -283,6 +283,10 @@ function main() { pull_images) pull_images ;; + pull_mysql) + docker pull registry.cn-beijing.aliyuncs.com/jumpservice/mysql:8.0 + docker tag registry.cn-beijing.aliyuncs.com/jumpservice/mysql:8.0 mysql:8.0 + ;; cmd) echo "${EXE}" ;; From b2be7eff12f9bbb74020195f462c1003fe8b6d55 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 29 Jul 2026 17:47:29 +0800 Subject: [PATCH 21/40] perf: set https port then use https --- scripts/gists/service.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index e86e97a..e27b72d 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -176,7 +176,7 @@ function get_docker_compose_cmd_line() { fi fi - if [[ "${use_lb}" == "1" || -n "${https_port}" ]]; then + if [[ -n "${https_port}" ]]; then cmd+=" -f compose/web.https.yml" fi From 0ded769d48d8abd718761b9d24a478994668b838 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Tue, 4 Aug 2026 18:22:15 +0800 Subject: [PATCH 22/40] perf: skip-kotl --- jmsctl.sh | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/jmsctl.sh b/jmsctl.sh index 9cc1830..c1f1997 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -11,6 +11,16 @@ cd "${PROJECT_DIR}" || exit 1 action=${1-} target=${2-} args=("$@") +skip_kotl=false + +if [[ "${target}" == "--skip-kotl" ]]; then + case "${action}" in + start|stop|restart|close|status|down) + skip_kotl=true + target="" + ;; + esac +fi function check_config_file() { if [[ ! -f "${CONFIG_FILE}" ]]; then @@ -52,10 +62,10 @@ function usage() { echo echo "Management Commands: " echo " config $(gettext 'Configuration Tools')" - echo " start $(gettext 'Start JumpServer')" - echo " stop $(gettext 'Stop JumpServer')" - echo " restart $(gettext 'Restart JumpServer')" - echo " status $(gettext 'Check JumpServer')" + echo " start [--skip-kotl] $(gettext 'Start JumpServer')" + echo " stop [--skip-kotl] $(gettext 'Stop JumpServer')" + echo " restart [--skip-kotl] $(gettext 'Restart JumpServer')" + echo " status [--skip-kotl] $(gettext 'Check JumpServer')" echo " down $(gettext 'Offline JumpServer')" echo " uninstall $(gettext 'Uninstall JumpServer')" echo @@ -79,6 +89,10 @@ function service_to_docker_name() { EXE="" +function should_manage_kotl() { + [[ "${skip_kotl}" != "true" ]] +} + function start() { set_openbao || return 1 gen_safe_config >/dev/null @@ -86,20 +100,26 @@ function start() { ${EXE} up -d ensure_current_installer_link || return 1 - start_kotl + if should_manage_kotl; then + start_kotl + fi } function stop() { if [[ "${target}" == "kotl" ]]; then stop_kotl elif [[ "${target}" == "ignore_db" ]]; then - stop_kotl || return 1 + if should_manage_kotl; then + stop_kotl || return 1 + fi cmd=$(get_docker_compose_cmd_line "ignore_db") ${cmd} down -v elif [[ -n "${target}" ]]; then ${EXE} stop "${target}" && ${EXE} rm -f "${target}" else - stop_kotl || return 1 + if should_manage_kotl; then + stop_kotl || return 1 + fi ${EXE} down -v fi } @@ -113,7 +133,9 @@ function close() { ${EXE} stop "${target}" return fi - stop_kotl || return 1 + if should_manage_kotl; then + stop_kotl || return 1 + fi services=$(get_docker_compose_services ignore_db) for i in ${services}; do ${EXE} stop "${i}" @@ -247,11 +269,15 @@ function main() { ;; status) ${EXE} ps - status_kotl + if should_manage_kotl; then + status_kotl + fi ;; down) if [[ -z "${target}" ]]; then - stop_kotl || exit 1 + if should_manage_kotl; then + stop_kotl || exit 1 + fi ${EXE} down -v elif [[ "${target}" == "kotl" ]]; then stop_kotl From 0abdcddd62fec8b24005a928b79109b1c7956732 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 5 Aug 2026 10:44:47 +0800 Subject: [PATCH 23/40] perf: KOTL_ENABLED 1 --- compose/web.yml | 2 +- config-example.txt | 2 +- scripts/gists/kotl.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compose/web.yml b/compose/web.yml index d8f507d..42fff6e 100644 --- a/compose/web.yml +++ b/compose/web.yml @@ -24,7 +24,7 @@ services: KAEL_ENABLED: ${KAEL_ENABLED:-0} RAZOR_ENABLED: ${RAZOR_ENABLED:-1} FACELIVE_ENABLED: ${FACELIVE_ENABLED:-0} - KOTL_ENABLED: ${KOTL_ENABLED:-0} + KOTL_ENABLED: ${KOTL_ENABLED:-1} BASIC_AUTH_PASSWORD: ${BASIC_AUTH_PASSWORD:-} volumes: - ${VOLUME_DIR}/core/data:/opt/jumpserver/data diff --git a/config-example.txt b/config-example.txt index 54b95e5..f4a59f7 100644 --- a/config-example.txt +++ b/config-example.txt @@ -132,7 +132,7 @@ DOMAINS= # KOTL is the host management console. It is distributed as an artifact image, # then installed as a systemd service on the host instead of running in Compose. # When enabled, the installer configures JDMC_ENABLED and JDMC_SOCK_PATH for Core. -KOTL_ENABLED=0 +KOTL_ENABLED=1 # Lion enables font smoothing to optimize the experience # diff --git a/scripts/gists/kotl.sh b/scripts/gists/kotl.sh index 190219c..1c04214 100644 --- a/scripts/gists/kotl.sh +++ b/scripts/gists/kotl.sh @@ -4,7 +4,7 @@ KOTL_SERVICE_NAME=${KOTL_SERVICE_NAME:-kotl.service} KOTL_CORE_SOCKET_PATH=${KOTL_CORE_SOCKET_PATH:-/opt/jumpserver/data/unshare/kotl.sock} function is_kotl_enabled() { - [[ "$(get_config_or_env KOTL_ENABLED 0)" == "1" ]] + [[ "$(get_config_or_env KOTL_ENABLED 1)" == "1" ]] } function should_include_kotl_image() { From 37632cee9ccb8034544ffc41bdf371f94cdd22ae Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 5 Aug 2026 23:30:54 +0800 Subject: [PATCH 24/40] feat: restrict KOTL to Enterprise Edition --- README.md | 9 ++++--- compose/web.yml | 2 +- config-example.txt | 15 ++++-------- locale/en/LC_MESSAGES/jumpserver-installer.po | 4 +++ .../zh_CN/LC_MESSAGES/jumpserver-installer.mo | Bin 13998 -> 14069 bytes .../zh_CN/LC_MESSAGES/jumpserver-installer.po | 4 +++ .../LC_MESSAGES/jumpserver-installer.mo | Bin 13781 -> 13849 bytes .../LC_MESSAGES/jumpserver-installer.po | 4 +++ scripts/0_prepare.sh | 13 +++++++--- scripts/7_upgrade.sh | 7 +----- scripts/config.sh | 23 +++--------------- scripts/gists/kotl.sh | 8 +++++- 12 files changed, 43 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 2ef952b..1e66533 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,14 @@ $ ./jmsctl.sh tail ``` -## KOTL +## KOTL(企业版) -KOTL 作为宿主机 systemd 服务安装,不加入 Docker Compose。启用时请在 -`static.env` 或 `/opt/jumpserver/config/config.txt` 中设置: +KOTL 是企业版组件,需要在 `/opt/jumpserver/config/config.txt` 中设置 +`USE_XPACK=1`。它作为宿主机 systemd 服务安装,不加入 Docker Compose;企业版中 +默认启用,如需关闭可设置: ```bash -KOTL_ENABLED=1 +KOTL_ENABLED=0 ``` 安装器会拉取 `${NAMESPACE:-jumpserver}/kotl:${VERSION}` artifact 镜像,从 diff --git a/compose/web.yml b/compose/web.yml index 42fff6e..d8f507d 100644 --- a/compose/web.yml +++ b/compose/web.yml @@ -24,7 +24,7 @@ services: KAEL_ENABLED: ${KAEL_ENABLED:-0} RAZOR_ENABLED: ${RAZOR_ENABLED:-1} FACELIVE_ENABLED: ${FACELIVE_ENABLED:-0} - KOTL_ENABLED: ${KOTL_ENABLED:-1} + KOTL_ENABLED: ${KOTL_ENABLED:-0} BASIC_AUTH_PASSWORD: ${BASIC_AUTH_PASSWORD:-} volumes: - ${VOLUME_DIR}/core/data:/opt/jumpserver/data diff --git a/config-example.txt b/config-example.txt index f4a59f7..f64149d 100644 --- a/config-example.txt +++ b/config-example.txt @@ -129,10 +129,10 @@ DOMAINS= # CHEN_ENABLED=0 # WEB_ENABLED=0 -# KOTL is the host management console. It is distributed as an artifact image, -# then installed as a systemd service on the host instead of running in Compose. -# When enabled, the installer configures JDMC_ENABLED and JDMC_SOCK_PATH for Core. -KOTL_ENABLED=1 +# KOTL is an Enterprise Edition host management console. It is distributed as +# an artifact image, then installed as a systemd service on the host instead of +# running in Compose. It requires USE_XPACK=1 and can be disabled with: +# KOTL_ENABLED=0 # Lion enables font smoothing to optimize the experience # @@ -144,12 +144,7 @@ JUMPSERVER_ENABLE_FONT_SMOOTHING=true KOKO_SSH_PORT=2222 RAZOR_RDP_PORT=3389 XRDP_PORT=3390 -MAGNUS_MYSQL_PORT=33061 -MAGNUS_MARIADB_PORT=33062 -MAGNUS_REDIS_PORT=63790 -MAGNUS_POSTGRESQL_PORT=54320 -MAGNUS_SQLSERVER_PORT=14330 -MAGNUS_ORACLE_PORT=15210 +MAGNUS_PORT=5525 #XRDP_ENABLED=1 diff --git a/locale/en/LC_MESSAGES/jumpserver-installer.po b/locale/en/LC_MESSAGES/jumpserver-installer.po index 55c115a..a173674 100644 --- a/locale/en/LC_MESSAGES/jumpserver-installer.po +++ b/locale/en/LC_MESSAGES/jumpserver-installer.po @@ -519,6 +519,10 @@ msgstr "" msgid "Please enter SSH PORT" msgstr "" +#: scripts/config.sh:80 +msgid "Please enter MAGNUS PORT" +msgstr "" + #: scripts/config.sh:80 msgid "Please enter MAGNUS MYSQL PORT" msgstr "" diff --git a/locale/zh_CN/LC_MESSAGES/jumpserver-installer.mo b/locale/zh_CN/LC_MESSAGES/jumpserver-installer.mo index 7948f16fe3112a226a5b1734e40e0420dc87abae..cacd48e844b84b6a1530649a40ef2fa0b9152260 100644 GIT binary patch delta 3365 zcmX}tdr*}{7{~E7C4_ST1&IWa1Kt2H2#APfXv&m%0kx7$(ojQ9O3X`w`l@6~Bq^`p zT~yQ>$JC;Rrcu*Bn8}*VNoTy|6itoVJx8TUo9z2LXKRP&e0JZY ze^8n0MjAArRHQ5Ov~ADD4BGYRD21n~TB1DkVKHiAm8jG=U>`gYL;f|gs~nJbtl{*o0VG+oF^~3GWK~QpPQ*sr zZbMxk%mQnTyYZvFFxWZ)HK2K@0aqcnn76xd!h}QoQa?p#$Yh@D^MNnLak}DJ^wXot?!`vkEe6>lWomM9WQaHXiZn4mZA~)GoSLK5&wXCU^^Om zkPlfUlY?6Ge9S}#HQ**p!Ou`@e+zx+W7-<<2vnw?w{2%J6^*tt zr~&+Kk4G~qb(D%c!{nj{I+Y)iYASFo-oLDa}G{wnEfqE5R%*M}0SrVn;lNnotXBfM;7RB-K=()H5N6XKB)VKp*CSY`ZI@) zE-0s>FW?5$hhw+B;4td^Dcin)dcaSp_xDeGK7qzW+F7Xc>#TJ+iuPVq%C8}FHJNMx zElFWA`BzF8ae#AX0}jNGP;bGH_QD{xw9Y4?Qu+jHCNu2u3ebj1stFB8# z_N~c5^)nguwm7NeUn8#P0QZm3}9wW$8i zVF9+<^XdHp_m4tlcnWGsW;;~0xyn%^twD8s05!r>sF7bp4WP~HWn-wFgnB!MSjVCE zN-=tIJLcj$wtXG-;M=GSIl=s=(F}a32WO%>9*aYxzi5k?6`%z1C2K5QO zfeGkI548KD+IiMls3ly3B+nc|P3)5YJnMg(ie?s_5mbmn7hF9(JTd3c0iGWM3g4O0$gULQph+K9$59M1dL<4Tk;X zA7ukRLwJY@L?xk89KbYMYfyt!85zL5gjzD*LVwBU_bH-`DEA*>y4rL~k7k-ij38FI zH$tOQN~kR&$m{=Qy{#=oC0}K?+uzeCWL=^P8=|Jr9*LaywTR~+m zG1Ff&Zl*Unmti%Wc++CW0vdI_PT9eE$Inpo}@ zg~g2COKm8jl1I!TULoEhwiC078AK4VjVL5G6DsvY4)GeXv*~!)HLrUlHpZ<=^EAC1 Qd!>t;l-9keDy>)Wzo8UQkN^Mx delta 3337 zcmX}ueN0zX9LMp4kHGK8gFJ{zA`qZriU>H-LJW-=n1V~qS(#?|^s|zD0K#9IijR=q zNFz*58=Fni{KK4^Sy?L!N4c~)r#<+vl|3#)Ys223dyn1u{k_gP_ug~Q`JQtx-VC$` zf|p{tH5!h6#63iAcVjMNX*fR|pG6qc8$ZVs{0>KAmq=rDNxpSF_N6`(tivijju?V}ycrz@g@dIk2!ji{NoU>2UR z?Z2Wj=O+ysP(P$A^N_92#1YijV^AqPMj;4QLi>z*WelW=CK0PuU#eM+68Hb@} zFd3DpC8)Kmx9#ttmhvm)R`VC?{zy8P8L0LG)Kbm}QqU4qBmc~9el*hKs0V$E8fgcz zIwqQvTI&qV!D*<0ZoTTpLBD=I_hQTxyQLqQpcPWE1>JglW& zh3=Z7Zt&BKHdz*GlNDedmZ82Ebr^~cYC_GZ0k+_1JcT8A2YX-%on~stlN!Cr~!4N?u(;yck`i}In?O9E=-V^G&m!$Mqu>hJ(g!K3zk z=zZS(iKq-`qn2bWYHyVVDQKkgP#xEzMz|9-@^?`KXtVxky^VT1qSz=h4YgPD(T_`U zECy};1Jr}RL}lm_Y68Iy3VLuje{uAnbkq`zu}(+c7*lEMji~qiu&uYF*7OFl-%J=g zSeeQ~t@%`B^~_4!z8AF=pP>86_=SRI>SrOeG1u2jD4Nzhdj1 z)}(B2=?ah}nR%!QZAabLiki?F)ZZWTI|a==bcC0pB-De3qi%Q@mC}W%>sDYd+=>yn z+qNG>UH7p)-;Pn#f3WBO#5vSM*{KV05su*b<{SmBNm#D8CaI{5|v4+s0 z)aiK3!)!$jN=K20``C^Oy>7d;yI$qZSgj*vZIM+>4QIx!b?twFLv-VlwKgn z=l{nRTiS+7zK-3_1HOS_bza2;oq%sZ%6e)WY>O68$6^oncZYM(mk@lF@`J=ILYuNH zv6d(%^u^Q>>ftV3tu5;f%_Q`Ot*~t~v6_gq^=`PwmZzfjrj7-~({9N)MgI7~n<=j( z_7Ss*iG+@M9`06rgz`dXwLdoO6-sPeQ|avTC-z@N>3L!&(LhWhqKPrYF6SHnknCqE z-947r!ZIu&99w?_(}-2Xb|*U`F=ZX4;e@vJazcl8WEWyJ@uCxmNSL^n(r7}*1Y$n1 sl&B|~hzepZ(Vcjmm_fWo=x8MJiI<7yBW)4a{YTpRU5z`^o|WG7Ke+ftSpWb4 diff --git a/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po b/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po index 0ee7773..5a5720e 100644 --- a/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po +++ b/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po @@ -522,6 +522,10 @@ msgstr "请输入 HTTPS 服务端口" msgid "Please enter SSH PORT" msgstr "请输入 KOKO SSH 服务端口" +#: scripts/config.sh:80 +msgid "Please enter MAGNUS PORT" +msgstr "请输入 MAGNUS 服务端口" + #: scripts/config.sh:80 msgid "Please enter MAGNUS MYSQL PORT" msgstr "请输入 MAGNUS MYSQL 服务端口" diff --git a/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.mo b/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.mo index 8b9b4c4d780f73267f3a7e1370b932431d3d1b24..b95f85772912dfea277d7072e729cf56ea5d3984 100644 GIT binary patch delta 3294 zcmX}tXKa;K9LMof>80ylDjk+mq_0ifr!Wp!%aW|(b^Xp5tS&>NGt@@grNzL5JN=#{_bmJhlpN8rq7rwI53tU($Ro1Pv8fbfuG}3cnx(+YB$eJOr@NM@i-p2#Z+MdF2H`c z7qhVq3ypEiO)^PT4B)9AScq|0g?hm}d>ogf?%Rm!=pM|(lc)|}#-4Z=lQFq`Y!VXNs5Dv!gP*eUd_QxQ@SGgRY#6_r)H(?&`xAotm zX6`nsLl3O|nU;LY6{wkOL}wJ4V`Mbq-;jGvByTOkRMZq!<5*mXTB4(<4zwYwXRaWF zGk>9$CL)E-VsF%d#$tHNF^h6NGA7fS!u%_9(pG$p>OhC}9+py$rd2J$WURnhwtND0 ze>-Yzf5z}0um-49hq6%}E=4YxImn-BNM-)j!xnqt1TqM79%jk4x zYgmb@Uxix27SwZ}ST7=vnj5I4>q29i`hKW(Cpi47hx1V{+JI`H6qu>d2u zSsfgXIXDTm#w#(1t*E7JN6pN2TmBo>;T}wbj_uQ^>rT1N%s{R6GE@iF+WOtr*un$mE%a*o14S9Ev_#*GNa8PC*rFX4azybObd6XOPq5n5$&gP>~t*den+~;1p_e z{es$DH*h%qgZe(?(@HdsL5-*!)xioJjkP!tk6~B5k2>BDQO{-5NR);!luRTQqfnc1 z46wYJ_t9p`4uqkR)1 zqYuS(9E;ugPO2l%p^Uq++N-8wMeW+s+LiPA3RKs_%5Ph6Ay{HVQVkPSOVbt@dP*ZyW zwG@|8OZg|NgAoJ0_okvcHq0TT9#2HQXpyzSx*c^+Tdk*XB;{|=k3Qy6dnN%@u0S<7 z3pF##QSWU=4d?)>qo+|b?|g4Fw~>=!qWRCG2Xm4AXo_ulA?i!E4mEXqF^K0-FTR58 zFZ00G2U#aQUxXUqd<^17)X0w@tLm7uWc0${Q4K^7@xEYvP&baV z7>^~W=ceIoT#SqH0&1y77I-td3==4CLCwfMjHi8b#$Gs&8d(R9^gpPW$)mD6nF_cf(@>$df+c6n` zKs9g!wPg1(0#_4BL}%JcriqwhE7TdbMYxmi;qycsF_mp$UMHjUqK7$XeG}D7rEwl+ z38oXArf{0f?=<2iVpX`t`{&f1Jbep)D++O~+ZLOcGmqRW1k>|>+G2CdPzPUWpZhR2 zE2hyam^JR8xb%#Tls4HKO_`Dwxijr@YvNLzofM0RYC@;03$dOkBZ>*7Xkt5|m3xg) z(gDgPbbwY6N>xN1(M<(XB(Xo7^FG4b2}%oy&EcGJyZDoH-XOn{I7G}Mo*|UxdV~-6 zv*Z`LMgGK?ZRGNaIqpngT^&i!1L{b0% delta 3274 zcmX}teN5F=9LMoPqH?(xL@!rVR4!T|m=AIA3gpAZG)XNG zZWxf3X`)+Oh4ip#4?11hTDsJnGX`6=R^}|1f3&66`}6x9`;G5?opXLq=X}pOKiVq4 zUm5Bd6xm`p_7TGseU0gr(fn|<#uzgg+b|hFz{z+Hb%`g|H6DjjPr?D1ja*_1F%#$E zJ-8FcU?=7p6Ec@6#M6+-T|;mpda)4ofH@e46{zdhpgOu8@5T;P2fx8#_#+1J7W&Z7 z&ALCxk2;uvBe4hryx**#z_q3h({UFj;W1o>KOlc5Z=h=#R#9Jqd3YW*!h}J_jKw0< z2&-`%?!zoRgQGCgZ_H>+#Yw#16j9KLI!wd^I3B-1rTiMEU>w6&{eB#Q<*1QY;{
iWu|4%#I&Y34?=0d?QM*dL?lU8IH*M?s4)fJ~1` zLp?YjHL_wXh~R;!k(?%<8c7c-V|}Q2a5yTHDX5NTqP{BywtX&Y8&{yFb_b5*{pKiz zDfla@BV+hZ>H!a-9$0K$U|nuqhw9K4b+g)cq&z`HQHITt$5sZrbzF^hWE? zjG&+wWm^kS`?M7Gg7sK}P4@iH*6Wy0`)yRp^SDVFYeX&56R3>-j{KQ^EDU`S$D`i6 zU<~=!+||&a3tCVq{R}mdi>Q%YL!~T&r)oE3psrhjx^5G)9?fplb3R1vmTuI*{zCqo zg}^MDbQT1CHZ#-7zec!*25plas2;zEdhyqoi`}RPjbP8s#&p#A^{D$BP^oOIbtyW#!rFijaNPm)VK-{c{ATNE+hpeHK6xb1_7j^>w$^xzRp6;RS7a!Q;WL3!}=v^ z0KcG89mNXNNQ3BP1T}yesQVV9GPo6;|Nl)Cbm1Y4!DG$|<{ounuRVVi2T<4lP`w}y z7hwvn!0o6hx`E2vxJ-8n3Q!p-N8Mj-+v_nUL_<4;C-4Lg#H2}X>M~FrDnYeBg<8d{ zaS-l7b?|+R#!pch_zIP&Ud%!tKmBkTsw0KAz6?Vi8dlkc8dMKM7{Er<3l5^@>I}=k>Es(YpYRg12@P1sLYKMbEw^BHpn9oenv0WG%^ADKIcD)& zMpO~&oEG<=lCneJoNq)fZVZ1H?N3`w={bTl{C{k>r3Tc7*RdxY<4yH!bt`5=ILDim zyoK6JwnaJ9vE0S^eJ#Avn-FTEJe7Ey(5~u3Y$ghbJVHm5i!*aC*s^wHI-w1;#*ga@gy;w&{5&yEXA3WmxUko`8}^vVttxt z!&SaS&(rprmT;5LAJHB@=o_0+Y1_m~TV9Pbh+VecirVb!iNFZViQpt&WTAVe3R0hBcH-5;u&Hm@j9`DSVZ(Cb`$f6FrlNF$R_HDwywP~UB0g6 N!|LO^yc1&k{|5w|Ir0Di diff --git a/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po b/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po index d80d144..5948a52 100644 --- a/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po +++ b/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po @@ -523,6 +523,10 @@ msgstr "請輸入 HTTPS 服務埠" msgid "Please enter SSH PORT" msgstr "請輸入 KOKO SSH 服務埠" +#: scripts/config.sh:80 +msgid "Please enter MAGNUS PORT" +msgstr "請輸入 MAGNUS 服務埠" + #: scripts/config.sh:80 msgid "Please enter MAGNUS MYSQL PORT" msgstr "請輸入 MAGNUS MYSQL 服務埠" diff --git a/scripts/0_prepare.sh b/scripts/0_prepare.sh index 91dde1a..11119b0 100644 --- a/scripts/0_prepare.sh +++ b/scripts/0_prepare.sh @@ -49,12 +49,17 @@ function prepare_image_files() { fi rm -f "${IMAGE_DIR}"/* - # The offline bundle must carry optional service images even when they are - # disabled by default, so they can be enabled later without registry access. + # The offline bundle must carry optional OpenBao even when it is disabled by + # default, so it can be enabled later without registry access. local INCLUDE_OPENBAO_IMAGE=1 - local INCLUDE_KOTL_IMAGE=1 export INCLUDE_OPENBAO_IMAGE - export INCLUDE_KOTL_IMAGE + + # KOTL is an Enterprise Edition component. Include it in the offline bundle + # only when building an XPack deployment. + if is_enterprise_edition; then + local INCLUDE_KOTL_IMAGE=1 + export INCLUDE_KOTL_IMAGE + fi pull_images images=$(get_images) diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index 202e4b2..c93b0e1 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -96,12 +96,7 @@ function upgrade_config() { use_xpack=$(get_config_or_env USE_XPACK) if [[ "${use_xpack}" == "1" ]]; then check_and_set_config "XRDP_PORT" "3390" - check_and_set_config "MAGNUS_MYSQL_PORT" "33061" - check_and_set_config "MAGNUS_MARIADB_PORT" "33062" - check_and_set_config "MAGNUS_REDIS_PORT" "63790" - check_and_set_config "MAGNUS_POSTGRESQL_PORT" "54320" - check_and_set_config "MAGNUS_SQLSERVER_PORT" "14330" - check_and_set_config "MAGNUS_ORACLE_PORT" "15210" + check_and_set_config "MAGNUS_PORT" "5525" fi } diff --git a/scripts/config.sh b/scripts/config.sh index b67855e..2773fbd 100644 --- a/scripts/config.sh +++ b/scripts/config.sh @@ -76,21 +76,9 @@ function set_port() { set_config KOKO_SSH_PORT "${ssh_port}" fi if [[ "${magnus_enable}" != "0" ]]; then - magnus_mysql_port=$(get_config MAGNUS_MYSQL_PORT) - read_from_input magnus_mysql_port "$(gettext 'Please enter MAGNUS MYSQL PORT')" "" "${magnus_mysql_port}" - set_config MAGNUS_MYSQL_PORT "${magnus_mysql_port}" - magnus_mariadb_port=$(get_config MAGNUS_MARIADB_PORT) - read_from_input magnus_mariadb_port "$(gettext 'Please enter MAGNUS MARIADB PORT')" "" "${magnus_mariadb_port}" - set_config MAGNUS_MARIADB_PORT "${magnus_mariadb_port}" - magnus_redis_port=$(get_config MAGNUS_REDIS_PORT) - read_from_input magnus_redis_port "$(gettext 'Please enter MAGNUS REDIS PORT')" "" "${magnus_redis_port}" - set_config MAGNUS_REDIS_PORT "${magnus_redis_port}" - magnus_postgresql_port=$(get_config MAGNUS_POSTGRESQL_PORT) - read_from_input magnus_postgresql_port "$(gettext 'Please enter MAGNUS POSTGRESQL PORT')" "" "${magnus_postgresql_port}" - set_config MAGNUS_POSTGRESQL_PORT "${magnus_postgresql_port}" - magnus_sqlserver_port=$(get_config MAGNUS_SQLSERVER_PORT) - read_from_input magnus_sqlserver_port "$(gettext 'Please enter MAGNUS SQLSERVER PORT')" "" "${magnus_sqlserver_port}" - set_config MAGNUS_SQLSERVER_PORT "${magnus_sqlserver_port}" + magnus_port=$(get_config MAGNUS_PORT) + read_from_input magnus_port "$(gettext 'Please enter MAGNUS PORT')" "" "${magnus_port}" + set_config MAGNUS_PORT "${magnus_port}" fi if [[ "${xrdp_enable}" != "0" ]]; then xrdp_port=$(get_config XRDP_PORT) @@ -102,11 +90,6 @@ function set_port() { read_from_input rdp_port "$(gettext 'Please enter RAZOR PORT')" "" "${rdp_port}" set_config RAZOR_RDP_PORT "${rdp_port}" fi - if [[ "${magnus_enable}" != "0" ]]; then - magnus_oracle_port=$(get_config MAGNUS_ORACLE_PORT) - read_from_input magnus_oracle_port "$(gettext 'Please enter MAGNUS ORACLE PORT')" "" "${magnus_oracle_port}" - set_config MAGNUS_ORACLE_PORT "${magnus_oracle_port}" - fi if [[ "${nec_enable}" != "0" ]]; then nec_vnc_port=$(get_config NEC_VNC_PORT) read_from_input nec_port "$(gettext 'Please enter NEC VNC PORT')" "" "${nec_vnc_port}" diff --git a/scripts/gists/kotl.sh b/scripts/gists/kotl.sh index 1c04214..67ee85d 100644 --- a/scripts/gists/kotl.sh +++ b/scripts/gists/kotl.sh @@ -3,11 +3,17 @@ KOTL_SERVICE_NAME=${KOTL_SERVICE_NAME:-kotl.service} KOTL_CORE_SOCKET_PATH=${KOTL_CORE_SOCKET_PATH:-/opt/jumpserver/data/unshare/kotl.sock} +function is_enterprise_edition() { + [[ "$(get_config_or_env USE_XPACK 0)" == "1" ]] +} + function is_kotl_enabled() { - [[ "$(get_config_or_env KOTL_ENABLED 1)" == "1" ]] + is_enterprise_edition && [[ "$(get_config_or_env KOTL_ENABLED 1)" == "1" ]] } function should_include_kotl_image() { + is_enterprise_edition || return 1 + case "${INCLUDE_KOTL_IMAGE:-}" in 1|true|True|TRUE) return 0 ;; esac From c5d9aa85aa6e265c3cf7a406a7a417c78a559e3c Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 6 Aug 2026 15:35:27 +0800 Subject: [PATCH 25/40] perf: update db backup and restore --- jmsctl.sh | 4 + scripts/5_db_backup.sh | 175 ++++++++++++++++++++++------------------ scripts/6_db_restore.sh | 147 +++++++++++++++++++-------------- 3 files changed, 188 insertions(+), 138 deletions(-) diff --git a/jmsctl.sh b/jmsctl.sh index c1f1997..30741e8 100755 --- a/jmsctl.sh +++ b/jmsctl.sh @@ -72,6 +72,7 @@ function usage() { echo "More Commands: " echo " load_image $(gettext 'Loading docker image')" echo " backup_db $(gettext 'Backup database')" + echo " backup_no_audit $(gettext 'Backup database without audit data')" echo " backup_audit $(gettext 'Backup audits tables')" echo " restore_db [file] $(gettext 'Data recovery through database backup file')" echo " raw $(gettext 'Execute the original docker compose command')" @@ -297,6 +298,9 @@ function main() { backup_db) bash "${SCRIPT_DIR}/5_db_backup.sh" ;; + backup_no_audit) + bash "${SCRIPT_DIR}/5_db_backup.sh" "no_audit" + ;; backup_audit) bash "${SCRIPT_DIR}/5_db_backup.sh" "audit" ;; diff --git a/scripts/5_db_backup.sh b/scripts/5_db_backup.sh index f6abb88..d971fd8 100644 --- a/scripts/5_db_backup.sh +++ b/scripts/5_db_backup.sh @@ -27,11 +27,6 @@ AUDITS_TABLES=( terminal_command ) -FULL_IGNORE_TABLES=( - audits_activitylog - terminal_command -) - SHARED_BACKUP_TABLES=( users_user ) @@ -42,8 +37,11 @@ if [[ $# -gt 0 ]]; then audit) MODE="audit" ;; + no_audit) + MODE="no_audit" + ;; *) - log_error "Usage: $0 [audit]" + log_error "Usage: $0 [audit|no_audit]" exit 1 ;; esac @@ -78,85 +76,106 @@ function cleanup_db_env() { fi } -function backup_main_db() { +function backup_main_db_mysql() { local table - case "${DB_ENGINE}" in - mysql) - DB_FILE="${BACKUP_DIR}/${DB_NAME}-${CURRENT_VERSION}-$(date +%F_%T).sql" - local dump_cmd=( - mysqldump - --skip-add-locks - --skip-lock-tables - --single-transaction - -h"${DB_HOST}" - -P"${DB_PORT}" - -u"${DB_USER}" - ) - for table in "${FULL_IGNORE_TABLES[@]}"; do - dump_cmd+=("--ignore-table=${DB_NAME}.${table}") - done - dump_cmd+=("${DB_NAME}") + local excluded_tables=() + if [[ "${MODE}" == "no_audit" ]]; then + excluded_tables=("${AUDITS_TABLES[@]}") + fi - if ! docker run --rm \ - --env MYSQL_PWD="${DB_PASSWORD}" \ - -i --network=jms_net \ - "${db_images}" \ - "${dump_cmd[@]}" > "${DB_FILE}"; then - log_error "$(gettext 'Backup failed')!" - rm -f "${DB_FILE}" - exit 1 - fi + DB_FILE="${BACKUP_DIR}/${DB_NAME}-${CURRENT_VERSION}-$(date +%F_%T).sql" + local dump_cmd=( + mysqldump + --skip-add-locks + --skip-lock-tables + --single-transaction + -h"${DB_HOST}" + -P"${DB_PORT}" + -u"${DB_USER}" + ) + for table in "${excluded_tables[@]}"; do + dump_cmd+=("--ignore-table=${DB_NAME}.${table}") + done + dump_cmd+=("${DB_NAME}") - local schema_cmd=( - mysqldump - --skip-add-locks - --skip-lock-tables - --single-transaction - --no-data - -h"${DB_HOST}" - -P"${DB_PORT}" - -u"${DB_USER}" - "${DB_NAME}" - "${FULL_IGNORE_TABLES[@]}" - ) - if ! docker run --rm \ - --env MYSQL_PWD="${DB_PASSWORD}" \ - -i --network=jms_net \ - "${db_images}" \ - "${schema_cmd[@]}" >> "${DB_FILE}"; then - log_error "$(gettext 'Backup failed')!" - rm -f "${DB_FILE}" - exit 1 - fi + if ! docker run --rm \ + --env MYSQL_PWD="${DB_PASSWORD}" \ + -i --network=jms_net \ + "${db_images}" \ + "${dump_cmd[@]}" > "${DB_FILE}"; then + log_error "$(gettext 'Backup failed')!" + rm -f "${DB_FILE}" + return 1 + fi + + if [[ ${#excluded_tables[@]} -gt 0 ]]; then + local schema_cmd=( + mysqldump + --skip-add-locks + --skip-lock-tables + --single-transaction + --no-data + -h"${DB_HOST}" + -P"${DB_PORT}" + -u"${DB_USER}" + "${DB_NAME}" + "${excluded_tables[@]}" + ) + if ! docker run --rm \ + --env MYSQL_PWD="${DB_PASSWORD}" \ + -i --network=jms_net \ + "${db_images}" \ + "${schema_cmd[@]}" >> "${DB_FILE}"; then + log_error "$(gettext 'Backup failed')!" + rm -f "${DB_FILE}" + return 1 + fi + fi +} + +function backup_main_db_postgresql() { + local table + local excluded_tables=() + if [[ "${MODE}" == "no_audit" ]]; then + excluded_tables=("${AUDITS_TABLES[@]}") + fi + + DB_FILE="${BACKUP_DIR}/${DB_NAME}-${CURRENT_VERSION}-$(date +%F_%T).dump" + local dump_cmd=( + pg_dump + --format=custom + --no-owner + -U "${DB_USER}" + -h "${DB_HOST}" + -p "${DB_PORT}" + -d "${DB_NAME}" + ) + for table in "${excluded_tables[@]}"; do + dump_cmd+=("--exclude-table-data=${table}") + done + + if ! docker run --rm \ + --env PGPASSWORD="${DB_PASSWORD}" \ + -i --network=jms_net \ + "${db_images}" \ + "${dump_cmd[@]}" > "${DB_FILE}"; then + log_error "$(gettext 'Backup failed')!" + rm -f "${DB_FILE}" + return 1 + fi +} + +function backup_main_db() { + case "${DB_ENGINE}" in + mysql) + backup_main_db_mysql || return 1 ;; postgresql) - DB_FILE="${BACKUP_DIR}/${DB_NAME}-${CURRENT_VERSION}-$(date +%F_%T).dump" - local dump_cmd=( - pg_dump - --format=custom - --no-owner - -U "${DB_USER}" - -h "${DB_HOST}" - -p "${DB_PORT}" - -d "${DB_NAME}" - ) - for table in "${FULL_IGNORE_TABLES[@]}"; do - dump_cmd+=("--exclude-table-data=${table}") - done - - if ! docker run --rm \ - --env PGPASSWORD="${DB_PASSWORD}" \ - -i --network=jms_net \ - "${db_images}" \ - "${dump_cmd[@]}" > "${DB_FILE}"; then - log_error "$(gettext 'Backup failed')!" - rm -f "${DB_FILE}" - exit 1 - fi + backup_main_db_postgresql || return 1 ;; *) log_error "$(gettext 'Invalid DB Engine selection')!" - exit 1 + return 1 ;; esac @@ -267,7 +286,7 @@ function main() { prepare_db_env case "${MODE}" in - full) + full|no_audit) if ! backup_main_db; then cleanup_db_env exit 1 diff --git a/scripts/6_db_restore.sh b/scripts/6_db_restore.sh index 1c9a69f..766e217 100644 --- a/scripts/6_db_restore.sh +++ b/scripts/6_db_restore.sh @@ -14,59 +14,45 @@ DB_USER=$(get_config DB_USER) DB_PASSWORD=$(get_config DB_PASSWORD) DB_NAME=$(get_config DB_NAME) -function main() { - echo_warn "$(gettext 'Make sure you have a backup of data, this operation is not reversible')! \n" - - if [[ ! -f "${DB_FILE}" ]]; then - echo "$(gettext 'file does not exist'): ${DB_FILE}" - exit 1 - fi - - db_images=$(get_db_images) - - echo "$(gettext 'Start restoring database'): $DB_FILE" - - if ! docker ps | grep -w "jms_core" &>/dev/null; then - create_db_ops_env - flag=1 - fi - case "${DB_HOST}" in - mysql|postgresql) - while [[ "$(docker inspect -f "{{.State.Health.Status}}" jms_${DB_HOST})" != "healthy" ]]; do - sleep 5s - done - ;; - esac - - case "${DB_ENGINE}" in - mysql) - restore_cmd=' +function restore_mysql() { + local restore_cmd=' if [[ "${DB_FILE}" == *.gz ]]; then gzip -dc "${DB_FILE}" | mysql -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASSWORD}" "${DB_NAME}" else mysql -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASSWORD}" "${DB_NAME}" < "${DB_FILE}" fi ' - ;; - postgresql) - restore_file="${DB_FILE}" - tmp_restore_file="" - if [[ "${DB_FILE}" == *.gz ]]; then - tmp_restore_file=$(mktemp "${BACKUP_DIR}/.pg_restore.XXXXXX") - if ! gzip -dc "${DB_FILE}" > "${tmp_restore_file}"; then - log_error "$(gettext 'Failed to decompress backup file')!" - rm -f "${tmp_restore_file}" - exit 1 - fi - restore_file="${tmp_restore_file}" - fi + local docker_env=( + --env "DB_HOST=${DB_HOST}" --env "DB_PORT=${DB_PORT}" --env "DB_USER=${DB_USER}" + --env "DB_PASSWORD=${DB_PASSWORD}" --env "DB_NAME=${DB_NAME}" --env "DB_FILE=${DB_FILE}" + ) + + docker run --rm "${docker_env[@]}" \ + -i --network=jms_net \ + -v "${BACKUP_DIR}:${BACKUP_DIR}" \ + "${db_images}" bash -c "${restore_cmd}" +} - pg_magic=$(dd if="${restore_file}" bs=1 count=5 2>/dev/null) - if [[ "${pg_magic}" == "PGDMP" ]]; then - echo "$(gettext 'Resetting database schema before restore')..." - fi +function restore_postgresql() { + local restore_file="${DB_FILE}" + local tmp_restore_file="" + if [[ "${DB_FILE}" == *.gz ]]; then + tmp_restore_file=$(mktemp "${BACKUP_DIR}/.pg_restore.XXXXXX") + if ! gzip -dc "${DB_FILE}" > "${tmp_restore_file}"; then + log_error "$(gettext 'Failed to decompress backup file')!" + rm -f "${tmp_restore_file}" + return 1 + fi + restore_file="${tmp_restore_file}" + fi - restore_cmd=' + local pg_magic + pg_magic=$(dd if="${restore_file}" bs=1 count=5 2>/dev/null) + if [[ "${pg_magic}" == "PGDMP" ]]; then + echo "$(gettext 'Resetting database schema before restore')..." + fi + + local restore_cmd=' reset_pg_public_schema() { PGPASSWORD="${DB_PASSWORD}" psql -v ON_ERROR_STOP=1 -U "${DB_USER}" -h "${DB_HOST}" -p "${DB_PORT}" -d "${DB_NAME}" \ -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = current_database() AND pid <> pg_backend_pid();" \ @@ -84,30 +70,69 @@ function main() { PGPASSWORD="${DB_PASSWORD}" psql -q -v ON_ERROR_STOP=1 -U "${DB_USER}" -h "${DB_HOST}" -p "${DB_PORT}" -d "${DB_NAME}" < "${RESTORE_FILE}" >/dev/null fi ' + local docker_env=( + --env "DB_HOST=${DB_HOST}" --env "DB_PORT=${DB_PORT}" --env "DB_USER=${DB_USER}" + --env "DB_PASSWORD=${DB_PASSWORD}" --env "DB_NAME=${DB_NAME}" + --env "RESTORE_FILE=${restore_file}" + ) + + docker run --rm "${docker_env[@]}" \ + -i --network=jms_net \ + -v "${BACKUP_DIR}:${BACKUP_DIR}" \ + "${db_images}" bash -c "${restore_cmd}" + local restore_status=$? + + [[ -n "${tmp_restore_file}" ]] && rm -f "${tmp_restore_file}" + return ${restore_status} +} + +function restore_database() { + case "${DB_ENGINE}" in + mysql) + restore_mysql + ;; + postgresql) + restore_postgresql ;; *) log_error "$(gettext 'Invalid DB Engine selection')!" - exit 1 + return 1 ;; esac +} - docker_env=( - --env "DB_HOST=${DB_HOST}" --env "DB_PORT=${DB_PORT}" --env "DB_USER=${DB_USER}" - --env "DB_PASSWORD=${DB_PASSWORD}" --env "DB_NAME=${DB_NAME}" --env "DB_FILE=${DB_FILE}" - ) - if [[ "${DB_ENGINE}" == "postgresql" ]]; then - docker_env+=(--env "RESTORE_FILE=${restore_file}") +function main() { + echo_warn "$(gettext 'Make sure you have a backup of data, this operation is not reversible')! \n" + + if [[ ! -f "${DB_FILE}" ]]; then + echo "$(gettext 'file does not exist'): ${DB_FILE}" + return 1 fi - if ! docker run --rm "${docker_env[@]}" \ - -i --network=jms_net \ - -v "${BACKUP_DIR}:${BACKUP_DIR}" \ - "${db_images}" bash -c "${restore_cmd}"; then - [[ -n "${tmp_restore_file}" ]] && rm -f "${tmp_restore_file}" + db_images=$(get_db_images) + + echo "$(gettext 'Start restoring database'): $DB_FILE" + + if ! docker ps | grep -w "jms_core" &>/dev/null; then + create_db_ops_env + flag=1 + fi + case "${DB_HOST}" in + mysql|postgresql) + while [[ "$(docker inspect -f "{{.State.Health.Status}}" jms_${DB_HOST})" != "healthy" ]]; do + sleep 5s + done + ;; + esac + + if ! restore_database; then log_error "$(gettext 'Database recovery failed. Please check whether the database file is complete or try to recover manually')!" - exit 1 + if [[ -n "$flag" ]]; then + down_db_ops_env + unset flag + fi + return 1 else - [[ -n "${tmp_restore_file}" ]] && rm -f "${tmp_restore_file}" log_success "$(gettext 'Database recovered successfully')!" run_post_restore fi @@ -148,5 +173,7 @@ if [[ "$0" == "${BASH_SOURCE[0]}" ]]; then fi stop_jms_core main + restore_status=$? start_jms_core -fi \ No newline at end of file + exit ${restore_status} +fi From 909e49844bbe9233164820f4c5466338a7efe9fa Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 6 Aug 2026 15:43:18 +0800 Subject: [PATCH 26/40] perf: update backup db backkup --- scripts/5_db_backup.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/5_db_backup.sh b/scripts/5_db_backup.sh index d971fd8..a44556d 100644 --- a/scripts/5_db_backup.sh +++ b/scripts/5_db_backup.sh @@ -78,12 +78,14 @@ function cleanup_db_env() { function backup_main_db_mysql() { local table + local backup_type="" local excluded_tables=() if [[ "${MODE}" == "no_audit" ]]; then + backup_type="-no_audit" excluded_tables=("${AUDITS_TABLES[@]}") fi - DB_FILE="${BACKUP_DIR}/${DB_NAME}-${CURRENT_VERSION}-$(date +%F_%T).sql" + DB_FILE="${BACKUP_DIR}/${DB_NAME}${backup_type}-${CURRENT_VERSION}-$(date +%F_%T).sql" local dump_cmd=( mysqldump --skip-add-locks @@ -135,12 +137,14 @@ function backup_main_db_mysql() { function backup_main_db_postgresql() { local table + local backup_type="" local excluded_tables=() if [[ "${MODE}" == "no_audit" ]]; then + backup_type="-no_audit" excluded_tables=("${AUDITS_TABLES[@]}") fi - DB_FILE="${BACKUP_DIR}/${DB_NAME}-${CURRENT_VERSION}-$(date +%F_%T).dump" + DB_FILE="${BACKUP_DIR}/${DB_NAME}${backup_type}-${CURRENT_VERSION}-$(date +%F_%T).dump" local dump_cmd=( pg_dump --format=custom @@ -245,9 +249,10 @@ function backup_audits_postgresql() { } function backup_audits() { + AUDIT_FILE="${BACKUP_DIR}/${DB_NAME}-audit-${CURRENT_VERSION}-$(date +%F_%H%M%S).sql.gz" + case "${DB_ENGINE}" in mysql) - AUDIT_FILE="${BACKUP_DIR}/audits_${CURRENT_VERSION}_$(date +%F_%H%M%S).sql.gz" if ! backup_audits_mysql "${AUDIT_FILE}"; then rm -f "${AUDIT_FILE}" log_error "$(gettext 'Backup failed')!" @@ -255,7 +260,6 @@ function backup_audits() { fi ;; postgresql) - AUDIT_FILE="${BACKUP_DIR}/audits_${CURRENT_VERSION}_$(date +%F_%H%M%S).sql.gz" if ! backup_audits_postgresql "${AUDIT_FILE}"; then rm -f "${AUDIT_FILE}" rm -f "${AUDIT_FILE%.gz}" From 76d57a946c3da7534cff6d59b10cd268ebb3f6ce Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 6 Aug 2026 15:51:50 +0800 Subject: [PATCH 27/40] perf: update db backup --- scripts/5_db_backup.sh | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/scripts/5_db_backup.sh b/scripts/5_db_backup.sh index a44556d..e3fbacc 100644 --- a/scripts/5_db_backup.sh +++ b/scripts/5_db_backup.sh @@ -89,7 +89,6 @@ function backup_main_db_mysql() { local dump_cmd=( mysqldump --skip-add-locks - --skip-lock-tables --single-transaction -h"${DB_HOST}" -P"${DB_PORT}" @@ -113,9 +112,7 @@ function backup_main_db_mysql() { if [[ ${#excluded_tables[@]} -gt 0 ]]; then local schema_cmd=( mysqldump - --skip-add-locks --skip-lock-tables - --single-transaction --no-data -h"${DB_HOST}" -P"${DB_PORT}" @@ -196,25 +193,31 @@ function backup_main_db() { function backup_audits_mysql() { local backup_file=$1 + local dump_cmd=( + mysqldump + -h"${DB_HOST}" + -P"${DB_PORT}" + -u"${DB_USER}" + --single-transaction + --no-create-info + --skip-triggers + --insert-ignore + ) + + if [[ "${db_images}" != *mariadb* ]]; then + dump_cmd+=(--set-gtid-purged=OFF) + fi + dump_cmd+=( + "${DB_NAME}" + "${AUDITS_TABLES[@]}" + "${SHARED_BACKUP_TABLES[@]}" + ) docker run --rm \ -e MYSQL_PWD="${DB_PASSWORD}" \ -i --network=jms_net \ "${db_images}" \ - mysqldump \ - -h"${DB_HOST}" \ - -P"${DB_PORT}" \ - -u"${DB_USER}" \ - --single-transaction \ - --quick \ - --set-gtid-purged=OFF \ - --no-create-info \ - --skip-triggers \ - --insert-ignore \ - --default-character-set=utf8mb4 \ - "${DB_NAME}" \ - "${AUDITS_TABLES[@]}" \ - "${SHARED_BACKUP_TABLES[@]}" | gzip > "${backup_file}" + "${dump_cmd[@]}" | gzip > "${backup_file}" } function backup_audits_postgresql() { @@ -241,8 +244,6 @@ function backup_audits_postgresql() { -d "${DB_NAME}" \ --data-only \ --inserts \ - --no-owner \ - --no-privileges \ "${table_args[@]}" | sed '/^INSERT INTO / s/;[[:space:]]*$/ ON CONFLICT DO NOTHING;/' > "${sql_file}" || return 1 gzip -f "${sql_file}" || return 1 From 9723997c311725b156923ebbe50ad916e9455266 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 6 Aug 2026 16:57:27 +0800 Subject: [PATCH 28/40] perf: update dbbackup --- scripts/5_db_backup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/5_db_backup.sh b/scripts/5_db_backup.sh index e3fbacc..7ab6d6f 100644 --- a/scripts/5_db_backup.sh +++ b/scripts/5_db_backup.sh @@ -22,13 +22,13 @@ AUDITS_TABLES=( audits_operatelog audits_passwordchangelog audits_userloginlog - terminal terminal_session terminal_command ) SHARED_BACKUP_TABLES=( users_user + terminal ) MODE="full" From 07fb6842bc4ce3b920155ba091d5b1948127db12 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 12 Aug 2026 18:24:25 +0800 Subject: [PATCH 29/40] perf: POSTGRESQL_EXPOSE_PORT --- scripts/1_config_jumpserver.sh | 6 ++++++ scripts/7_upgrade.sh | 3 +++ 2 files changed, 9 insertions(+) diff --git a/scripts/1_config_jumpserver.sh b/scripts/1_config_jumpserver.sh index eef9187..52fe994 100644 --- a/scripts/1_config_jumpserver.sh +++ b/scripts/1_config_jumpserver.sh @@ -83,6 +83,9 @@ function set_external_db() { read_from_input db_password "$(gettext 'Please enter DB password')" "" "${db_password}" set_db_config "${db_engine}" "${db_host}" "${db_port}" "${db_user}" "${db_password}" "${db_name}" + if [[ "${db_engine}" == "postgresql" ]]; then + remove_config POSTGRESQL_EXPOSE_PORT + fi } function set_internal_db() { @@ -100,6 +103,9 @@ function set_internal_db() { fi set_db_config "${db_engine}" "${db_host}" "${db_port}" "${db_user}" "${db_password}" "${db_name}" + if [[ "${db_engine}" == "postgresql" ]]; then + set_config POSTGRESQL_EXPOSE_PORT "127.0.0.1:5432" + fi } function set_db() { diff --git a/scripts/7_upgrade.sh b/scripts/7_upgrade.sh index c93b0e1..c33061c 100644 --- a/scripts/7_upgrade.sh +++ b/scripts/7_upgrade.sh @@ -92,6 +92,9 @@ function upgrade_config() { check_and_set_config "JUMPSERVER_ENABLE_FONT_SMOOTHING" "true" check_and_set_config "USE_LB" "1" check_and_set_config "VERIFY_EXTERNAL_SSL" "false" + if [[ "$(get_config DB_HOST)" == "postgresql" ]]; then + check_and_set_config "POSTGRESQL_EXPOSE_PORT" "127.0.0.1:5432" + fi # XPACK use_xpack=$(get_config_or_env USE_XPACK) if [[ "${use_xpack}" == "1" ]]; then From 51cef78ba2f7082a504f3994117399aa93d858cb Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 13 Aug 2026 14:51:11 +0800 Subject: [PATCH 30/40] perf: generate nginx test cert, when install --- .gitignore | 3 ++- config_init/nginx/cert/server.crt | 22 --------------------- config_init/nginx/cert/server.key | 27 -------------------------- scripts/gists/conf.sh | 32 +++++++++++++++++-------------- 4 files changed, 20 insertions(+), 64 deletions(-) delete mode 100644 config_init/nginx/cert/server.crt delete mode 100644 config_init/nginx/cert/server.key diff --git a/.gitignore b/.gitignore index d94a71c..69cd375 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ cofnig.link .bak config.link release/* -.history/ \ No newline at end of file +.history/ +config_init/nginx/cert/ diff --git a/config_init/nginx/cert/server.crt b/config_init/nginx/cert/server.crt deleted file mode 100644 index e060a86..0000000 --- a/config_init/nginx/cert/server.crt +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDtDCCApwCCQC70xxmpUL+9zANBgkqhkiG9w0BAQUFADCBmzELMAkGA1UEBhMC -Q04xEDAOBgNVBAgMB0JlaWppbmcxEDAOBgNVBAcMB0JlaWppbmcxFDASBgNVBAoM -C0R1aVpoYW4uSW5jMQ0wCwYDVQQLDARUZWNoMRwwGgYDVQQDDBN0ZXN0Lmp1bXBz -ZXJ2ZXIub3JnMSUwIwYJKoZIhvcNAQkBFhZzdXBwb3J0QGp1bXBzZXJ2ZXIub3Jn -MB4XDTE5MDExNzA5MjYwNFoXDTI5MDExNDA5MjYwNFowgZsxCzAJBgNVBAYTAkNO -MRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW5nMRQwEgYDVQQKDAtE -dWlaaGFuLkluYzENMAsGA1UECwwEVGVjaDEcMBoGA1UEAwwTdGVzdC5qdW1wc2Vy -dmVyLm9yZzElMCMGCSqGSIb3DQEJARYWc3VwcG9ydEBqdW1wc2VydmVyLm9yZzCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKOEMGaqwjlNTTDtJkQpQH/5 -0QbvXWr+Q82ihPnFV685uQsj6vLFjD4gksdehENbMnPjpVDZCvzfhBOqahLZsvM6 -7ea0S1RFtX0t7rwErn3DOs5MYxU1bVyss1Ahf+bvOWgwaQpxkOmynOe4wxEqC2OJ -mQEzhb9sPo+tF52yMKtoQdkLVzf1Ci9HkVfwwAytejktnYwhzKR65GYHjMb9j7+p -z2dp3n6QKz0R9mnkEj6d6zRaFWT4sE5TMJt4DmHSwSP43c58rAbL8wyqWV9lifRr -RevHzGgFE3ep1Y53fm4jVCK5jY17CtV8g9iP8b0ttL2qr9jvNec37kGONpYjkl8C -AwEAATANBgkqhkiG9w0BAQUFAAOCAQEAdsI48hcuVz65dK1JYaoezM/PmVTD17Nx -l9QeRWANALro/nV8UOtMFGVBPFFzji+BsLKol6o8BCdpw72nfRNIPsNFFCrCgbft -2eNNc0hFHqbfwjT6E03JLb42BU5is+x2U8/Krg90Yt5XF0LoHm9lr24Kb31/wBKx -Ilb7mpC/TPd4p2V+QG46t6Ji4Q+DufihupgobG3PgcaOtPzT51HAlrL7R8OmDciB -o3h1ALD6CsvSK38SkFo6yc3lckjlfg/q0LZLeSEAAKerzL2j/DPw3hTUwMhFmTt5 -PWL26PfEUlv6wwUi/9Soa7B9QM0XEa9ib5PAWbIRCG4VxOG8fl57UA== ------END CERTIFICATE----- diff --git a/config_init/nginx/cert/server.key b/config_init/nginx/cert/server.key deleted file mode 100644 index 742b323..0000000 --- a/config_init/nginx/cert/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAo4QwZqrCOU1NMO0mRClAf/nRBu9dav5DzaKE+cVXrzm5CyPq -8sWMPiCSx16EQ1syc+OlUNkK/N+EE6pqEtmy8zrt5rRLVEW1fS3uvASufcM6zkxj -FTVtXKyzUCF/5u85aDBpCnGQ6bKc57jDESoLY4mZATOFv2w+j60XnbIwq2hB2QtX -N/UKL0eRV/DADK16OS2djCHMpHrkZgeMxv2Pv6nPZ2nefpArPRH2aeQSPp3rNFoV -ZPiwTlMwm3gOYdLBI/jdznysBsvzDKpZX2WJ9GtF68fMaAUTd6nVjnd+biNUIrmN -jXsK1XyD2I/xvS20vaqv2O815zfuQY42liOSXwIDAQABAoIBAHmpj0G0Z9Ku23I9 -4Szx7JXL0GTykHVdPiGwfHRDCtzLfAz36oY7yf8nyU4h2xMqtb1YcdZXxz8jJ2hi -cY4ZAHbNL9lp6GqJe2HqXSjz6siUDBsW5toO6JH9xWUnp7yx3erRqjYlDYd0aB5Z -cHpC6DplVLx6E1e8OEg6p8mjnWbKeUAYAjw5ib3Cpn/VIY+ehuuDIwpfEKLct1yc -dWTJUqOhKOHxEPMdfmgaqqFi5XsDwC+aK4kXOvmLOYYvwH9DummcRckY7WOVF4yS -vKThEs60xOYViAtKLan47XhDqBaUcLWfK09OC9X87OXlUFh9nxdrZ6cwLcmYOL2Q -ZDYqf7ECgYEA0HvB6S87I5p2eaFLRS3ZYcHo75ooGAoUSDSkf2UBqznVWQrhQgUY -TOFf+/RQnDGY/tLbd338nhuOae2qtaY5iaFnbFVe0H4gDoIqM6tYCcJ0SXSvWTFk -E5Jso0O/yPGudztc2LBYpN6TTKbmANFBbq/zsDWFigFYXYjmDw/voFsCgYEAyMjE -vWb29VEELyWaBGUs3ryezvMA/Leli7uD3VwcVzLUIlhoTFESjooZeQlIHoYDuFX5 -aHjF2U4sLJ2lft+3nbBVfdW7s4FZtsX7QM5IfcVVj8PTvM2uMWxOxA6L/DPIin01 -PiCnEe7Xz/7ypEXS7cu4SNHwZu9toNcEUFsQtU0CgYBmtCDBm+fZUTV+E6w95ylI -lDsJFfscZJK7Q1up+ntI+5OTat2vJU1kSj57o062s2Q4XG2LPwBcbxzIKDHJjJqZ -p26ImsG7mfZ2zz6093rGTAn3Sck7+i3fymlEQJLRDeYxjIffo3f3uEH+J9X0nyFJ -wtocezFO2/zJDzCuSN52MwKBgQCRCAysrzJV0xaNo8CTyi1WGrMv03H0Ggd3XpSK -kd1a0zlOMcPs1GbuFSz/M8gnXDBVt6x3XT20kPXxqFIBykGMovGt+nQh3p5aGro5 -fof4aVE7jn1klMFtq8ldbxCItTL3bifGX7muh3LWKFdGd7U71XqhBxx6jhoHIylX -jeAMxQKBgAYSePmWULgXazuqTM0VeyiVOYlBmoD5WOZPBmX3KBs3FQmaVJmCdJBx -m8eudLlU2FSjPqEYOFqkH+bIMh6GsIAy09FlCyC9GhkiU8cMETa3S1MQsXAf9JP7 -5+/8/MoppyBaDEjbYNp3kAB0AcsSNgc2tbkquoKeyPG6xWabvhxb ------END RSA PRIVATE KEY----- diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 01b473b..56d97fd 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -184,21 +184,25 @@ function prepare_config() { done nginx_cert_dir="${CONFIG_DIR}/nginx/cert" - if [[ ! -d ${nginx_cert_dir} ]]; then - mkdir -p "${nginx_cert_dir}" - \cp -rf "${PROJECT_DIR}/config_init/nginx/cert" "${CONFIG_DIR}/nginx" - fi - - # shellcheck disable=SC2045 - for f in $(ls "${PROJECT_DIR}/config_init/nginx/cert"); do - if [[ -f "${PROJECT_DIR}/config_init/nginx/cert/${f}" ]]; then - if [[ ! -f "${nginx_cert_dir}/${f}" ]]; then - \cp -f "${PROJECT_DIR}/config_init/nginx/cert/${f}" "${nginx_cert_dir}" - else - echo_check "${nginx_cert_dir}/${f} " - fi + nginx_cert_file="${nginx_cert_dir}/server.crt" + nginx_key_file="${nginx_cert_dir}/server.key" + mkdir -p "${nginx_cert_dir}" + if [[ ! -f "${nginx_cert_file}" && ! -f "${nginx_key_file}" ]]; then + if ! command -v openssl >/dev/null 2>&1; then + log_error "$(gettext 'OpenSSL is required to generate the initial Nginx certificate')" + exit 1 fi - done + openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 3650 \ + -keyout "${nginx_key_file}" \ + -out "${nginx_cert_file}" \ + -subj "/CN=localhost" + elif [[ ! -f "${nginx_cert_file}" || ! -f "${nginx_key_file}" ]]; then + log_error "$(gettext 'Nginx certificate and private key must both exist')" + exit 1 + else + echo_check "${nginx_cert_file}" + echo_check "${nginx_key_file}" + fi chmod 700 "${CONFIG_DIR}/../" find "${CONFIG_DIR}" -type d -exec chmod 700 {} \; find "${CONFIG_DIR}" -type f -exec chmod 600 {} \; From 6a949b6da2a0994839732550a64ae04e84213bf9 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 13 Aug 2026 15:56:22 +0800 Subject: [PATCH 31/40] perf: fix xrdp healthy --- compose/xrdp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compose/xrdp.yml b/compose/xrdp.yml index b44b396..47ea06a 100644 --- a/compose/xrdp.yml +++ b/compose/xrdp.yml @@ -14,10 +14,10 @@ services: - ${VOLUME_DIR}/xrdp/data:/opt/xrdp/data - ${CONFIG_DIR}/nginx/cert:/opt/xrdp/cert healthcheck: - test: "nc -z 127.0.0.1 $$XRDP_PORT || exit 1" + test: "nc -z 127.0.0.1 3390 || exit 1" interval: 10s timeout: 5s retries: 3 start_period: 10s networks: - - net \ No newline at end of file + - net From 9533d6df79c6caa238eaae964d98275eda589942 Mon Sep 17 00:00:00 2001 From: BugKing Date: Mon, 17 Aug 2026 17:05:15 +0800 Subject: [PATCH 32/40] chore: Update DOCKER_VERSION to 29.7.2 --- scripts/const.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/const.sh b/scripts/const.sh index e0b2a26..02f32b5 100644 --- a/scripts/const.sh +++ b/scripts/const.sh @@ -27,7 +27,7 @@ STATIC_ENV=${PROJECT_DIR}/static.env . "${STATIC_ENV}" export OS=$(uname -s) -export DOCKER_VERSION=29.6.1 +export DOCKER_VERSION=29.7.2 export DOCKER_COMPOSE_VERSION=v2.40.3 ARCH=$(uname -m) From e8b13fe9348a678d7cb2bd430c23fdbbbd523570 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 18 Aug 2026 15:00:28 +0800 Subject: [PATCH 33/40] perf: update postgre version --- compose/postgresql.yml | 4 ++-- scripts/gists/service.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compose/postgresql.yml b/compose/postgresql.yml index 19aa293..917a25a 100644 --- a/compose/postgresql.yml +++ b/compose/postgresql.yml @@ -1,6 +1,6 @@ services: postgresql: - image: postgres:16.10-bookworm + image: postgres:16.15-bookworm container_name: jms_postgresql restart: always environment: @@ -17,4 +17,4 @@ services: retries: 3 start_period: 30s networks: - - net \ No newline at end of file + - net diff --git a/scripts/gists/service.sh b/scripts/gists/service.sh index e27b72d..b8eb2be 100644 --- a/scripts/gists/service.sh +++ b/scripts/gists/service.sh @@ -88,7 +88,7 @@ function get_db_info() { elif [[ "${mariadb_data_exists}" == "1" ]]; then echo "mariadb:10.6" elif [[ "${postgres_data_exists}" == "1" ]]; then - echo "postgres:16.10-bookworm" + echo "postgres:16.15-bookworm" fi ;; "file") From 48a0a9832405035e6596ed560f8d3911bf00724a Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 18 Aug 2026 15:13:05 +0800 Subject: [PATCH 34/40] perf: update pg redis version --- compose/redis.yml | 2 +- scripts/gists/image.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compose/redis.yml b/compose/redis.yml index 00eeaf5..7cd1f84 100644 --- a/compose/redis.yml +++ b/compose/redis.yml @@ -1,6 +1,6 @@ services: redis: - image: redis:7.4.6-bookworm + image: redis:7.4.10-bookworm container_name: jms_redis hostname: jms_redis restart: always diff --git a/scripts/gists/image.sh b/scripts/gists/image.sh index 2bd7035..408c8e7 100644 --- a/scripts/gists/image.sh +++ b/scripts/gists/image.sh @@ -8,7 +8,7 @@ function get_db_images() { function get_pull_images() { use_xpack=$(get_config_or_env USE_XPACK) - images=("redis:7.4.6-bookworm") + images=("redis:7.4.10-bookworm") images+=("$(get_db_images)") enabled_services=$(get_enabled_services) @@ -36,7 +36,7 @@ function get_pull_images() { function get_images() { use_xpack=$(get_config_or_env USE_XPACK) - images=("redis:7.4.6-bookworm") + images=("redis:7.4.10-bookworm") images+=("$(get_db_images)") enabled_services=$(get_enabled_services) From 296299aade2a0fd03845dbbfb45dc221e427ec3a Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 19 Aug 2026 14:20:56 +0800 Subject: [PATCH 35/40] perf: update pull base image --- scripts/gists/conf.sh | 8 +++++++- scripts/gists/image.sh | 12 ++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 56d97fd..92acc2b 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -27,7 +27,13 @@ function get_config_or_env() { value='' default=${2-''} - value="${!key}" + # Bash supports ${!key}, but zsh reports "bad substitution" when this + # helper is called from an interactive shell. The installer only passes + # configuration variable names here, so use a validated, portable indirect + # expansion instead. + if [[ "${key}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then + eval "value=\${${key}:-}" + fi if [[ -z "$value" && -f "${CONFIG_FILE}" ]];then value=$(get_config "$key") fi diff --git a/scripts/gists/image.sh b/scripts/gists/image.sh index 408c8e7..7167d6a 100644 --- a/scripts/gists/image.sh +++ b/scripts/gists/image.sh @@ -74,10 +74,18 @@ function image_has_prefix() { function image_uses_mirror_prefix() { image=$1 + # Infrastructure images are pulled directly from Docker Hub. Only + # JumpServer application images and the remaining third-party images use + # the configured internal mirror. + case "${image}" in + redis|redis:*|redis@*|postgres|postgres:*|postgres@*|openbao|openbao:*|openbao@*|openbao/openbao|openbao/openbao:*|openbao/openbao@*) + echo "0" + return + ;; + esac + if [[ "${image}" != */* || $(image_has_prefix "${image}") == "1" ]]; then echo "1" - elif [[ "${image}" == "openbao/openbao" || "${image}" == openbao/openbao:* || "${image}" == openbao/openbao@* ]]; then - echo "1" else echo "0" fi From 135e76314c61ab714e4b33ba21d8b59a7d4fa86c Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 19 Aug 2026 22:37:13 +0800 Subject: [PATCH 36/40] perf: openssl req add -quiet --- scripts/gists/conf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 92acc2b..8de7dfd 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -198,7 +198,7 @@ function prepare_config() { log_error "$(gettext 'OpenSSL is required to generate the initial Nginx certificate')" exit 1 fi - openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 3650 \ + openssl req -quiet -x509 -nodes -newkey rsa:2048 -sha256 -days 3650 \ -keyout "${nginx_key_file}" \ -out "${nginx_cert_file}" \ -subj "/CN=localhost" From 8ba064788ada7515a704541089db173c562f0be2 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 20 Aug 2026 11:03:37 +0800 Subject: [PATCH 37/40] perf: translate --- locale/en/LC_MESSAGES/jumpserver-installer.po | 2 +- locale/zh_CN/LC_MESSAGES/jumpserver-installer.po | 2 +- locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/locale/en/LC_MESSAGES/jumpserver-installer.po b/locale/en/LC_MESSAGES/jumpserver-installer.po index a173674..1d89d2c 100644 --- a/locale/en/LC_MESSAGES/jumpserver-installer.po +++ b/locale/en/LC_MESSAGES/jumpserver-installer.po @@ -187,7 +187,7 @@ msgstr "" #: scripts/1_config_jumpserver.sh:116 msgid "Do you want to use external MySQL" -msgstr "Do you want to use external MySQL (version ≥ 5.7 required)" +msgstr "Do you want to use external MySQL (version ≥ 8.0 required)" #: scripts/1_config_jumpserver.sh:128 msgid "Do you want to use external PostgreSQL" diff --git a/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po b/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po index 5a5720e..1a92462 100644 --- a/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po +++ b/locale/zh_CN/LC_MESSAGES/jumpserver-installer.po @@ -187,7 +187,7 @@ msgstr "配置数据库" #: scripts/1_config_jumpserver.sh:116 msgid "Do you want to use external MySQL" -msgstr "是否使用外部 MySQL (版本需 ≥ 5.7)" +msgstr "是否使用外部 MySQL (版本需 ≥ 8.0)" #: scripts/1_config_jumpserver.sh:128 msgid "Do you want to use external PostgreSQL" diff --git a/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po b/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po index 5948a52..609db38 100644 --- a/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po +++ b/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.po @@ -187,7 +187,7 @@ msgstr "配置資料庫" #: scripts/1_config_jumpserver.sh:116 msgid "Do you want to use external MySQL" -msgstr "是否使用外部 MySQL(版本需 ≥ 5.7)" +msgstr "是否使用外部 MySQL(版本需 ≥ 8.0)" #: scripts/1_config_jumpserver.sh:128 msgid "Do you want to use external PostgreSQL" From 85c956b42c64093b37b8fd3be4da9e66fab16126 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 20 Aug 2026 11:17:22 +0800 Subject: [PATCH 38/40] perf: audits add --on-conflict-do-nothing --- scripts/5_db_backup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/5_db_backup.sh b/scripts/5_db_backup.sh index 7ab6d6f..685bcc5 100644 --- a/scripts/5_db_backup.sh +++ b/scripts/5_db_backup.sh @@ -244,7 +244,8 @@ function backup_audits_postgresql() { -d "${DB_NAME}" \ --data-only \ --inserts \ - "${table_args[@]}" | sed '/^INSERT INTO / s/;[[:space:]]*$/ ON CONFLICT DO NOTHING;/' > "${sql_file}" || return 1 + --on-conflict-do-nothing \ + "${table_args[@]}" > "${sql_file}" || return 1 gzip -f "${sql_file}" || return 1 } From 1dc8cb404249eb5432eda511c00228f6b9eb9a66 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 20 Aug 2026 11:17:22 +0800 Subject: [PATCH 39/40] perf: audits add --on-conflict-do-nothing --- scripts/gists/conf.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/gists/conf.sh b/scripts/gists/conf.sh index 8de7dfd..2c5a99b 100644 --- a/scripts/gists/conf.sh +++ b/scripts/gists/conf.sh @@ -198,10 +198,13 @@ function prepare_config() { log_error "$(gettext 'OpenSSL is required to generate the initial Nginx certificate')" exit 1 fi - openssl req -quiet -x509 -nodes -newkey rsa:2048 -sha256 -days 3650 \ + if ! openssl_output=$(openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 3650 \ -keyout "${nginx_key_file}" \ -out "${nginx_cert_file}" \ - -subj "/CN=localhost" + -subj "/CN=localhost" 2>&1); then + log_error "${openssl_output}" + exit 1 + fi elif [[ ! -f "${nginx_cert_file}" || ! -f "${nginx_key_file}" ]]; then log_error "$(gettext 'Nginx certificate and private key must both exist')" exit 1 From f6914509390d8cec1e311a4e778bba0dc48ddfef Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 20 Aug 2026 15:21:16 +0800 Subject: [PATCH 40/40] perf: translate --- locale/en/LC_MESSAGES/jumpserver-installer.mo | Bin 629 -> 629 bytes .../zh_CN/LC_MESSAGES/jumpserver-installer.mo | Bin 14069 -> 14069 bytes .../LC_MESSAGES/jumpserver-installer.mo | Bin 13849 -> 13849 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/locale/en/LC_MESSAGES/jumpserver-installer.mo b/locale/en/LC_MESSAGES/jumpserver-installer.mo index b20270deb3b58f7486b0e317643f2ccffe42ac62..3e1d0773ba197f339c2c348de3c87728d9694f56 100644 GIT binary patch delta 15 Wcmey$@|9(S8WXdHp21{ICLaJR90YCv delta 15 Wcmey$@|9(S8WXdrp7~@=CLaJRDg<%> diff --git a/locale/zh_CN/LC_MESSAGES/jumpserver-installer.mo b/locale/zh_CN/LC_MESSAGES/jumpserver-installer.mo index cacd48e844b84b6a1530649a40ef2fa0b9152260..c99784087c30cbc8b89654173738bdb79f1fbcbf 100644 GIT binary patch delta 16 XcmeyG`!#pNSxsgOJ%h~`G*x*4M=1v4 delta 16 XcmeyG`!#pNSxshBJ@d^MG*x*4M>_`Q diff --git a/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.mo b/locale/zh_Hant/LC_MESSAGES/jumpserver-installer.mo index b95f85772912dfea277d7072e729cf56ea5d3984..681a12b64694d81ca6fc0b31eb706feb72fcf136 100644 GIT binary patch delta 16 XcmbQ4Gc#vHuqLyGp26lY&BHtZHd+PI delta 16 XcmbQ4Gc#vHuqLyqp84i5&BHtZHf#me