* scanopy: use prebuilt server binary, relax release profile for generate-fixtures
* scanopy: drop unneeded rust build, use committed UI fixtures
* scanopy: restore generate-fixtures build, ui/src/lib/data is gitignored and incomplete
* scanopy: serve the UI from the binary, drop the source build
Upstream confirmed in scanopy/scanopy#698 that scanopy-server-linux-*
has carried the built UI since v0.17.13, fixtures and service logos
included, served on the same port as the API. The release notes never
said so, which is why we kept building it.
That removes the source tarball, the Rust toolchain and
generate-fixtures, Node with npm ci and npm run build, and
SCANOPY_WEB_EXTERNAL_PATH. With the variable set to a directory that no
longer has an index.html, v0.17.14 and earlier refuse to start, so the
update deletes the line rather than leaving it. build-essential,
libssl-dev and pkg-config go too: the release binary is static-pie with
no INTERP segment, so it has no runtime library dependencies.
/opt/scanopy stays, now only for .env and oidc.toml, and the unit's
WorkingDirectory follows it out of the removed backend directory. Since
nothing wipes that directory any more, the config survives an update on
its own, which is the report upstream passed on of an update coming
back without SCANOPY_WEB_EXTERNAL_PATH and the server starting API-only.
The update keeps the running binary until the new one answers
/api/health and puts it back if it does not, so a bad release leaves a
working server instead of a stopped one.
check_for_gh_release now keys on scanopy-server, matching the version
file the binary deploy writes; the Scanopy key belonged to the tarball
that is gone. Existing containers run one extra update, then agree.
* Refactor scanopy-install.sh for server setup
Updated installation script to configure Scanopy server and removed daemon configuration section.
* Update service names from 'scanopy-server' to 'Scanopy'
* Fix case sensitivity in fetch_and_deploy_gh_release
* scanopy: make the rollback restore the whole old setup
The health check put the previous binary back but nothing else, and the
source tree it needs was already gone by then: the update deleted
/opt/scanopy/ui before starting the new server, and removed
SCANOPY_WEB_EXTERNAL_PATH from the env at the same time. A failed
health check therefore left the old binary running without the UI it
serves from disk, so the rollback produced an API-only server.
Back up the env file and the unit alongside the binary, restore all
three when the check fails, and delete the source tree only once the
new server has answered. Nothing the old version needs is removed
before the new one has proven itself.
* scanopy: name the deployed binary what the unit starts
singlefile mode writes the asset to <target>/<app name>:
local target_file="$app"
[[ "${USE_ORIGINAL_FILENAME:-false}" == "true" ]] && target_file="$filename"
so with the app renamed to Scanopy the binary lands at /usr/bin/Scanopy
while the unit starts /usr/bin/scanopy-server, and the service never
comes up on a fresh install. Rename it after the deploy, the same way
the daemon block already renames "Scanopy Daemon".
Keeping the app name is what matters here: it is also the version file
(~/.scanopy), and changing it would make every existing container
report an update it does not need.
* immich: keep geodata linked and the build deps present on update
The update wipes $APP_DIR before redeploying, which takes the geodata
symlink the install created with it, and never puts it back. The app
then finds no reverse-geocoding data and the web UI does not come up.
The library recompile assumes headers that only reached the install
list later, so a container built before that fails at the first missing
one - LCMS2 in the reported case.
* immich: keep geodata linked and the build deps present on update
The update wipes $APP_DIR before redeploying, which takes the geodata
symlink the install created with it, and never puts it back. The app
then finds no reverse-geocoding data and the web UI does not come up.
The library recompile assumes headers that only reached the install
list later, so a container built before that fails at the first missing
one - LCMS2 in the reported case.
* Let uv see the project before syncing it
uv refuses to run when a project pins a required-version it does not
match, in either direction: RomM pins ==0.12.13, which fails against
both the 0.10.3 a container was built with and the 0.12.17 latest
installs.
UV_PROJECT_DIR points setup_uv at the project so it reads that pin. It
is a prefix like PYTHON_VERSION and UV_VERSION, and the call sits
directly under fetch_and_deploy: the project is on disk by then, and
the deploy has closed its message block, which setup_uv needs since it
opens one of its own. That is also the only call needed - nothing
between the old early call and the deploy uses uv or Python, so the two
collapse into one.
Two things found along the way:
UV_PYTHON was set as a command prefix on setup_uv in 14 places. setup_uv
reads PYTHON_VERSION, never UV_PYTHON, and a prefix assignment does not
outlive the call, so those pins did nothing. They now use
PYTHON_VERSION, which installs the interpreter they were asking for.
Five update scripts had no setup_uv at all while their install
counterpart pinned a Python version. They now carry the same pin.
immich is left out: it runs uv through sudo -u inside a retry loop.
* yubal: drop the uv 0.7.19 pin
The pin came in with the script and was never explained. uv 0.7.19 is
from 2025-07-02; yubal's uv.lock has carried revision 3 since at least
2025-12-27, and older uv refuses a newer lockfile revision. The script
runs uv sync --frozen, so there is no fallback.
yubal declares no required-version of its own, so latest is what it
gets - and if it ever pins one, that pin is now honoured.
generate-app-headers.sh read APP with a plain grep -oP, so a script that
sets APP twice yielded both lines and the filename became
"almalinux
almalinux${var_version}vm". Three of those are in the tree
and they make main impossible to check out on Windows.
Nothing reads vm/headers: get_header fetches banners from the core
repo, which already carries clean almalinux, debian and ubuntu.
The update script doesn't run `php artisan storage:link`, so the symlink at `public/storage` is left pointing at the old release path after an update. As a result, uploaded images 404 in the frontend until the link is recreated by hand.
This change runs `storage:link` after the release is swapped in, to ensure that the storage path is symlinked correctly.
update_script() compared the upstream tag against /opt/${APP}_version.txt but
never wrote it back, so the stored version stayed at whatever the installer
wrote. Every subsequent run took the update branch, wiping the web root and
re-downloading the full release archive even with no new upstream release.
Write the tag after a successful update, matching what the installer already
does at install/alpine-it-tools-install.sh:42.
Closes#17420
Umami 3.4.0 pins engines.pnpm to 12.3.4. update_script() never
refreshed pnpm, so containers installed with pnpm < 12 fail at
pnpm install with ERR_PNPM_UNSUPPORTED_ENGINE after the service was
already stopped and the old release replaced.
Read engines.pnpm from the deployed package.json and pass it to
setup_nodejs (same approach as ct/seerr.sh), falling back to latest.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Portabase creates the default admin from AUTH_DEFAULT_PASSWORD and checks it
with assertValidPassword (src/utils/password.ts): at least 8 characters, an
uppercase letter, a lowercase letter, a number and a special character. The
generated password is alphanumeric only, so the first start fails with
"Password must contain at least 1 special character".
Generate until each class is present rather than appending fixed characters,
and leave #, $, quotes and backticks out of the charset, because the value is
written unquoted into .env.
Fixes#17370
Co-authored-by: Claude Opus 5 <claude-opus-5@anthropic.com>