Guides
Deploying
Building a release, running it on a server behind HTTPS, and the checklist before going live.
A Cadmus project builds into one executable. Copy it to the server with your settings in environment variables, run its migrations, and start it.
#Building
cargo build --release
# the program is target/release/<project name>
On the server:
export DATABASE_URL=postgres://...
export SECRET_KEY=...
./blog migrate # before starting each new version
./blog serve
#What is already taken care of
- Time limit: a request that takes longer than 30 seconds gets
503and is stopped (server.request_timeout;Nonefor no limit). Uploads and downloads are exempt. - Request log: one line per request with method, address, status and duration (the query string is left out).
- Protective headers on every admin and API response: no embedding in other sites, no content-type guessing, no caching of pages that needed a login.
- Cross-origin access (CORS) is off until you set
server.cors_origins. - Graceful shutdown on Ctrl-C and on the stop signal sent by
docker stop, systemd and Kubernetes: requests in progress finish first. - Health check:
/answers503when the database is down (see Settings).
#Before going live
- HTTPS. Serve over HTTPS (a reverse proxy such as nginx or Caddy, or your platform's),
and leave
DEBUGunset: the generated settings only allow the login cookie over plain HTTP whenDEBUG=true. - Behind a proxy, set
server.client_ip_header(see Two-factor login and limits), andserver.bindto0.0.0.0:3000if the proxy runs on another machine or container. - Secrets. Set
DATABASE_URLandSECRET_KEYon the server, keep.envout of git, and use a differentSECRET_KEYfor each environment (cadmus secretprints one). Changing it logs everyone out. - Migrations. Run
migrateas part of each deployment, before starting the new version. - Uploads. If you use the local folder backend, keep that folder on storage that survives redeploys, or use S3, Azure or Google Cloud.
- E-mail. Set
MAIL_URLandPUBLIC_URLso login links and password resets work.
#Containers
A minimal Dockerfile:
FROM rust:1 AS build
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:stable-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=build /app/target/release/blog /usr/local/bin/blog
ENV APP_BIND=0.0.0.0:3000
EXPOSE 3000
CMD ["sh", "-c", "blog migrate && exec blog serve"]
The generated settings read the address to listen on from APP_BIND; inside a container it
must be 0.0.0.0:3000 to be reachable from outside.
#Compression
Responses are not compressed, on purpose: admin pages contain a security token next to text the visitor controls (the search box), which is what the BREACH attack on compressed HTTPS needs. Let your proxy compress static files only, if anything.