EmberlyEmberly Docs

Deploying

Deploy Emberly with Docker Compose, Dokploy, Railpack/Nixpacks, or directly on a Linux server.

Pick whichever fits how you run servers. Docker Compose is the simplest and bundles PostgreSQL and Redis for you.

MethodGood for
Docker ComposeA single server, with everything in one file
DokployDokploy users; deploys from a template or your fork
Railpack / NixpacksRailway, Coolify and other PaaS hosts
Linux serverRunning with Bun and systemd, without containers

Whatever you choose, put Emberly behind HTTPS (see Reverse Proxy) and set APP_URL to the public address.


Docker Compose

compose.yaml runs Emberly, PostgreSQL and Redis from published images, so you don't need the source code. Uploads are stored in a Docker volume.

mkdir emberly && cd emberly
curl -fsSLo compose.yaml https://raw.githubusercontent.com/EmberlyOSS/Emberly/master/compose.yaml
curl -fsSLo .env https://raw.githubusercontent.com/EmberlyOSS/Emberly/master/.env.example

Edit .env:

APP_URL="https://files.example.com"
AUTH_SECRET="..."          # openssl rand -base64 32
POSTGRES_PASSWORD="..."    # any strong password

Then start it:

docker compose up -d

Emberly listens on port 3000. Set EMBERLY_PORT to use a different host port. Migrations run each time the container starts.

With S3 Storage

To store uploads in S3 instead of the local volume, compose.s3.yaml adds a RustFS server:

curl -fsSLo compose.s3.yaml https://raw.githubusercontent.com/EmberlyOSS/Emberly/master/compose.s3.yaml
docker compose -f compose.yaml -f compose.s3.yaml up -d

Set S3_SECRET_ACCESS_KEY and S3_PUBLIC_ENDPOINT in .env first. See Storage.

Updating

docker compose pull
docker compose up -d

To run your own build instead, build the image from a clone of the repository and point Compose at it:

docker build -t emberly .
EMBERLY_IMAGE=emberly docker compose up -d

Dokploy

From the Template

The dokploy/ folder has a Dokploy template (docker-compose.yml and template.toml). It runs the published image with PostgreSQL and Redis, and generates AUTH_SECRET and the database password for you.

  1. In your Dokploy project, create a Compose service.
  2. Paste dokploy/docker-compose.yml as the compose file, or import the template.
  3. Under Environment, set APP_URL, AUTH_SECRET and POSTGRES_PASSWORD if the template didn't.
  4. Under Domains, add your domain for the emberly service on port 3000, with HTTPS on.
  5. Deploy.

From Your Fork

To build from source instead, for example to run your own changes:

  1. Create PostgreSQL and Redis databases in Dokploy and copy their internal connection URLs.
  2. Create an Application pointing at your repository.
  3. Set Build Type to Dockerfile, with Docker File Dockerfile and Docker Context Path ..
  4. Add the environment variables:
APP_URL=https://files.example.com
AUTH_SECRET=...
DATABASE_URL=postgresql://...
REDIS_URL=redis://...
  1. Under Advanced → Volumes, mount a volume at /data so local uploads survive redeploys. You can skip this if you use S3.
  2. Add your domain on port 3000 and deploy.

Railpack and Nixpacks

The repository includes railpack.json and nixpacks.toml, so hosts that build with either detect Emberly automatically. Both run migrations and then start the app.

Set at least APP_URL, AUTH_SECRET, DATABASE_URL and REDIS_URL.

These hosts usually don't keep files between deploys, so use S3 storage.


Linux Server

1. Install

You need Bun, Node.js 24, PostgreSQL 14+ and Redis 7+.

curl -fsSL https://bun.sh/install | bash
sudo apt-get install -y postgresql redis-server
 
git clone https://github.com/EmberlyOSS/Emberly.git /opt/emberly
cd /opt/emberly
bun install
cp .env.example .env
chmod 600 .env

Fill in .env. See Environment Variables.

2. Build

bun run db:generate
bun run db:deploy
bun run build

3. Run with systemd

Create /etc/systemd/system/emberly.service:

[Unit]
Description=Emberly
After=network.target postgresql.service redis-server.service
 
[Service]
Type=simple
WorkingDirectory=/opt/emberly
ExecStart=/usr/bin/env bun run start
Restart=on-failure
User=emberly
 
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now emberly

bun run start reads .env from the repository root.

Running the Worker Separately

The background worker (emails, notifications, Discord alerts, OCR, malware scans) runs inside the app, so you don't need a second process. On busy instances you can move it to its own: set EMBERLY_RUN_EVENT_WORKER=false on the app and add a second service with ExecStart=/usr/bin/env bun run worker. Running the app on several servers is fine too; each picks up its share of the jobs.

Updating

cd /opt/emberly
git pull
bun install
bun run db:deploy
bun run build
sudo systemctl restart emberly

Reverse Proxy

Dokploy and most PaaS hosts handle HTTPS for you. On your own server, use Caddy or Nginx.

Caddy

files.example.com {
    reverse_proxy localhost:3000
}

Nginx

server {
    listen 80;
    server_name files.example.com;
 
    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 0;
    }
}

New sign-in alerts and the devices list show where someone signed in from when your proxy adds location headers. Cloudflare does this automatically (CF-IPCountry, and CF-IPCity with its location headers turned on), as does Vercel. Without them, sign-ins still show the device and time, just not the place.

Then run sudo certbot --nginx -d files.example.com. client_max_body_size 0 leaves upload limits to Emberly.


After Deploying

  1. Open your domain and complete the Setup Wizard.
  2. Set up email in Admin → Settings → Integrations, so verification and password reset emails send.
  3. Upload a test file.

Health Checks

GET /api/health reports the database, Redis, storage and event queue. It needs no authentication; the Docker image uses it as its health check.

{
  "success": true,
  "data": {
    "status": "ok",
    "checks": {
      "database": { "status": "up", "latencyMs": 4 },
      "redis": { "status": "up", "latencyMs": 1 },
      "storage": { "status": "up", "provider": "local" },
      "eventQueue": { "status": "up", "workerRunning": true }
    }
  }
}

status is ok, degraded (something other than the database is failing) or down (the database is unreachable, returned with HTTP 503).


Backups

Back up the database and your uploads.

# Docker Compose
docker compose exec postgres pg_dump -U emberly emberly > backup-$(date +%F).sql
 
# Linux server
pg_dump -U emberly emberly > backup-$(date +%F).sql

Uploads live in the emberly-data volume (Docker), in DATA_DIR (Linux server), or in your S3 bucket.


Troubleshooting

Admin → Overview shows the state of the database, Redis, storage, the event worker, email and Discord alerts. When reporting a bug, click Copy debug info there and paste it into the issue. It never includes keys, passwords or tokens.

ProblemCheck
AUTH_SECRET is not set on startSet AUTH_SECRET (openssl rand -base64 32)
Signed in but sent back to the login pageAPP_URL must be the exact public address, including https://
Emails, notifications or Discord alerts never arriveAdmin → Overview shows whether an event worker is running. If EMBERLY_RUN_EVENT_WORKER=false, run bun run worker
Uploads disappear after a redeployMount a volume at /data, or use S3
Uploads from Flicker or ShareX fail with S3S3_PUBLIC_ENDPOINT must be reachable from users' machines
Emails don't sendCheck the email settings in Admin → Settings → Integrations

On this page