unraid / unraid/api

Bug: Plugin installs fail with "is not a plg file" and downloader doesn't follow `ca.unraid.net/dl` redirect

Open
#2,088 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
113
Forks
22
Avg merge
10h 40m
Merged PRs (30d)
13

Description

Summary

Since plugin installs began routing through the https://ca.unraid.net/dl/<source-url> proxy, almost all plugin installs fail with:

Downloading plugin
plugin: <random-hash-string> is not a plg file
Plugin installed

The plugin is not actually installed, despite the misleading "Plugin installed" line. Docker app installs via Community Applications seem to be unaffected, only .plg plugin installs.

Root cause

ca.unraid.net/dl/ correctly issues an HTTP 302 redirect to the real source URL (e.g. raw.githubusercontent.com). Whatever HTTP client Unraid's plugin-install code uses to fetch the .plg file is not following that redirect. Instead, it saves the 302 response's HTML body (a <meta http-equiv="refresh"> stub) to disk, which then fails plg/XML validation, hence the "is not a plg file" error. The install routine still reports success because the download-failure path and the "installed" message aren't gated on the same check.

Reproduction

Tested directly against the proxy from an Unraid 7.4.0-beta.2 host via SSH, isolating the proxy/redirect from Unraid's own downloader:

1. Request the well-formed proxy URL without following redirects (mirrors what appears to be happening internally):

curl -v -o /tmp/test-proxy.plg "https://ca.unraid.net/dl/https://raw.githubusercontent.com/Squidly271/user.scripts/master/plugins/user.scripts.plg"
head -20 /tmp/test-proxy.plg

Result: HTTP/2 302, with a correct absolute Location header:

location: https://raw.githubusercontent.com/Squidly271/user.scripts/master/plugins/user.scripts.plg

But the saved file content is just:

<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=https://raw.githubusercontent.com/Squidly271/user.scripts/master/plugins/user.scripts.plg"></head></html>

this is not valid .plg XML.

2. Same URL, but following the redirect (-L):

curl -sL -o /tmp/test-follow.plg "https://ca.unraid.net/dl/https://raw.githubusercontent.com/Squidly271/user.scripts/master/plugins/user.scripts.plg"
head -20 /tmp/test-follow.plg

Result: valid .plg XML is returned cleanly:

<?xml version='1.0' standalone='yes'?>
<!DOCTYPE PLUGIN [
<!ENTITY name      "user.scripts">
<!ENTITY author    "Andrew Zawadzki">
<!ENTITY version   "2025.06.21">
<!ENTITY md5       "652ad83eb3369d1603a289f01b40307d">
<!ENTITY launch    "Settings/Userscripts">
<!ENTITY plugdir   "/usr/local/emhttp/plugins/&name;">
<!ENTITY github    "Squidly271/user.scripts">
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/master/plugins/&name;.plg">
]>

<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;" pluginURL="&pluginURL;" min="6.3.3" icon="file-text-o">

Conclusion: the proxy and the origin (GitHub) both behave correctly. The only variable that determines success vs. failure is whether the HTTP client follows the redirect. This isolates the defect to Unraid's plugin-download code not following redirects issued by ca.unraid.net/dl, which is most likely a missing CURLOPT_FOLLOWLOCATION => true (if using PHP curl) or equivalent redirect-following configuration in the fetch call.

Environment

  • Unraid OS: 7.4.0-beta.2
  • Verified via direct curl testing over SSH, bypassing the WebUI to isolate proxy vs. downloader behavior
  • TLS/DNS/network path confirmed healthy: valid certs, correct resolution, no interception, in both directions (raw.githubusercontent.com direct and ca.unraid.net proxied)

Impact

  • Affects installation of essentially all Community Applications plugins (not Docker apps, which use a separate Docker-registry pull path unaffected by this proxy)
  • Misleading "Plugin installed" message on failure makes the problem harder for affected users to diagnose and the plugin silently does not install

Related reports

Other users have reported the identical symptom (same garbled hashed filename pattern, same false "Plugin installed" message) in the Unraid forums, generally resolving on their own after a period of time which is consistent with this being an intermittent or recently-introduced regression rather than a permanent block:

Suspected origin of the regression

Plugin installs began routing through ca.unraid.net/dl/ following unraid/api PR #2000 (merged May 11, 2026), which introduced this proxy for onboarding-flow plugin installs. If this proxying was later extended to general Community Applications plugin installs without the corresponding downloader code being updated to follow redirects, that would explain both the timing and the breadth of the failures.

Suggested fix

Ensure the plugin-install download call follows HTTP redirects (e.g. CURLOPT_FOLLOWLOCATION => true plus a sane CURLOPT_MAXREDIRS, if using PHP curl), or have ca.unraid.net/dl return the proxied file content directly (HTTP 200 passthrough) instead of a redirect, if client-side changes aren't feasible.

Workaround

Bypass the proxy entirely by installing plugins using their raw source URL directly (e.g. from a plugin's Community Applications listing page → Details → Repository field) via Plugins → Install Plugin, rather than clicking "Install" from the Apps tab.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the plugin-install download call and review the changes introduced by unraid/api PR #2000, focusing on how redirects and download failures are handled. Reproduce the request against ca.unraid.net/dl and verify that the downloaded file is valid plugin XML and that installation is not reported as successful when fetching fails.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.