6.9 KiB
Deployment
RenewCMS ships as one self-contained executable. It serves:
| Path | What |
|---|---|
/v1/* |
JSON API |
/healthz |
Liveness check, returns 200 ok |
/* |
The Vue SPA (embedded), with fallback to index.html for client-side routes |
Its only runtime state is the SQLite database (DB_FILE) and the uploads directory (UPLOAD_DIR). Nothing else needs to be installed on the server.
1. Build
On any machine with the dev prerequisites:
task build # this OS/arch → bin/renewcms[.exe]
task release # all targets → bin/renewcms_<version>_<os>_<arch>[.exe]
task release also signs the release: it writes bin/checksums.txt (SHA-256 of the six binaries) and signs it into bin/checksums.txt.sig with an Ed25519 key. It refuses to start, before building anything, unless RELEASE_SIGNING_KEY points to the private key file and that key matches the public key committed as internal/infrastructure/update/release.pub. The one-time setup is below.
The frontend is built once and embedded into every binary. The binaries are static (CGO_ENABLED=0), so a Linux build runs on any distribution. The version comes from git describe: tag a release (git tag v1.2.0) before building, and the binary logs its version at startup.
Release signing key (maintainers, once)
- Run
task release:keygen -- <path>with a path outside the repository (for example~/.renewcms/release.key). The private key is written there and never leaves your machine; keygen refuses a path inside the work tree. - Commit the printed public key as
internal/infrastructure/update/release.pub. Until you do, the file holds a placeholder (32 zero bytes) andtask releasefails with a message saying so. - Export
RELEASE_SIGNING_KEY=<path to the private key>before everytask release.
To check a download by hand: go run ./cmd/releasesign verify checksums.txt, with checksums.txt.sig next to it, then compare the binary's hash with the matching line of checksums.txt.
Update checks
The owner's Settings page asks the release feed for the newest release (see UPDATE_FEED_URL in configuration.md) and keeps the last result in update-status.json, next to DB_FILE. Back it up with the rest of the data directory if you like; it is rebuilt by the next check when missing. The Settings page only reports a newer version for now: the site does not update itself.
Update downloads
Once the restart helper is installed (it writes update-helper.json next to DB_FILE), the owner's Update button downloads the new binary, checksums.txt and checksums.txt.sig from the release feed host over https only, checks the ed25519 signature and the SHA-256, runs the staged binary with --version, copies the database into backups/ (the last 3 copies are kept) and stages everything under updates/<tag>/, all next to DB_FILE. The job record is update-job.json. Nothing running is replaced and the site is not restarted. renewcms --version prints the build version and exits.
2. Lay out the server
The following is a suggested layout for Linux:
/opt/renewcms/renewcms the binary
/etc/renewcms/renewcms.env configuration (chmod 600, owned by root)
/var/lib/renewcms/ data: renewcms.db, uploads/ (owned by the service user)
sudo useradd --system --home /var/lib/renewcms --shell /usr/sbin/nologin renewcms
sudo install -d -o renewcms -g renewcms /var/lib/renewcms
sudo install -D -m 755 bin/renewcms_v1.2.0_linux_amd64 /opt/renewcms/renewcms
sudo install -D -m 600 /dev/null /etc/renewcms/renewcms.env # then edit it
/etc/renewcms/renewcms.env looks like this (see configuration.md for every variable):
ENVIRONMENT=production
PUBLIC_URL=https://cms.example.com
PORT=8080
DB_FILE=/var/lib/renewcms/renewcms.db
UPLOAD_DIR=/var/lib/renewcms/uploads
JWT_SECRET=<openssl rand -hex 32>
SMTP_LOGIN=noreply@example.com
SMTP_SENDER=noreply@example.com
SMTP_PASSWORD=...
SMTP_HOST=smtp.example.com
SMTP_PORT=465
3. Run it as a service (systemd)
/etc/systemd/system/renewcms.service:
[Unit]
Description=RenewCMS
After=network-online.target
Wants=network-online.target
[Service]
User=renewcms
Group=renewcms
WorkingDirectory=/var/lib/renewcms
EnvironmentFile=/etc/renewcms/renewcms.env
ExecStart=/opt/renewcms/renewcms
Restart=on-failure
# RenewCMS shuts down gracefully on SIGTERM (up to 10 s to finish requests and close the DB)
TimeoutStopSec=15
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/renewcms
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now renewcms
journalctl -u renewcms -f
curl -fsS http://localhost:8080/healthz
On Windows, register the binary as a service with a wrapper such as NSSM or WinSW, and set the same environment variables.
4. Put HTTPS in front
With ENVIRONMENT=production the auth cookie is Secure, so the site must be served over HTTPS. Terminate TLS in a reverse proxy and keep RenewCMS on localhost.
Caddy handles certificates automatically:
cms.example.com {
reverse_proxy localhost:8080 {
header_up X-Real-IP {remote_host}
}
}
nginx:
server {
listen 443 ssl http2;
server_name cms.example.com;
# ssl_certificate ... (e.g. certbot)
client_max_body_size 20m; # image uploads
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
If RenewCMS runs on the same host as the proxy, consider firewalling port 8080.
Either way, set TRUSTED_PROXIES (see configuration.md) to the proxy's own address as seen by RenewCMS, typically 127.0.0.1 when the proxy and RenewCMS share a host, so the login/password-reset rate limiter honors the forwarded client IP instead of the proxy's own address.
Backups
Everything worth backing up is under the data directory. Take a consistent SQLite copy while the service is running:
sqlite3 /var/lib/renewcms/renewcms.db ".backup '/backups/renewcms-$(date +%F).db'"
rsync -a /var/lib/renewcms/uploads/ /backups/uploads/
Alternatively, run systemctl stop renewcms, copy the directory, and run systemctl start renewcms.
Upgrading
- Back up (see above). The schema is migrated automatically at startup (GORM
AutoMigrate), and there is no down-migration. - Replace
/opt/renewcms/renewcmswith the new binary. - Run
sudo systemctl restart renewcms, then checkjournalctl -u renewcmsfor the new version line.
To roll back, put the previous binary back and restore the database backup if the schema changed.