Third-party artifacts
A server a customer runs downloads things it did not build: firewalls, PHP tooling, a webmail client, container-orchestration binaries, TLS clients, distribution packages. Every one of those downloads is a dependency on somebody else staying online, staying honest and not changing the bytes behind a URL. This page is the inventory of that surface: what moved onto our own mirror with a version and a checksum we compute ourselves, and what still calls out to a third party on purpose, with the reason and what it would take to change that later.
The mechanism, in hitechcloudcli: hitechadmin/config/vendor.json
(hitechcloud-configuration) pins each artifact's version, file name,
upstream URL and a SHA-256 computed by downloading the file and hashing it.
native/vendor.rs's native_vendor::fetch tries
mirrors.hitechcloud.org/vendor/<name>/<file> first, the manifest's url
second, and checks the SHA-256 against whichever source answered — every
time a server fetches the artifact, not once when it was pinned. Nothing
resolves "latest" at install time: picking up a newer release means a
person editing the manifest, computing a new hash, and committing both.
Shell scripts that still need this call the same logic through
hitechcloudcli vendor fetch <name> <dest>.
Moved onto the mirror
| Artifact | Was | Now pinned to |
|---|---|---|
| MailFlow webmail | git clone of the main branch of a personal GitHub account (maathimself/mailflow) — no version, no checksum, the worst case of the lot | 3.5.6 (a real tag) |
| ConfigServer Firewall (csf) | a tarball fetched from a mirror/fallback chain with no checksum at all | 15.10 |
| Composer | getcomposer.org/composer-stable.phar — a floating "stable" alias | 2.10.3 |
| WP-CLI | the gh-pages branch's HEAD phar on mirrors.hitechcloud.org | 2.12.0 |
| Docker Compose (amd64, arm64) | resolved via mirrors.hitechcloud.org/api/repos/docker/compose/releases/latest at every run | 5.5.1 |
| Traefik (amd64, arm64) | releases/latest, or a hardcoded v3.1.4 when that lookup failed | 3.7.13 |
| acme.sh | get.acme.sh, whose --install-online mode re-fetches the current default branch during install | 3.1.6 |
| restic (amd64) | releases/latest, checked against a SHA256SUMS fetched live from the same release | 0.19.1 |
| rclone (amd64) | curl https://rclone.org/install.sh | bash — a third party's script piped straight into a root shell | 1.75.1 |
| ionCube Loader (amd64, arm64) | downloads.ioncube.com, which carries no version in its URL or filename at all | a dated snapshot, pinned 2026-09-24 (loader version 15.5.1 read out of the archive) |
Every checksum above was computed here — the artifact was downloaded and
hashed, not copied from a page. Where the publisher also ships its own
checksum (Docker Compose's .sha256 files, Traefik's checksums.txt,
WP-CLI's .sha256, restic's and rclone's SHA256SUMS), the hash computed
here matched it on the first try; that is a cross-check, not the source of
truth recorded in the manifest.
ionCube is the one entry without a real version to pin: the vendor's own download URL and the archive's filename never change, so there is nothing to pin but the bytes. Re-pinning it later means downloading it again, hashing it again, and recording that day's date — the manifest cannot tell on its own whether a fresh download of that URL is the loader it already has or a new one.
tinyphotogallery, Roundcube and phpMyAdmin are the same mechanism, pinned
in a companion change; they are not covered here.
Public IP self-answered instead of asked of a stranger
Eight call sites asked ip.hitechcloud.org (ours) for the server's public
IP and, when that failed, fell back to ifconfig.me — a stranger's echo
service, for a question a server with a directly assigned public IP (the
normal case here — no NAT) can answer about itself. In seven of the eight,
a local fallback (hostname -I, or reading the global-scope address off
ip addr) already existed one tier further down for exactly this reason;
ifconfig.me was removed from the chain, moving straight from our own
service to the self-answer:
sentinel.rs, user/login.rs, domains/add.rs, user/backup.rs,
user/transfer.rs, user/restore.rs, server/migrate.rs.
The eighth, license.rs, was left alone on purpose. Its public_ip()
feeds /api/license/verify — licence validation needs the address the
outside world actually sees this server at, which a NAT'd or multi-homed
box's local interface address will not always match. Swapping in a local
answer there risks a licence that only functions on directly-addressed
servers by accident and breaks quietly on the ones that are not. A second,
independent external opinion is worth keeping for that one call; if
ifconfig.me itself is a concern there, the fix is a second endpoint we
operate, not a local answer.
Stays remote: package repositories and their GPG keys
Mirroring a curl | bash repo-bootstrap script or a signing key is not the
same job as mirroring a tarball: the repo it configures still has to be
reachable afterwards for every future apt/dnf update, so half-mirroring
it (catching the bootstrap script but not the repository it points at)
removes none of the dependency and adds a second, subtly different copy of
the same trust chain to keep in sync. Properly mirroring an apt/dnf
repository (its Packages/repodata index, every referenced .deb/.rpm,
kept in sync on a schedule, served over the panel's own mirror with its own
signing key) is a real, separate infrastructure project - not something to
half-do inside this one. These all stay remote for that reason:
| Source | Used for | Where |
|---|---|---|
deb.nodesource.com / rpm.nodesource.com | Node.js | native/install.rs, native/install.sh |
dl.cloudsmith.io (Cloudsmith) | Caddy | native/install.rs, native/install.sh, enterprise.rs |
rspamd.com/apt-stable, /rpm-stable, its gpg key | rspamd | native/install.rs, native/install.sh |
rpms.remirepo.net | Remi (PHP on RHEL-family) | native/php.rs |
packages.microsoft.com | MSSQL Server | native/mssql.rs |
repo.mongodb.org, pgp.mongodb.com | MongoDB | native/mongodb.rs |
artifacts.opensearch.org | OpenSearch | native/install.rs, native/install.sh |
artifacts.elastic.co | Elasticsearch | native/install.rs, native/install.sh |
repo.litespeed.sh | LiteSpeed | native/install.rs, native/install.sh |
nginx.org/keys, nginx.org/packages | nginx mainline | native/install.rs, native/install.sh |
packages.sury.org | PHP (Debian/Ubuntu, Sury) | native/php.rs |
get.docker.com/rootless | Docker CE, rootless mode | user/add.sh |
To change this later: stand up a real repository mirror (reposync/aptly or
equivalent, on a schedule, behind mirrors.hitechcloud.org), point one
distro+arch at it as a pilot, and only then rewrite the bootstrap step to
add that repo instead of the vendor's. Until that infrastructure exists,
naming the vendor's own repo URL in an install script is not a design
choice to revisit — it is the only thing that works.
Stays remote: licensed product installers
A second category, related but distinct: install.sh-style bootstrap
scripts for commercial products that are activated against the vendor's own
licence servers, and keep calling home afterwards for updates regardless of
what fetched the installer. Pinning the installer script would not remove
the dependency — the product still phones home to activate and to update
itself — so it would add a stale copy of a script for no real reduction in
the third-party surface:
| Source | Product | Where |
|---|---|---|
repo.cloudlinux.com/cloudlinux/sources/cln/cldeploy | CloudLinux OS | enterprise.rs |
repo.cloudlinux.com/kernelcare/kc-install.sh | KernelCare | enterprise.rs |
repo.jetlicense.com/.../jetapps-repo-latest.{rpm,deb} | JetBackup/JetApps | enterprise.rs |
repo.imunify360.cloudlinux.com/defence360/*-deploy.sh | ImunifyAV / Imunify360 | imunify.rs |
pkg.cpguard.io/installer.sh | cPGuard | enterprise.rs |
files.softaculous.com/install.sh | Softaculous | enterprise.rs |
files.sitepad.com/install.sh | SitePad | enterprise.rs |
To change this later: ask each vendor whether their activation protocol
tolerates a locally-cached installer at all (some tie the installer itself
to a licence key, not just the product afterwards); if one does, pin that
one script the same way vendor.json pins everything else, but the
product's own ongoing calls home stay - there is no local answer for a
licence check by definition.
Stays remote: live data
Some third-party calls are not "download an artifact" at all — the answer has to be whatever is true right now, so a mirror would serve yesterday's answer as if it were today's:
- Cloudflare's IP ranges (
www.cloudflare.com/ips-v4,/ips-v6,enterprise.rs) — used to trustX-Forwarded-Forfrom Cloudflare's edge. Cloudflare adds and retires ranges; serving a stale list either trusts an IP Cloudflare no longer owns or stops trusting one it has just started using. To change this later: nothing to change — this has to be fetched live, on a schedule, for as long as Cloudflare is trusted at all. api.wordpress.org/core/stable-checkand thewordpress.org/wordpress-<ver>.tar.gzit names (websites/wp_autodownload.rs) — a customer creating a new WordPress site is deliberately handed whatever WordPress currently considers stable, not a version this panel picked months ago. Pinning it would defeat the feature's purpose. To change this later: if a slower, reviewed WordPress version ever becomes the intended default, that is a product decision to pin a specific WordPress release deliberately (and it would then belong invendor.jsonlike anything else pinned) - not a mirroring fix.www.php.net/releases/index.php?json(native/phpselector.rs) — feeds the per-version security/EOL score the PHP Selector shows, from PHP's own release and support-window data. That calendar changes as php.net updates it (a branch reaching end of life, a new patch release); a cached copy goes wrong exactly when it matters most - during a security incident. To change this later: nothing to change, for the same reason as above; a periodic local cache with a visible age would be the only safe compromise, not a static mirror.- MTA-STS lookups (
https://<domain>/.well-known/mta-sts.txt,native/mailautoconfig.rs) — these are not requests to one vendor at all; they check whatever policy a customer's own mail domain (or a domain sending it mail) currently publishes, which by design can change at any time and is different for every domain. There is nothing to mirror.
website's own docs.hitechcloud.org links
Comment/help text throughout hitechcloudcli and the panels links to
hitechcloud.org/docs/... and community.hitechcloud.org — this project's
own documentation and forum, not a third party. Not part of this inventory.
Found during this audit, not converted
gist.githubusercontent.com/hitechcloud-vietnam/.../imav_email.sh(imunify.rs, the ImunifyAV virus-notification hook) resolves to a 404 today. Fetching the gist by its ID shows it is owned by a different GitHub account entirely and its content references a different product's paths — a leftover from an early, unfinished rebrand pass that was apparently never updated. This is not a mirroring job: the content itself needs to be rewritten for this project before it is worth hosting anywhere. Left as a bug for a follow-up, not pinned as-is.- The password-strength dictionary (
hitechcloud.org/steveklabnik/password-cracker,user/add.sh) is a static file with no live-data reason to float, andhitechcloudcli vendor-fetch(this change) could serve it. It was not converted here only becauseuser/add.shis a shell-only path this round; a follow-up needs one manifest entry and a one-line edit (wget -qO "$dict" "$url"→hitechcloudcli vendor-fetch password-dictionary "$dict"). - MySQL 8.4 community server (
cdn.mysql.com/dev.mysql.com,native/mysql84.sh) was not converted: it needs a check of Oracle's redistribution terms for the community binaries before anything is re-hosted, which is a legal question, not a technical one, and out of scope for this pass.