Server with Docker
server/Dockerfile produces a self-contained image with Node 20, the media tools, the compiled server and the sources (the CLI still runs from TypeScript). It is the only deployment artefact in the repository.
What the image contains
Section titled “What the image contains”FROM node:20WORKDIR /appRUN apt-get updateRUN apt-get install -y ffmpeg ghostscript libreoffice coreutils imagemagickCOPY package.json .COPY package-lock.json .RUN npm installCOPY . .RUN npm run buildCMD ["npm", "start"]npm run buildrunstscwithNODE_ENV=productionand writesdist/.npm startrunsnode dist/index.jswithNODE_ENV=production.- LibreOffice makes the image large (around 2 GB). It is needed for office document previews; removing it from the
apt-getline only loses those previews. mailconfig.jsonis copied with the sources, so the file fallback works inside the container whenMAILCONFIGis unset.
From the server/ folder:
docker build -t damvia-server:latest .npm install installs dev dependencies too (the build needs typescript); the image is not slimmed. Add a .dockerignore with node_modules, dist and .env to keep the build context small and to avoid copying a local .env into the image.
Pass the configuration as environment variables, never bake .env into the image:
docker run -d --name damvia-server \ --env-file /srv/damvia/server.env \ -e ENABLE_WORKER=true \ -p 3000:3000 \ damvia-server:latestENABLE_WORKER=true is required on exactly one container: npm start does not set it, unlike npm run dev. Without it no email is sent and no file is downloaded. See Worker and scaling.
The complete variable list is in Environment variables. Inside a Docker network, DATABASE_URL, SMTP_HOST and the S3 URLs use the service names (postgres, minio) rather than localhost; the S3 URLs must nonetheless be reachable from browsers, see Reverse proxy.
Startup sequence and health
Section titled “Startup sequence and health”On start the process:
- Initialises the cloud storage driver (for Dropbox, refreshes the token). Failure exits with code 1.
- Connects to Postgres and runs pending migrations.
- Listens on
0.0.0.0:${PORT}(default 3000). - Starts the worker if
ENABLE_WORKER=true. - Logs
server listening.
There is no dedicated health endpoint. GET /trpc/env returns a JSON body with the app name and regions and needs no authentication, which makes it a usable readiness check:
curl -fsS http://localhost:3000/trpc/envTemp space
Section titled “Temp space”File contents are downloaded to the system temp directory before upload, download archives are assembled there, and LibreOffice and ffmpeg write intermediate files there. Mount a volume or tmpfs on /tmp sized for your largest asset plus a 10 GB archive.
Winston writes to stdout in the format timestamp level: message {json}. Use docker logs or your platform’s collector; there is no log file.
docker-compose for production
Section titled “docker-compose for production”The repository’s server/docker-compose.yml is the development stack (Postgres, MailHog, MinIO) and does not include the server. A production compose file adds the server service built from server/, replaces MailHog with real SMTP settings, and puts the proxy in front. Keep the named volumes for Postgres and MinIO on persistent storage.