feat: add Rocket.Chat LXC script - #2313
william-aqn wants to merge 7 commits into
Conversation
Installs Rocket.Chat 8.8.0 from the official prebuilt Meteor bundle on Debian 13, backed by a local MongoDB 8.0 single-node replica set. Notes on the non-obvious parts, all found while testing against a real Proxmox host: - The bundle is published on releases.rocket.chat, not as a GitHub release asset, so check_for_gh_release/fetch_and_deploy_gh_release cannot be used. /latest/info gives the stable tag as JSON; the GitHub API is unsuitable because backport releases on older majors are published after newer ones and win a "latest" query. - npm is pinned to 10. Under npm 12 the install fails twice over: npm 12 refuses the bundle's remote tarball dependency (EALLOWREMOTE on source-map-support) and the bundle's own npm-rebuild.js calls `npm rebuild --update-binary`, a flag npm 12 rejects. - build-essential is required, not optional: @sematext/gc-stats has no prebuilt binary for Node 22 and falls back to compiling. - MongoDB runs as a replica set because 8.x dropped oplog tailing and now needs change streams and multi-document transactions. MONGO_OPLOG_URL was removed in 8.0 and is deliberately absent. - NSAPP is overridden because variables() only strips spaces, so the dot in "Rocket.Chat" would resolve to install/rocket.chat-install.sh. - Config lives in /etc/rocketchat/rocketchat.env, outside the bundle directory that an update replaces wholesale. Verified end to end on Proxmox VE 9.2.10: clean install in ~4 minutes, web UI answering ~15s after service start, and the update path exercised both when an update is available and when it is not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AGENTS.md and the PR checklist both require the existing helper over a hand-rolled download, and fetch_and_deploy_from_url covers this case: it detects the archive type with file(1) rather than the extension, which matters because the release URL ends in /download and carries no suffix, and it strips the archive's single top-level bundle/ directory into the target. The update path gets CLEAN_INSTALL=1 so a stale bundle cannot survive. Retested end to end after the change: clean install and both update paths. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The wizard cannot be completed on a fresh bare-metal install. Its last step
("Awaiting confirmation") waits on an emailed confirmation code, and the
server has no MAIL_URL, so the mail never leaves the box: the UI sits on
step 4 with an empty address and an empty, disabled security-code field.
The admin account created in step 1 already exists at that point, but
Show_Setup_Wizard stays "in_progress", so logging in only returns to the
dead end.
Reproduced from scratch on a clean container, not inferred: after the
organization step the wizard jumps straight past the Register/Standalone
choice to "Awaiting confirmation", cloud.registerPreIntent returns
{"offline":false,"success":true}, and the server logs an unhandled
rejection from Meteor's email package at the same instant.
So the admin is seeded through Rocket.Chat's own ADMIN_* environment
variables and Show_Setup_Wizard is forced to "completed". Both are
mechanisms the shipped 8.8.0 bundle already implements
(insertAdminUserFromEnv, OVERWRITE_SETTING_*), and insertAdminUserFromEnv
only fires while no admin exists, so they are inert on later boots. The
generated password lands in ~/rocketchat.creds (0600), matching how
dreeve and unsloth surface credentials.
Verified on a clean rebuild: install completes, no wizard is shown, and
POST /api/v1/login with the generated password returns status success.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The admin address was hardcoded to admin@example.com, which every install then had to correct by hand. It now follows the var_ pattern from CONTRIBUTING: read the variable first, prompt only when it is unset, and fall back to a default, so an unattended run is never blocked. The prompt sits before the ~250 MB download rather than next to the config it feeds, so an interactive run is not left waiting minutes for a question. Declared in json as app_vars so the website generator can offer the field. Two details found by testing rather than by reading: `read` needs `|| true`. An unattended run reaches the install script over lxc-attach with no tty, so read hits EOF and returns 1, and the error trap turns that into a failed install before anything is downloaded. Without the guard the default path -- the common one -- dies at line 20. The same bare `read` appears in forgejo-runner-install.sh and valkey-install.sh, and in the CONTRIBUTING example itself. An invalid address is worth catching. Rocket.Chat drops an ADMIN_EMAIL it cannot parse and leaves the admin with no address at all, which is quieter and more confusing than a warning, so a malformed answer falls back. Also adds `|| exit` to the two `cd` calls; shellcheck now reports both scripts clean at warning level (bar SC1090 on the mandated boot line). Verified on clean rebuilds of both paths: var_admin_email=ops@example.net reaches the seeded account in MongoDB, and the unset path completes and logs in with the generated password. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
var_arm64="no" states that arm64 was verified not to work. It was not
verified either way -- the bundle is JS and core resolves MongoDB arm64
from the Ubuntu repo, so it may well work. Unset is what the repo uses for
exactly this case ("unset = ask the user; set yes/no only when verified",
45 scripts against 5), and it lets the engine ask instead of deciding on
the user's behalf. json still declares amd64 only, matching stoatchat,
which is in the same untested state.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Found by a real run, not by review: the Proxmox web console sends a carriage return with the line and read keeps it, so a typed d@x-crm.in arrives as $'d@x-crm.in\r'. \r is in [:space:], so the address failed validation and was silently replaced by the placeholder -- the check meant to catch typos rejected a perfectly good address instead. Stripping whitespace before validating fixes that case and the leading/trailing space variants with it. An email address cannot contain whitespace, so removing it is safe rather than merely convenient. Verified against $'d@x-crm.in\r', both space variants, a genuinely malformed address (still rejected) and the empty answer (still defaults). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AGENTS.md became a work instruction rather than a style guide while this
sat waiting, and two of its new rules apply here.
"Write the Application's Name, Not a Placeholder": the strings this script
author wrote now say Rocket.Chat. The two that stay as ${APP} --
"No ${APP} Installation Found!" and the footer -- are verbatim from the CT
template in AGENTS.md itself, so changing them would diverge from it.
"Deciding var_arm64" forbids leaving the line commented when the answer is
knowable. It is: the shipped bundle carries aarch64 natives next to the
x86-64 ones (node-v127-linux-arm64-glibc/gcstats.node), anything without a
prebuild is compiled by node-gyp, which is why build-essential is a
dependency, and both other layers publish arm64 -- MongoDB 8.0 has 428
arm64 packages in the Ubuntu noble suite core maps Debian arm64 onto, and
NodeSource 22 serves arm64. So yes, with the caveat stated in the PR that
this is reasoned from the artifact and its dependencies, not from a run on
arm64 hardware.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
❌ Pull Request Closed – PR Template Not Used The PR description is missing the 📦 Application Requirements section, which means this PR was not opened with the ProxmoxVED PR template. This usually happens in one of two ways:
The ProxmoxVED template contains required sections (Type of Change, Code & Security Review, Application Requirements, Source) that the maintainers rely on to review submissions. A custom description — no matter how thorough — cannot replace it. What to do
⚠ Maintainer note Please do not ping or repeatedly contact maintainers to reopen this PR. Open a fresh PR with the correct template instead. |
Try this scriptCOMMUNITY_SCRIPTS_URL=https://raw.githubusercontent.com/william-aqn/ProxmoxVED/feat/rocketchat \
bash -c "$(curl -fsSL https://raw.githubusercontent.com/william-aqn/ProxmoxVED/feat/rocketchat/ct/rocketchat.sh)"
Against a core branch as wellAdd Useful flags while testing
|
✍️ Description
Adds
ct/rocketchat.sh,install/rocketchat-install.shandjson/rocketchat.json.Rocket.Chat installed bare-metal from the official prebuilt Meteor bundle on Debian 13, backed by a local MongoDB 8.0 single-node replica set. Defaults 2 CPU / 4096 MB / 20 GB. Config lives in
/etc/rocketchat/rocketchat.env, outside the bundle directory an update replaces wholesale.Supersedes #2250, which I opened while PRs were closed.
Where the install steps came from
Not from the docs: the docs and the shipped code disagree, so the thresholds come out of the bundle itself (
programs/server/app/app.js) and fromreleases.rocket.chat/<version>/info.enginespins 22.22.3, but the server validates only the major line at startup, againstbundle/.node_version.txt. Any 22.x boots./inforeportscompatibleMongoVersions: ["8.0"]; the code hard-exits below 7.0 and warns below 8.0.bundle/README-(cd programs/server && npm install), thennode main.jswithMONGO_URL,ROOT_URL,PORT.Findings worth a reviewer's attention
The setup wizard cannot be completed on a fresh install, so the script skips it. Its last step waits on an emailed confirmation code; a fresh install has no
MAIL_URL, so the mail never leaves the box and the UI sits on step 4 with an empty address and a disabled code field. The admin created in step 1 exists, butShow_Setup_Wizardstaysin_progress, so logging in only returns to the dead end. Reproduced from scratch: after the organization step it jumps past the Register/Standalone choice,cloud.registerPreIntentreturns{"offline":false,"success":true}, and the server logs an unhandled rejection from Meteor's email package at that instant. The script therefore seeds the admin through Rocket.Chat's ownADMIN_*variables and forcesShow_Setup_Wizardtocompleted- both mechanisms the bundle already implements (insertAdminUserFromEnv,OVERWRITE_SETTING_*), and the former only fires while no admin exists, so they stay inert on later boots.No GitHub release assets.
RocketChat/Rocket.Chatreleases carry an emptyassetsarray; the tarball lives only onreleases.rocket.chat.fetch_and_deploy_gh_release/check_for_gh_releasedo not apply, so this usesfetch_and_deploy_from_urlwith the version from/latest/info. The GitHub API is not merely unnecessary but wrong here: backport releases on older majors are published after newer ones (7.10.15 landed after 8.7.1), so/releases/latestcan return a 7.x tag. Two further traps on that host -HEADreturns 404 whileGETreturns 307, so acurl -Iprobe reports a live release as missing; and an unknown version returns 500, not 404.npm pinned to 10 via
NPM_VERSION. Under npm 12 the bundle fails twice over: npm 12 refuses its remote tarball dependency (EALLOWREMOTEonsource-map-support), and the bundle's ownnpm-rebuild.jscallsnpm rebuild --update-binary, which npm 12 rejects.build-essentialis required, not optional.@sematext/gc-statshas no prebuilt binary for Node 22 - node-pre-gyp 404s and it compiles.MongoDB must be a replica set. 8.x dropped oplog tailing and needs change streams and multi-document transactions;
MONGO_OPLOG_URLwas removed in 8.0 and is deliberately absent. Debian 13 works despite MongoDB shipping no trixie server packages - core'smanage_tool_repositorymaps trixie onto bookworm.NSAPPis overridden, asct/netboot-xyz.shdoes, becausevariables()strips only spaces: the dot inRocket.Chatwould otherwise resolve toinstall/rocket.chat-install.sh.One note for the project, not this script: a bare
readbreaks unattended installs. The install script is reached overlxc-attachwith no tty, soreadhits EOF and returns 1 and the error trap fails the install. The prompt here needs|| true. The same bareread -r -pappears ininstall/forgejo-runner-install.sh,install/valkey-install.sh, and the CONTRIBUTING example that documents the pattern.Testing
Proxmox VE 9.2.10, Debian 13 unprivileged LXC, rebuilt from scratch after every correction - most findings above came from a failed run, not from review. Clean install ~4 min; no wizard;
POST /api/v1/loginwith the generated password returnsstatus: success. Both prompt paths rebuilt:var_admin_email=ops@example.netreaches the seeded account in MongoDB, and the unset path defaults and still completes. Update path exercised with an update available and without. Re-verified today against currentmainand Rocket.Chat 8.8.1. shellcheck clean at warning level, bar SC1090 on the mandated boot line.🔗 Related PR / Issue
Link: #2250
✅ Prerequisites (X in brackets)
🏗️ arm64 Support (X in brackets)
var_arm64is set toyes, decided per AGENTS.md rather than left commented: the shipped bundle carries aarch64 natives alongside the x86-64 ones (node-v127-linux-arm64-glibc/gcstats.node), anything without a prebuild is compiled by node-gyp (hencebuild-essential), MongoDB 8.0 has 428 arm64 packages in the Ubuntu noble suite that core maps Debian arm64 onto, and NodeSource 22 serves arm64. That is reasoned from the artifact and its dependencies - I have no arm64 host, so the checkbox above stays honest.🛠️ Type of Change (X in brackets)
README,AppName.md,CONTRIBUTING.md, or other docs.🔍 Code & Security Review (X in brackets)
CODE-AUDIT.md&CONTRIBUTING.mdguidelinesAppName.sh,AppName-install.sh,AppName.json)fetch_and_deploy_from_url.🤖 AI Assistance (X in brackets)
AGENTS.mdand.github/agents/pve-script-creator.agent.mdas guidance, and the output has been reviewed and corrected to match those guidelines.Claude Opus 5, high reasoning effort, used to research the upstream project, write both scripts, and drive the testing against a live Proxmox host, then reviewed and corrected against
AGENTS.mdandCONTRIBUTING.md.This was not one-shot generated. Every version threshold, dependency and failure mode above was established by installing against real hardware, and the container was rebuilt from scratch after each correction. The npm pin, the
build-essentialrequirement, theNSAPPoverride, the move tofetch_and_deploy_from_url, the wizard skip and theread/|| trueguard each came from an observed failure or a guideline check, not from a guess. Re-reviewed against the new bindingAGENTS.mdbefore opening this PR, which is what changedvar_arm64and the placeholder strings.📋 Additional Information (optional)
var_testurlis intentionally unset -sync-testurl.ymlfills it in once a testing issue is labelled.🤖 Generated with Claude Code