Blog

alist: I Installed It — Then Decided Not to Feed It My Cloud Accounts

Deploying alist, a cloud-storage aggregator, on a home server

alist has been running on my home Docker host for the better part of a year now. This post covers the whole process: why I installed it, how I deployed it, reverse-proxied it, hardened it, and mounted storages to it — and why, in the end, I decided not to feed it any of my important cloud accounts.

Let me state the conclusion up front: alist is an aggregator, not storage. It lets you browse, search, and download content from a dozen cloud drives and local folders in one place, but it's terrible at the things real file management is supposed to do — trash, versioning, sync. Treat it as a read-only consumption front end and it's great; treat it as your primary cloud drive and something will eventually bite you.

Deploy: three steps with Docker Compose

alist runs on lab-core — my 2018 i5-8500 mini PC running Ubuntu Server 24.04, with Docker and 1Panel managing containers. All my compose projects live under /opt/stack/. alist officially recommends Docker, and it's a single compose file:

services:
  alist:
    image: xhofe/alist:latest
    container_name: alist
    volumes:
      - ./data:/opt/alist/data
    ports:
      - "5244:5244"
    environment:
      - PUID=1000
      - PGID=1000
      - UMASK=022
      - TZ=Asia/Shanghai
    restart: unless-stopped

Two details are worth calling out. First, mount the data directory separately: every piece of alist state — the SQLite database, config, logs — lives in the data directory, so backing up one folder backs up everything. Second, use a normal user for PUID/PGID: the official example likes to write 0 (root), but a process holding tokens for all your cloud drives has no business running as root. I'll come back to this.

Right after the container starts, set the admin password for the first time:

docker exec -it alist ./alist admin set your-strong-password

Then open http://server-ip:5244, log in, and fill in the site_url first (Admin → Settings → Site URL). This is what keeps you out of trouble when the reverse proxy goes up — leave it blank now and you'll be coming back to fix it in a minute.

Reverse proxy: don't let 5244 wander onto the public internet

Home connections rarely have a stable public IP — my ISP hands out CGNAT on a whim, and I've written up the port-forwarding lesson elsewhere. The takeaway was: the fewer inbound holes, the better. Everything external goes through Cloudflare Tunnel: outbound connections, no inbound ports open at home. Whatever path you pick though, the first step is to bind alist back to localhost: change the port mapping in compose to 127.0.0.1:5244:5244 so only the host can reach it, and let the reverse proxy own the public entry.

The topology ends up clean: public → Cloudflare Tunnel → my home reverse proxy (in the /opt/stack/proxy stack) → 127.0.0.1:5244. Here's the config in Nginx syntax as an example; Traefik and Caddy work the same way, the headers are what matter:

location / {
    proxy_pass http://127.0.0.1:5244;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Range $http_range;
    proxy_set_header If-Range $http_if_range;
}

Notice the Range / If-Range headers — they must pass through. alist's video preview relies on HTTP range requests, and if Range doesn't make it, large files break in weird ways (play button does nothing, seeking restarts from zero). It's the single most common mistake when reverse-proxying alist, bar none.

One more thing you must do: site_url has to be the full public URL (e.g. https://pan.example.com, no trailing slash). alist builds direct links, redirects, and preview URLs off it; leave it blank and everything behind the proxy looks like it logs in fine but serves broken downloads and previews.

alist is a "private but daily" service in my book, so I put Access in front of it on the Tunnel: unauthenticated requests get blocked at the edge, you can't even casually land on the login page. On the proxy layer I enable HTTPS and basic rate limiting — getting scanned on the public internet is the norm, and a login page is exactly the kind of surface that attracts brute force.

Hardening: six moves, half an hour

  1. Run as a non-root user: set PUID/PGID to a dedicated account in compose, don't copy the official example's 0;
  2. Bind the port to 127.0.0.1 only — the public side goes through the reverse proxy with HTTPS (see my earlier Traefik post);
  3. Keep ufw open only for what the proxy needs; 5244 and the S3 port 5246 stay closed to the public;
  4. Run the latest stable image and watch the GitHub security advisories — the path traversal and the TLS-verification-off-by-default issues were only fixed in v3.57.0 (advisory);
  5. Back up the data directory on a schedule — fold it into my existing backup job, the database and config are both in there;
  6. Tighten the admin surface: strong password, disable unneeded S3/FTP entry points.

Six items sounds like a lot, but the first pass takes under half an hour. Only then does this alist count as "deployed" — not "you can log in," but "the rollback paths and hardening items are all checked off."

Mounting: on demand, not a stamp collection

Mounting is alist's core feature: local folders, Aliyun Drive, Baidu, OneDrive, S3 — dozens of drivers. My rules are three:

  • Mount on demand. Every mount is a token and an API attack surface. The drive side can throttle, ban, or revoke API access; when any one dies, your "single entry" is missing a piece.
  • Assume read-only. An aggregator doesn't do file management. Treat mounted storages as content sources by default — important files always have another copy on the TrueNAS storage layer.
  • Least-privilege tokens. If a read-only grant exists, use it. Review validity and scope periodically.

Before mounting anything, ask one question: is this drive "content to browse" or "files to manage"? The former goes to alist, the latter stays in the storage itself.

Trust: after the 2025 ownership change, the math changed

Bigger than any technical detail is the project itself. In 2025, alist's original developer xhofe sold the project to BugoTech, and the site moved from alist.nn.ci to alistgo.com. The new owner submitted code that collected telemetry (the PR was later withdrawn), and then Aliyun Drive, 123 Pan, 115 and others revoked alist's API access one after another — not because alist did something wrong, but because the vendors no longer trusted this third-party aggregator. The community's answer was OpenList, a fork built around transparent governance and no hidden telemetry.

That chain of events says one thing: an aggregator's value comes from centralization, and so does its risk. Putting tokens for ten drives into one process is hanging ten doors' keys on a single keychain. Whether that keychain deserves your trust and whether it's convenient are two separate questions.

My move: keep using it, but mount read-only content sources only, and never feed it important accounts. If you want an aggregator but are uneasy about the ownership change, OpenList is worth evaluating.

When not to use alist

Decision table below, principle in one line: content goes to self-hosted storage, accounts connect read-only.

Situation Pick
Browsing, downloading, sharing direct links (read-only consumption) alist / OpenList — good enough
Files are the only copy; you need versions and trash NAS storage layer + Nextcloud / Seafile
Unify several cloud drives behind one entry alist works, but assume "read-only"
Two-way sync needed Native clients or Syncthing — not an aggregator
Sensitive to ownership changes, want long-term trust OpenList, or don't aggregate at all

FAQ

alist or OpenList?

As of mid-2026, for a fresh deployment I lean OpenList: more transparent governance, no telemetry controversy. If you're on an older alist, keep up with security advisories and upgrade promptly — no need to rush a migration.

Which cloud drives does alist support?

Aliyun Drive, Baidu, OneDrive, Google Drive, 123, 115 and dozens more — but several revoked API access after 2025, so check the official docs. Another reason to mount on demand.

Video won't play behind the reverse proxy — what now?

Nine times out of ten site_url isn't set, or the proxy isn't forwarding Range / X-Forwarded headers. Fix site_url first, then check the proxy config — don't go poking at alist itself.

alist is good software, and mine is still running at home, doing its job as a read-only browsing entry. But "good" and "worth handing over your life's files" are different things. The right posture for an aggregator is division of labor: self-hosted storage keeps the content, cloud accounts connect read-only, tokens are granted on demand, and trust is re-reviewed every year. The place I've given alist is the living-room TV that can find anything you want to watch — not the safe.

← Back to Blog