Deployment (Dokploy)
Set up the bot on Dokploy from scratch, or migrate an existing deployment to the monorepo layout.
FluffBoost deploys as a Docker image on Dokploy. Because Bun runs TypeScript directly, there's no build step — the image just needs the bot's source and its production dependencies.
How it works
apps/discord/Dockerfilebuilds the image. It usesturbo pruneso the bot image only contains the bot and its dependencies, neverapps/docs.- Build context is the repository root (not
apps/discord) — the Bun workspace lockfile lives at the root and Turborepo needs the whole graph to prune. - The container's entrypoint runs database migrations, then starts the bot with
bun run src/app.ts. - A health check hits
GET /api/healthonPORT(default3000). - All configuration is injected as environment variables — see Configuration.
Setting up a fresh deployment
Starting from a clean server? Work through these in order.
Provision PostgreSQL and Redis
Create a PostgreSQL 16 and a Redis 7 service in Dokploy (or point at
existing ones). Copy each connection string — they become DATABASE_URL and
REDIS_URL.
Create the application
Add a new Docker / Dockerfile application pointing at this repository, then set exactly two build fields:
| Field | Value |
|---|---|
| Build context / base directory | . (the repository root) |
| Dockerfile path | apps/discord/Dockerfile |
The context must stay at the root — the Bun workspace lockfile lives there
and turbo prune needs the whole graph.
Add the environment variables
Set the required variables — DATABASE_URL, REDIS_URL,
DISCORD_APPLICATION_ID, DISCORD_APPLICATION_PUBLIC_KEY,
DISCORD_APPLICATION_BOT_TOKEN, OWNER_ID, MAIN_GUILD_ID,
MAIN_CHANNEL_ID — plus any optional ones you want. The full table (with
defaults) is in Configuration.
Production does not read a .env file; inject these through Dokploy.
Invalid or missing config exits the process immediately at startup — that's by design. If the container dies instantly, read the logs: the Zod error names the exact variable.
Expose the port and health check
The container listens on PORT (default 3000) and answers
GET /api/health. Point Dokploy's health check at that path.
Deploy and verify
Trigger the deploy. The container applies the database migrations before the bot
starts, so the schema is created for you on this first run — watch the logs for
Running database migrations..., then a successful Postgres + Redis connection
and the shards logging in. Confirm the health check goes green.
Load the starter quotes
The quote library is not seeded automatically, and without it the bot has nothing to post. Now that the tables exist, run this once from your machine against the production database:
DATABASE_URL='<your-production-url>' OWNER_ID='<your-discord-id>' bun run db:seeddb:seed skips quotes that already exist, so it's safe to re-run.
Point the bot at a channel
In Discord, run /setup channel in your server to choose where the daily quote
lands, then /quote to confirm the library loaded.
Migrating an existing deployment
This applies to deployments created before the monorepo move, when the
Dockerfile lived at the repository root. The bot's runtime behavior is
unchanged — only the build path moves.
The only thing that changed is where the Dockerfile lives. Update your Dokploy application:
Keep the build context at the repo root
Base directory / build context stays . (the repository root). Do not point
it at apps/discord — the workspace lockfile is at the root.
Point the Dockerfile path at the app
Change the Dockerfile path from Dockerfile to:
apps/discord/DockerfileLeave everything else as-is
Environment variables, ports, and the health check path (/api/health) are
unchanged. No new variables are required.
Redeploy and watch the logs
Trigger a deploy. Confirm the bot boots, connects to Postgres and Redis, and the health check goes green.
Local sanity check
Before touching production, verify the image builds with the new path:
docker build -f apps/discord/Dockerfile -t fluffboost:test .(Note the trailing . — the context is the repo root.)
Rollback
If anything looks wrong, redeploy the previous commit. Nothing in this migration touches the database, the environment, or the health check, so a rollback is just a redeploy of the old image.
Environment files
Local Docker Compose reads apps/discord/.env. Production does not use a
.env file — inject the variables through Dokploy directly.