@@ -6,23 +6,37 @@ set -euo pipefail
66
77export DEBIAN_FRONTEND=noninteractive
88
9- # Kill unattended-upgrades and wait for any running apt/dpkg to finish.
10- # Fresh VPS instances often have unattended-upgrades holding apt locks.
9+ # Wait for cloud-init to finish — it triggers apt operations on fresh VPS instances.
10+ if command -v cloud-init > /dev/null 2>&1 ; then
11+ echo " ==> Waiting for cloud-init to finish (max 5 minutes)"
12+ if timeout 300s cloud-init status --wait; then
13+ echo " cloud-init finished successfully"
14+ else
15+ echo " WARNING: cloud-init wait exited with code $? " >&2
16+ fi
17+ fi
18+
19+ # Stop unattended-upgrades so it doesn't race with our apt-get calls.
20+ # We mask it during provisioning but re-enable at the end of the script
21+ # so the final image still receives automatic security updates.
1122echo " ==> Stopping unattended-upgrades"
1223systemctl stop unattended-upgrades.service 2> /dev/null || true
24+ systemctl mask unattended-upgrades.service 2> /dev/null || true
1325systemctl kill --signal=TERM apt-daily.service 2> /dev/null || true
1426systemctl kill --signal=TERM apt-daily-upgrade.service 2> /dev/null || true
27+ # Kill any lingering apt/unattended-upgrade processes (but not dpkg — killing
28+ # dpkg mid-transaction can corrupt the package database).
29+ killall -9 apt-get unattended-upgrade 2> /dev/null || true
30+ sleep 2
1531
16- # Wait for any lingering dpkg/apt processes to exit
17- while fuser /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock > /dev/null 2>&1 ; do
18- echo " Waiting for apt/dpkg locks..."
19- sleep 3
20- done
32+ # Use apt-get's built-in lock timeout (wait up to 5 minutes for locks to clear)
33+ # instead of a fragile fuser loop that can race between update and install.
34+ APT_OPTS=(-o DPkg::Lock::Timeout=300)
2135
2236echo " ==> Installing runtime dependencies"
23- apt-get update -q
37+ apt-get " ${APT_OPTS[@]} " update -q
2438# Keep this package list in sync with Dockerfile
25- apt-get install -y -q \
39+ apt-get " ${APT_OPTS[@]} " install -y -q \
2640 ca-certificates \
2741 tzdata \
2842 nftables
@@ -35,7 +49,7 @@ echo " URL: ${deb_url}"
3549curl -fsSL -o " /tmp/${deb_name} " " ${deb_url} "
3650
3751echo " ==> Installing ${deb_name} "
38- dpkg -i " /tmp/${deb_name} "
52+ apt-get " ${APT_OPTS[@]} " install -y -q " /tmp/${deb_name} "
3953rm -f " /tmp/${deb_name} "
4054
4155# The .deb installs the binary as /usr/bin/sing-box-extensions.
@@ -67,7 +81,7 @@ otelcol_deb="otelcol-contrib_${otelcol_version}_linux_${arch}.deb"
6781otelcol_url=" https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${otelcol_version} /${otelcol_deb} "
6882echo " URL: ${otelcol_url} "
6983curl -fsSL -o " /tmp/${otelcol_deb} " " ${otelcol_url} "
70- dpkg -i " /tmp/${otelcol_deb} "
84+ apt-get " ${APT_OPTS[@]} " install -y -q " /tmp/${otelcol_deb} "
7185rm -f " /tmp/${otelcol_deb} "
7286
7387# Copy our config into the otelcol-contrib config directory.
@@ -88,6 +102,10 @@ DROPIN
88102systemctl daemon-reload
89103# Do NOT enable — cloud-init writes env vars first, then enables the service.
90104
105+ # Re-enable unattended-upgrades so the final image receives security updates.
106+ systemctl unmask unattended-upgrades.service 2> /dev/null || true
107+ systemctl enable unattended-upgrades.service 2> /dev/null || true
108+
91109echo " ==> Verifying installation"
92110if ! command -v lantern-box > /dev/null 2>&1 ; then
93111 echo " lantern-box not found on PATH" >&2
0 commit comments