|
@@ -111,10 +111,12 @@ gen_random_string() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
install_postgres_local() {
|
|
install_postgres_local() {
|
|
|
- local pg_user="xui"
|
|
|
|
|
- local pg_db="xui"
|
|
|
|
|
- local pg_pass
|
|
|
|
|
|
|
+ local pg_user pg_pass
|
|
|
|
|
+ pg_user=$(gen_random_string 8)
|
|
|
pg_pass=$(gen_random_string 24)
|
|
pg_pass=$(gen_random_string 24)
|
|
|
|
|
+ local pg_db="xui"
|
|
|
|
|
+ local pg_host="127.0.0.1"
|
|
|
|
|
+ local pg_port="5432"
|
|
|
|
|
|
|
|
case "${release}" in
|
|
case "${release}" in
|
|
|
ubuntu | debian | armbian)
|
|
ubuntu | debian | armbian)
|
|
@@ -170,20 +172,34 @@ install_postgres_local() {
|
|
|
sleep 1
|
|
sleep 1
|
|
|
done
|
|
done
|
|
|
|
|
|
|
|
- # Idempotent role/db creation.
|
|
|
|
|
|
|
+ # Idempotent role/db creation. Identifiers are double-quoted because a
|
|
|
|
|
+ # random username may start with a digit, which Postgres rejects unquoted.
|
|
|
sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${pg_user}'" 2> /dev/null \
|
|
sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${pg_user}'" 2> /dev/null \
|
|
|
| grep -q 1 \
|
|
| grep -q 1 \
|
|
|
- || sudo -u postgres psql -c "CREATE USER ${pg_user} WITH PASSWORD '${pg_pass}';" >&2 || return 1
|
|
|
|
|
|
|
+ || sudo -u postgres psql -c "CREATE USER \"${pg_user}\" WITH PASSWORD '${pg_pass}';" >&2 || return 1
|
|
|
|
|
|
|
|
sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${pg_db}'" 2> /dev/null \
|
|
sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${pg_db}'" 2> /dev/null \
|
|
|
| grep -q 1 \
|
|
| grep -q 1 \
|
|
|
- || sudo -u postgres psql -c "CREATE DATABASE ${pg_db} OWNER ${pg_user};" >&2 || return 1
|
|
|
|
|
|
|
+ || sudo -u postgres psql -c "CREATE DATABASE \"${pg_db}\" OWNER \"${pg_user}\";" >&2 || return 1
|
|
|
|
|
|
|
|
- sudo -u postgres psql -c "ALTER USER ${pg_user} WITH PASSWORD '${pg_pass}';" >&2 || return 1
|
|
|
|
|
|
|
+ sudo -u postgres psql -c "ALTER USER \"${pg_user}\" WITH PASSWORD '${pg_pass}';" >&2 || return 1
|
|
|
|
|
|
|
|
local pg_pass_enc
|
|
local pg_pass_enc
|
|
|
pg_pass_enc=$(printf '%s' "${pg_pass}" | sed -e 's/%/%25/g' -e 's/:/%3A/g' -e 's/@/%40/g' -e 's|/|%2F|g' -e 's/?/%3F/g' -e 's/#/%23/g')
|
|
pg_pass_enc=$(printf '%s' "${pg_pass}" | sed -e 's/%/%25/g' -e 's/:/%3A/g' -e 's/@/%40/g' -e 's|/|%2F|g' -e 's/?/%3F/g' -e 's/#/%23/g')
|
|
|
- echo "postgres://${pg_user}:${pg_pass_enc}@127.0.0.1:5432/${pg_db}?sslmode=disable"
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if [[ -n "${PG_CRED_FILE:-}" ]]; then
|
|
|
|
|
+ umask 077
|
|
|
|
|
+ cat > "${PG_CRED_FILE}" <<EOF
|
|
|
|
|
+PG_USER=${pg_user}
|
|
|
|
|
+PG_PASS=${pg_pass}
|
|
|
|
|
+PG_HOST=${pg_host}
|
|
|
|
|
+PG_PORT=${pg_port}
|
|
|
|
|
+PG_DB=${pg_db}
|
|
|
|
|
+EOF
|
|
|
|
|
+ umask 022
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ echo "postgres://${pg_user}:${pg_pass_enc}@${pg_host}:${pg_port}/${pg_db}?sslmode=disable"
|
|
|
return 0
|
|
return 0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -823,7 +839,7 @@ config_after_install() {
|
|
|
echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
|
echo -e "${green} Database Selection ${plain}"
|
|
echo -e "${green} Database Selection ${plain}"
|
|
|
echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
|
- echo -e " 1) SQLite (default — recommended for < 1000 clients)"
|
|
|
|
|
|
|
+ echo -e " 1) SQLite (default — recommended for < 500 clients)"
|
|
|
echo -e " 2) PostgreSQL (recommended for high client counts / many nodes)"
|
|
echo -e " 2) PostgreSQL (recommended for high client counts / many nodes)"
|
|
|
read -rp "Choose [1]: " db_choice
|
|
read -rp "Choose [1]: " db_choice
|
|
|
db_choice="${db_choice:-1}"
|
|
db_choice="${db_choice:-1}"
|
|
@@ -843,6 +859,7 @@ config_after_install() {
|
|
|
|
|
|
|
|
local xui_dsn=""
|
|
local xui_dsn=""
|
|
|
local pg_mode=""
|
|
local pg_mode=""
|
|
|
|
|
+ local pg_local_installed=0
|
|
|
while [[ -z "$xui_dsn" ]]; do
|
|
while [[ -z "$xui_dsn" ]]; do
|
|
|
echo ""
|
|
echo ""
|
|
|
echo -e " 1) Install PostgreSQL locally and create a dedicated user/db (recommended)"
|
|
echo -e " 1) Install PostgreSQL locally and create a dedicated user/db (recommended)"
|
|
@@ -857,8 +874,17 @@ config_after_install() {
|
|
|
db_label="PostgreSQL (external)"
|
|
db_label="PostgreSQL (external)"
|
|
|
else
|
|
else
|
|
|
echo -e "${yellow}Installing PostgreSQL — this may take a moment...${plain}"
|
|
echo -e "${yellow}Installing PostgreSQL — this may take a moment...${plain}"
|
|
|
- if xui_dsn=$(install_postgres_local); then
|
|
|
|
|
- db_label="PostgreSQL ([email protected]:5432/xui)"
|
|
|
|
|
|
|
+ local pg_cred_file
|
|
|
|
|
+ pg_cred_file="/tmp/x-ui-pg-creds.$$"
|
|
|
|
|
+ rm -f "${pg_cred_file}"
|
|
|
|
|
+ if xui_dsn=$(PG_CRED_FILE="${pg_cred_file}" install_postgres_local); then
|
|
|
|
|
+ pg_local_installed=1
|
|
|
|
|
+ if [[ -r "${pg_cred_file}" ]]; then
|
|
|
|
|
+ # shellcheck disable=SC1090
|
|
|
|
|
+ source "${pg_cred_file}"
|
|
|
|
|
+ rm -f "${pg_cred_file}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ db_label="PostgreSQL (${PG_USER}@${PG_HOST}:${PG_PORT}/${PG_DB})"
|
|
|
else
|
|
else
|
|
|
echo ""
|
|
echo ""
|
|
|
echo -e "${red}PostgreSQL installation failed.${plain}"
|
|
echo -e "${red}PostgreSQL installation failed.${plain}"
|
|
@@ -870,8 +896,15 @@ config_after_install() {
|
|
|
pg_fail="${pg_fail:-1}"
|
|
pg_fail="${pg_fail:-1}"
|
|
|
case "$pg_fail" in
|
|
case "$pg_fail" in
|
|
|
2) pg_mode="2" ;;
|
|
2) pg_mode="2" ;;
|
|
|
- 3) echo -e "${red}Install aborted.${plain}"; exit 1 ;;
|
|
|
|
|
- 4) db_choice="1"; xui_dsn=""; break ;;
|
|
|
|
|
|
|
+ 3)
|
|
|
|
|
+ echo -e "${red}Install aborted.${plain}"
|
|
|
|
|
+ exit 1
|
|
|
|
|
+ ;;
|
|
|
|
|
+ 4)
|
|
|
|
|
+ db_choice="1"
|
|
|
|
|
+ xui_dsn=""
|
|
|
|
|
+ break
|
|
|
|
|
+ ;;
|
|
|
*) xui_dsn="" ;;
|
|
*) xui_dsn="" ;;
|
|
|
esac
|
|
esac
|
|
|
fi
|
|
fi
|
|
@@ -935,6 +968,28 @@ EOF
|
|
|
else
|
|
else
|
|
|
echo -e "${yellow}⚠ SSL Certificate: Skipped — panel is HTTP-only. Use a reverse proxy or SSH tunnel.${plain}"
|
|
echo -e "${yellow}⚠ SSL Certificate: Skipped — panel is HTTP-only. Use a reverse proxy or SSH tunnel.${plain}"
|
|
|
fi
|
|
fi
|
|
|
|
|
+
|
|
|
|
|
+ if [[ "$db_choice" == "2" && "$pg_local_installed" == "1" ]]; then
|
|
|
|
|
+ echo ""
|
|
|
|
|
+ echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
|
|
|
+ echo -e "${green} PostgreSQL Credentials ${plain}"
|
|
|
|
|
+ echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
|
|
|
+ echo -e "${green}DB Name: ${PG_DB}${plain}"
|
|
|
|
|
+ echo -e "${green}Username: ${PG_USER}${plain}"
|
|
|
|
|
+ echo -e "${green}Password: ${PG_PASS}${plain}"
|
|
|
|
|
+ echo -e "${green}Host: ${PG_HOST}${plain}"
|
|
|
|
|
+ echo -e "${green}Port: ${PG_PORT}${plain}"
|
|
|
|
|
+ echo -e "${green}DSN: ${xui_dsn}${plain}"
|
|
|
|
|
+ echo -e "${green}Env file: ${xui_env_file}${plain}"
|
|
|
|
|
+ echo -e "${green}-------------------------------------------${plain}"
|
|
|
|
|
+ echo -e "${green}Connect from this server:${plain}"
|
|
|
|
|
+ echo -e " ${blue}sudo -u postgres psql -d ${PG_DB}${plain} (as the postgres superuser)"
|
|
|
|
|
+ echo -e " ${blue}PGPASSWORD='${PG_PASS}' psql -h ${PG_HOST} -p ${PG_PORT} -U ${PG_USER} -d ${PG_DB}${plain}"
|
|
|
|
|
+ echo -e "${green}═══════════════════════════════════════════${plain}"
|
|
|
|
|
+ echo -e "${yellow}⚠ The panel reads these credentials from ${xui_env_file}.${plain}"
|
|
|
|
|
+ echo -e "${yellow}⚠ Save the password — it is not stored anywhere else in plain text.${plain}"
|
|
|
|
|
+ unset PG_USER PG_PASS PG_HOST PG_PORT PG_DB
|
|
|
|
|
+ fi
|
|
|
else
|
|
else
|
|
|
local config_webBasePath=$(gen_random_string 18)
|
|
local config_webBasePath=$(gen_random_string 18)
|
|
|
echo -e "${yellow}WebBasePath is missing or too short. Generating a new one...${plain}"
|
|
echo -e "${yellow}WebBasePath is missing or too short. Generating a new one...${plain}"
|