Skip to content
GuidesAddons24 min read

Better Files Manager

Installer
Ainx installation path

Better Files Manager V-A.1.0.0 installs in two layers. The panel package provides the interface and panel-backed NBT and database previews. Patched Wings adds native collaboration, streamed search and media, resumable uploads, archive tools, file history, bulk operations, and Git endpoints.

Back up the panel and commit or copy a modified Wings source tree before migration. Do not combine the retired standalone installer with the current Ainx or Blueprint package.

Run the package installer from the Pterodactyl panel root:

bash
ainx install betterfilesmanager.ainx

That completes the panel layer. Do not run the old Artisan installer or paste the retired standalone routes afterward.

Optional translations

The package includes an English catalog at translations/en/betterfilesmanager.php. Better Files works without installing it and uses built-in English strings as its fallback.

Translation paths differ between Pterodactyl themes. Place the catalog using the theme developer's Laravel-to-React translation instructions, and preserve all placeholders when creating another locale. The extension installer does not overwrite or remove customer translation files.

What works without patched Wings

The package installs the panel routes, assets, settings, and frontend build. NBT and database previews run through the panel and do not require daemon changes.

Continue below for native collaboration, streamed path/content search, media streaming, resumable uploads, directory archives, revision history, bulk copy and rename, operation cancellation, fingerprints, largest-directory analysis, and Git operations.

Security requirements

Build source installations with Go 1.26.7 or newer and golang.org/x/text v0.39.0 or newer. The current smart script and both current patch files carry those versions. Updating only the panel package or Wings source files does not update the running service: rebuild Wings, replace /usr/local/bin/wings, and restart it. Prebuilt installations must download the current binary and restart Wings.

The hardened resumable-upload flow keeps the existing endpoint and request headers, but clients must follow these rules:

  • Mint one signed upload token per file. Every HEAD, chunk, and retry for that token must use the same server and canonical file path.
  • A successful Upload-Complete: ?1 request retires the token. Mint a new token for another file or any request after completion.
  • PATCH /upload/file can return 408 when the request body is idle, 409 for a competing same-file writer or an offset/length conflict, and 429 when an upload admission limit is full. Honor Retry-After on 429.

Git clone and pull now accept only the final public HTTPS repository URL. Redirects, proxies, credentials in URLs, internal addresses, and unsafe repository-local Git configuration fail closed. Network fetches run through the isolated alpine/git:2.49.1 helper; clone checkout and pull's fast-forward merge run separately with networking disabled. Wings may need to download the helper image on first use.

Folder batch upload API

Current Go Wings supports nested folders in one POST /upload/file request. Before using this mode, inspect GET /openapi.json and require paths['/upload/file'].post['x-betterfiles-folder-upload'].version === 1. The capability specifies paths_field: "paths" and max_files: 512. A plain POST route alone does not prove support: older daemons may ignore the manifest and flatten filenames.

Use the existing signed upload URL and directory query parameter. Append each file under the repeated files field with its basename, then add exactly one text field named paths, containing a JSON array of relative paths in the same order:

javascript
const form = new FormData();
form.append("files", firstConfigFile, "config.yml");
form.append("files", secondConfigFile, "config.yml");
form.append(
  "paths",
  JSON.stringify(["mods/a/config.yml", "mods/b/config.yml"])
);
const url = new URL(signedUploadUrl);
url.searchParams.set("directory", "/uploads");
await fetch(url, { method: "POST", body: form });

This creates /uploads/mods/a/config.yml and /uploads/mods/b/config.yml. Go strips directory components from multipart filenames, so sending a path only as the file's name does not preserve folders. The browser supplies the multipart Content-Type boundary automatically.

  • Paths use / and are relative to directory. Their basenames must match the corresponding file parts. Paths are literal JSON strings, not URL-encoded values.
  • Empty paths, absolute paths, dot/parent components, repeated separators, backslashes, NUL, Windows drive prefixes, invalid UTF-8, duplicate destinations, and file/directory conflicts are rejected. Paths are limited to 4096 bytes and components to 255 bytes.
  • Missing parent directories are created with server ownership. Ignored paths, symbolic links, hardlinks, and non-regular destinations cannot be overwritten through this API.
  • At most 512 files fit in one folder-batch request. Individual and combined file bytes must fit the Wings upload limit and server quota. The request body is also bounded to the upload limit plus 8 MiB of metadata.
  • Each POST uses one fresh single-use token for the whole batch, even when the request fails. Obtain another token before retrying. Batches are not transactional: a runtime failure may leave earlier files written.
  • Success remains 200; invalid manifests or file limits return 400, ignored paths 403, unavailable/consumed tokens 404, active same-file writers 409, and oversized HTTP bodies 413.
  • When the capability is absent, use the existing per-directory flat uploads or per-file resumable uploads. Omitting paths keeps flat multipart behavior, and the resumable HEAD/PATCH format is unchanged.

Install C-Wings

Choose a C-Wings installation method

Wings modifications

The prebuilt binary is the shortest route. For source builds, the smart script is the recommended automatic method. Use the addon patch for a reviewable Better Files-only change, and use manual recovery only when another addon conflicts with the patch.

Run this in Bash on your existing Wings node. The download command automatically selects the x86-64 or ARM64 binary from our latest dev-latest build:

bash
sudo systemctl stop wings
sudo curl -fL --retry 3 -o /usr/local/bin/wings "https://github.com/Tomaxikz/daemon/releases/download/dev-latest/wings_linux_$([[ "$(uname -m)" == "x86_64" ]] && echo "amd64" || echo "arm64")"
sudo chmod u+x /usr/local/bin/wings
sudo systemctl restart wings

Release page: Tomaxikz/daemon dev-latest.

Build and verify

Before replacing the running service, confirm the Go version, format the touched packages, run focused tests, and build Wings:

bash
go version  # must report go1.26.7 or newer
gofmt -w router/*.go router/middleware/*.go router/websocket/*.go \
  server/*.go server/filesystem/*.go config/*.go environment/docker/*.go
go test ./router ./router/middleware ./router/websocket ./server ./server/filesystem
go build -o wings .
sudo systemctl stop wings
sudo install -m 0755 ./wings /usr/local/bin/wings
sudo systemctl start wings
sudo systemctl is-active wings

If the host has a working C compiler, also run the race detector before deploying a custom build:

bash
go test -race ./router ./router/middleware ./router/websocket ./server ./server/filesystem

Inspect the capability document and recent service logs:

bash
curl -fsS "http://127.0.0.1:8080/openapi.json"
sudo journalctl -u wings -n 100 --no-pager

Verify these capabilities from Better Files in the panel:

  • HEAD and PATCH /upload/file for resumable uploads with offset checks, bounded concurrency, fail-fast same-file locking, idle-body timeouts, and one completed file per signed token.
  • POST /git/clone and POST /git/pull for HTTPS-only network transfers in the isolated helper and network-disabled checkout or fast-forward merge.
  • GET /download/directory for streamed tar, tar_gz, tar_xz, tar_bz2, tar_zstd, and zip archives.
  • POST /files/search for structured path, size, and content search.
  • POST /files/copy-many and PUT /files/rename for safe bulk operations.
  • GET /files/largest-directories and GET /files/fingerprints for analysis.
  • DELETE /files/operations/:operation for background-operation cancellation.

Upload, download, and server-file routes require a signed token or panel authentication. An unauthenticated 401 or 403 from a copied route URL does not by itself mean the installation failed.