Skip to content

Running a public demo

The demo runs at https://nextexplorer-demo.onrender.comdemo@example.com / demo1234.

A demo of a file manager is not an ordinary deployment: strangers will upload to it, and the interesting parts of the application are exactly the ones you would not normally expose. This describes the setup published at the address in the README, and what makes it safe to leave open.

The one setting that matters

The demo account is an administrator, so that visitors can see the settings, access control and admin screens — otherwise half the application is invisible. That is only acceptable because the terminal is off:

yaml
TERMINAL_ENABLED: 'false'

The terminal is admin-only, and it is a shell inside the container. Left on, the login you publish is a login to your host. Nothing else in this page matters as much as that line.

Sharing, by contrast, is on. Publishing a link is one of the things people come to a file manager to try, and turning it off hides a whole feature. What stops the demo becoming a file host is the absence of a disk: every link dies with the instance, which on a plan that sleeps happens several times a day.

No disk, on purpose

The service runs without a persistent disk. Everything a visitor does lives until the next restart, and then demo/Dockerfile rebuilds the folders from the content baked into the image.

That is the reset. There is no cleanup job to schedule, nothing accumulates between restarts, and nobody can leave anything behind — which on a free plan that sleeps after fifteen minutes means several times a day.

The demo folders are copied into /mnt when the image is built, not seeded by a script at boot. A script that silently fails to run looks exactly like one that ran and found nothing — which is what happened first, and the demo came up with no volumes at all.

demo/Dockerfile also has to chown /mnt: the image's entrypoint takes ownership of /config and /cache but deliberately leaves the volume root alone, because in a real deployment that is the host's filesystem. Without it, the demo is read-only, and uploading and renaming — most of what it exists to show — do not work.

That chown uses the numeric id, not the name. appuser is created with a system UID, and the entrypoint renumbers it to PUID (1000 by default) when the container starts — so chown appuser at build time writes an id that is already stale when the application runs, and every write fails with EACCES on a demo that otherwise looks perfectly healthy.

A sign-in nobody has to retype

The credentials are published on this page, in the README and on the login screen, so asking visitors to copy them across is friction for no benefit. With DEMO_LOGIN_EMAIL and DEMO_LOGIN_PASSWORD set, the form arrives filled in and there is nothing to do but press the button.

Serving a password to whoever loads a page is right for a demo and wrong everywhere else, so it takes three things at once, and any one of them missing publishes nothing:

yaml
DEMO_MODE: 'true'
DEMO_LOGIN_EMAIL: demo@example.com
DEMO_LOGIN_PASSWORD: demo1234

The two credential variables are deliberately separate from AUTH_ADMIN_EMAIL and AUTH_ADMIN_PASSWORD: no flag can ever publish a real password by reaching for credentials that were set for another purpose. DEMO_MODE on its own only seeds sample files. A value it does not recognise — DEMO_MODE: oui — counts as off, so a typo leaves the credentials unpublished rather than the reverse.

The server says so plainly at startup:

[Config] Demo sign-in enabled: demo@example.com and its password are served to
anyone who opens the sign-in page.

DEMO_MODE=true also downloads a sample archive of photos and videos at boot. This demo turns that off with DEMO_SAMPLES=false: the archive is 80 MB and, with no disk, would be fetched again at every restart — most of the delay the first visitor after a nap would feel. Leave it on where richer content matters more than a fast wake.

Deploying on Render

The repository carries a render.yaml, so Render can create the service itself:

  1. Sign in at render.com and connect your GitHub account.
  2. New → Blueprint, and pick this repository. Render reads render.yaml.
  3. Confirm. It builds demo/Dockerfile and starts the service.
  4. The first deploy takes a few minutes; afterwards, pushes to main redeploy it automatically.

The login is demo@example.com / demo1234, created at boot by AUTH_ADMIN_EMAIL and AUTH_ADMIN_PASSWORD. The password must be at least six characters: below that the bootstrap is skipped with only a line in the log, and the first visitor is met by the setup wizard instead of the demo.

DEMO_MODE does not create an account — it only downloads sample files. The account comes from the bootstrap variables, and because the service has no disk, it is recreated on every restart along with everything else.

The free plan gives 512 MB of RAM and sleeps after fifteen minutes without traffic — the first visitor then waits about thirty seconds. Both are fine for a demo, and the sleeping is what keeps it clean.

Folder sizes run in full mode with the usage bar shown, because a demo exists to show features rather than to save cycles. On a tenth of a CPU that needs pacing, so the blueprint reconciles in batches of 20 with a second between them and rescans at most hourly — the walk stays in the background instead of competing with the browsing it annotates.

The blueprint pins the region to Frankfurt and the latest-lean image: hardware video acceleration and RAW decoding are no use on an instance this size, and the smaller image wakes faster.

Afterwards

Put the URL and the credentials in the README, and say plainly that the data resets — otherwise someone will store something there and be surprised.

Watch the first day. If thumbnail generation makes the instance struggle, lower the concurrency in Settings → Files & thumbnails; it is a runtime setting rather than a variable, so it survives without redeploying.