feat(install): install PostgreSQL 18 from PGDG for new local databases

The local PostgreSQL setup installed whatever the distro metapackage pointed
at, so Ubuntu 22.04 got 14 (EOL Nov 2026), Debian 12 got 15 and EL9 got 13.
Servers ended up on different majors, and a pg_dump backup taken on a newer
server does not restore onto an older one.

New installs now add the official PGDG repository and install
PostgreSQL 18 (apt on Debian/Ubuntu, dnf on EL 8+ with the AppStream module
disabled, postgresql-18 service and /var/lib/pgsql/18/data). Where PGDG has
no build (Ubuntu 20.04, Debian 11, armhf/i386/s390x, EL7, Fedora, Amazon
Linux, older EL point releases) the repository change is rolled back and
the distro package is installed as before. A host that already has a
cluster keeps it, so existing installs are never upgraded.

x-ui.sh resolves the postgresql-18 unit on EL for start/stop/log and also
removes the PGDG packages on purge.

Verified in containers: Ubuntu 22.04/24.04, Debian 12, Rocky 8/9 and
AlmaLinux 10 get 18.6; Ubuntu 20.04 falls back to 12 and Debian 12 armv7 to
15 with apt-get update still clean; Ubuntu 22.04 with an existing 14 cluster
stays on 14. The CI PostgreSQL test set passes against postgres:18.
This commit is contained in:
MHSanaei
2026-10-06 14:13:34 +02:00
parent 6be3c438e1
commit c9207b6f3e
2 changed files with 149 additions and 25 deletions
+71 -11
View File
@@ -208,6 +208,60 @@ pg_ensure_hba_password_auth() {
sudo -u postgres psql -tAc 'SELECT pg_reload_conf()' > /dev/null 2>&1 || true
}
# New installs get this PostgreSQL major from the official PGDG repository; distros or
# CPU architectures PGDG does not build for fall back to the distribution's own package.
PG_TARGET_MAJOR=18
pg_has_debian_cluster() {
command -v pg_lsclusters > /dev/null 2>&1 && [[ -n "$(pg_lsclusters -h 2> /dev/null)" ]]
}
# Installs postgresql-${PG_TARGET_MAJOR} from apt.postgresql.org. On failure it removes the
# repository it added, so an unsupported release cannot break later `apt-get update` runs.
pg_apt_install_pgdg_server() {
local list added_lists=()
for list in /etc/apt/sources.list.d/pgdg.list /etc/apt/sources.list.d/pgdg.sources; do
[[ -e "${list}" ]] || added_lists+=("${list}")
done
if apt-get install -y -q postgresql-common ca-certificates gnupg >&2 \
&& /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y >&2 \
&& apt-get install -y -q "postgresql-${PG_TARGET_MAJOR}" >&2; then
return 0
fi
for list in "${added_lists[@]}"; do
rm -f "${list}"
done
apt-get update >&2 || true
echo -e "${yellow}PostgreSQL ${PG_TARGET_MAJOR} is not available for this system; installing the distribution's PostgreSQL instead.${plain}" >&2
return 1
}
# Installs postgresql${PG_TARGET_MAJOR}-server from the PGDG yum repository (EL 8+ only); on
# failure it undoes the repository and module changes it made. The caller runs initdb.
pg_el_install_pgdg_server() {
local elver
elver=$(rpm -E %rhel 2> /dev/null)
[[ "${elver}" =~ ^[0-9]+$ && "${elver}" -ge 8 ]] && command -v dnf > /dev/null 2>&1 || return 1
[[ -f /var/lib/pgsql/data/PG_VERSION ]] && return 1
local added_repo=false
if ! rpm -q pgdg-redhat-repo > /dev/null 2>&1; then
if dnf install -y -q "https://download.postgresql.org/pub/repos/yum/reporpms/EL-${elver}-$(uname -m)/pgdg-redhat-repo-latest.noarch.rpm" >&2; then
added_repo=true
dnf -qy module disable postgresql > /dev/null 2>&1 || true
fi
fi
if rpm -q pgdg-redhat-repo > /dev/null 2>&1 \
&& dnf install -y -q "postgresql${PG_TARGET_MAJOR}-server" "postgresql${PG_TARGET_MAJOR}-contrib" >&2; then
return 0
fi
if [[ "${added_repo}" == "true" ]]; then
dnf -qy module reset postgresql > /dev/null 2>&1 || true
dnf remove -y -q pgdg-redhat-repo >&2 || true
fi
echo -e "${yellow}PostgreSQL ${PG_TARGET_MAJOR} is not available for this system; installing the distribution's PostgreSQL instead.${plain}" >&2
return 1
}
install_postgres_local() {
local pg_user pg_pass
pg_pass=$(gen_random_string 24)
@@ -215,21 +269,27 @@ install_postgres_local() {
local pg_host="127.0.0.1"
local pg_port="5432"
local pg_service="postgresql"
case "${release}" in
ubuntu | debian | armbian)
apt-get update >&2 && apt-get install -y -q postgresql >&2 || return 1
apt-get update >&2 || return 1
if pg_has_debian_cluster || ! pg_apt_install_pgdg_server; then
apt-get install -y -q postgresql >&2 || return 1
fi
;;
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
dnf install -y -q postgresql-server postgresql-contrib >&2 || return 1
[[ -d /var/lib/pgsql/data && -f /var/lib/pgsql/data/PG_VERSION ]] || postgresql-setup --initdb >&2 || return 1
;;
centos)
if [[ "${VERSION_ID}" =~ ^7 ]]; then
yum install -y postgresql-server postgresql-contrib >&2 || return 1
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol | centos)
if [[ "${release}" != "fedora" && "${release}" != "amzn" ]] && pg_el_install_pgdg_server; then
pg_service="postgresql-${PG_TARGET_MAJOR}"
[[ -f "/var/lib/pgsql/${PG_TARGET_MAJOR}/data/PG_VERSION" ]] \
|| "/usr/pgsql-${PG_TARGET_MAJOR}/bin/postgresql-${PG_TARGET_MAJOR}-setup" initdb >&2 || return 1
else
dnf install -y -q postgresql-server postgresql-contrib >&2 || return 1
if [[ "${release}" == "centos" && "${VERSION_ID}" =~ ^7 ]]; then
yum install -y postgresql-server postgresql-contrib >&2 || return 1
else
dnf install -y -q postgresql-server postgresql-contrib >&2 || return 1
fi
[[ -d /var/lib/pgsql/data && -f /var/lib/pgsql/data/PG_VERSION ]] || postgresql-setup --initdb >&2 || return 1
fi
[[ -d /var/lib/pgsql/data && -f /var/lib/pgsql/data/PG_VERSION ]] || postgresql-setup --initdb >&2 || return 1
;;
arch | manjaro | parch)
pacman -Sy --noconfirm postgresql >&2 || return 1
@@ -259,7 +319,7 @@ install_postgres_local() {
esac
if [[ "${release}" != "alpine" ]]; then
systemctl enable --now postgresql >&2 || return 1
systemctl enable --now "${pg_service}" >&2 || return 1
fi
# Wait briefly for the server to accept connections.
+78 -14
View File
@@ -2738,6 +2738,8 @@ pg_systemd_unit() {
ver="${info%% *}"
cluster="${info##* }"
echo "postgresql@${ver}-${cluster}"
elif [[ -f "/usr/lib/systemd/system/postgresql-${PG_TARGET_MAJOR}.service" ]]; then
echo "postgresql-${PG_TARGET_MAJOR}"
else
echo "postgresql"
fi
@@ -2860,19 +2862,21 @@ purge_postgresql() {
systemctl disable "$(pg_systemd_unit)" 2> /dev/null
fi
local pgdg_pkgs=()
command -v rpm > /dev/null 2>&1 && mapfile -t pgdg_pkgs < <(rpm -qa --qf '%{NAME}\n' "postgresql${PG_TARGET_MAJOR}*")
case "${release}" in
ubuntu | debian | armbian)
apt-get -y --purge remove 'postgresql*'
apt-get -y autoremove --purge
;;
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
dnf remove -y postgresql postgresql-server postgresql-contrib
dnf remove -y postgresql postgresql-server postgresql-contrib "${pgdg_pkgs[@]}"
;;
centos)
if [[ "${VERSION_ID}" =~ ^7 ]]; then
yum remove -y postgresql postgresql-server postgresql-contrib
else
dnf remove -y postgresql postgresql-server postgresql-contrib
dnf remove -y postgresql postgresql-server postgresql-contrib "${pgdg_pkgs[@]}"
fi
;;
arch | manjaro | parch)
@@ -2925,6 +2929,60 @@ pg_ensure_hba_password_auth() {
sudo -u postgres psql -tAc 'SELECT pg_reload_conf()' > /dev/null 2>&1 || true
}
# New installs get this PostgreSQL major from the official PGDG repository; distros or
# CPU architectures PGDG does not build for fall back to the distribution's own package.
PG_TARGET_MAJOR=18
pg_has_debian_cluster() {
command -v pg_lsclusters > /dev/null 2>&1 && [[ -n "$(pg_lsclusters -h 2> /dev/null)" ]]
}
# Installs postgresql-${PG_TARGET_MAJOR} from apt.postgresql.org. On failure it removes the
# repository it added, so an unsupported release cannot break later `apt-get update` runs.
pg_apt_install_pgdg_server() {
local list added_lists=()
for list in /etc/apt/sources.list.d/pgdg.list /etc/apt/sources.list.d/pgdg.sources; do
[[ -e "${list}" ]] || added_lists+=("${list}")
done
if apt-get install -y -q postgresql-common ca-certificates gnupg >&2 \
&& /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y >&2 \
&& apt-get install -y -q "postgresql-${PG_TARGET_MAJOR}" >&2; then
return 0
fi
for list in "${added_lists[@]}"; do
rm -f "${list}"
done
apt-get update >&2 || true
echo -e "${yellow}PostgreSQL ${PG_TARGET_MAJOR} is not available for this system; installing the distribution's PostgreSQL instead.${plain}" >&2
return 1
}
# Installs postgresql${PG_TARGET_MAJOR}-server from the PGDG yum repository (EL 8+ only); on
# failure it undoes the repository and module changes it made. The caller runs initdb.
pg_el_install_pgdg_server() {
local elver
elver=$(rpm -E %rhel 2> /dev/null)
[[ "${elver}" =~ ^[0-9]+$ && "${elver}" -ge 8 ]] && command -v dnf > /dev/null 2>&1 || return 1
[[ -f /var/lib/pgsql/data/PG_VERSION ]] && return 1
local added_repo=false
if ! rpm -q pgdg-redhat-repo > /dev/null 2>&1; then
if dnf install -y -q "https://download.postgresql.org/pub/repos/yum/reporpms/EL-${elver}-$(uname -m)/pgdg-redhat-repo-latest.noarch.rpm" >&2; then
added_repo=true
dnf -qy module disable postgresql > /dev/null 2>&1 || true
fi
fi
if rpm -q pgdg-redhat-repo > /dev/null 2>&1 \
&& dnf install -y -q "postgresql${PG_TARGET_MAJOR}-server" "postgresql${PG_TARGET_MAJOR}-contrib" >&2; then
return 0
fi
if [[ "${added_repo}" == "true" ]]; then
dnf -qy module reset postgresql > /dev/null 2>&1 || true
dnf remove -y -q pgdg-redhat-repo >&2 || true
fi
echo -e "${yellow}PostgreSQL ${PG_TARGET_MAJOR} is not available for this system; installing the distribution's PostgreSQL instead.${plain}" >&2
return 1
}
# Installs a local PostgreSQL server and creates a dedicated xui user/database.
# Progress goes to stderr; on success the connection DSN is printed to stdout so
# callers can capture it. Mirrors install_postgres_local() from install.sh, so the
@@ -2936,21 +2994,27 @@ pg_install_local() {
pg_host="127.0.0.1"
pg_port="5432"
local pg_service="postgresql"
case "${release}" in
ubuntu | debian | armbian)
apt-get update >&2 && apt-get install -y -q postgresql >&2 || return 1
apt-get update >&2 || return 1
if pg_has_debian_cluster || ! pg_apt_install_pgdg_server; then
apt-get install -y -q postgresql >&2 || return 1
fi
;;
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
dnf install -y -q postgresql-server postgresql-contrib >&2 || return 1
[[ -d /var/lib/pgsql/data && -f /var/lib/pgsql/data/PG_VERSION ]] || postgresql-setup --initdb >&2 || return 1
;;
centos)
if [[ "${VERSION_ID}" =~ ^7 ]]; then
yum install -y postgresql-server postgresql-contrib >&2 || return 1
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol | centos)
if [[ "${release}" != "fedora" && "${release}" != "amzn" ]] && pg_el_install_pgdg_server; then
pg_service="postgresql-${PG_TARGET_MAJOR}"
[[ -f "/var/lib/pgsql/${PG_TARGET_MAJOR}/data/PG_VERSION" ]] \
|| "/usr/pgsql-${PG_TARGET_MAJOR}/bin/postgresql-${PG_TARGET_MAJOR}-setup" initdb >&2 || return 1
else
dnf install -y -q postgresql-server postgresql-contrib >&2 || return 1
if [[ "${release}" == "centos" && "${VERSION_ID}" =~ ^7 ]]; then
yum install -y postgresql-server postgresql-contrib >&2 || return 1
else
dnf install -y -q postgresql-server postgresql-contrib >&2 || return 1
fi
[[ -d /var/lib/pgsql/data && -f /var/lib/pgsql/data/PG_VERSION ]] || postgresql-setup --initdb >&2 || return 1
fi
[[ -d /var/lib/pgsql/data && -f /var/lib/pgsql/data/PG_VERSION ]] || postgresql-setup --initdb >&2 || return 1
;;
arch | manjaro | parch)
pacman -Sy --noconfirm postgresql >&2 || return 1
@@ -2980,7 +3044,7 @@ pg_install_local() {
esac
if [[ "${release}" != "alpine" ]]; then
systemctl enable --now postgresql >&2 || return 1
systemctl enable --now "${pg_service}" >&2 || return 1
fi
local i
@@ -3090,7 +3154,7 @@ pg_upgrade_client() {
apt-get install -y -q postgresql-client >&2 || return 1
elif ! apt-get install -y -q "postgresql-client-${want}" >&2; then
LOGI "postgresql-client-${want} is not in the distribution repositories; adding the official PostgreSQL apt repository..."
apt-get install -y -q postgresql-common ca-certificates >&2 || return 1
apt-get install -y -q postgresql-common ca-certificates gnupg >&2 || return 1
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y >&2 || return 1
apt-get install -y -q "postgresql-client-${want}" >&2 || return 1
fi