Skip to the content

Documentation

Harden a self-hosted install

A checklist for running Docustay on your own servers when the documents are sensitive, including health information. What to switch on, what to keep private, and what to check.

Run Docustay on your own servers and you choose every provider that touches your documents. This page is the checklist for an install that holds sensitive documents, such as health information. Work through it top to bottom after installing and before the first real document.

Docustay is built to follow the HIPAA Security Rule's safeguards: encryption, two-step sign-in, audit logs and access controls. Whether your install meets the rule depends on your servers, your providers and your policies too. This page is not legal advice.

1. Turn on the workspace's health rules

In Settings → Security, turn on This workspace handles health information. It changes these at once, for everyone in the workspace:

What With health information on
Two-step sign-in Required for everyone (an owner turns this on in Workspace → Security)
Idle sign-out After 15 minutes without activity, or sooner if you set it in Settings → Security
AI drafting Off, and it cannot be turned on
Emails Never name the document: they say "the document"
Signed copies Sent as a download link (7 days unless you set longer), never as an attachment
Access log Every view, download and export by your team, in Settings → Security, with a CSV

2. Keep the inside private

  • Only the web container listens. In the bundled docker-compose.yml only web publishes a port. The database, the file store and the PDF converter talk on Compose's private network. Do not add ports: to db, storage or gotenberg.
  • Put HTTPS in front. Use a reverse proxy with TLS (reverse proxy guide). Set KEYSTONE_PUBLIC_URL to the https:// address and KEYSTONE_TRUSTED_PROXY_HOPS to the number of proxies in front. Docustay sends HSTS on every HTTPS answer.
  • Firewall the host. Allow 443 (and 80 for the certificate check) in; nothing else from outside.

3. Encrypt what is stored

  • Disks. Put the Docker volumes (dbdata, filedata, appdata) on an encrypted disk: LUKS on Linux, or your cloud provider's encrypted volumes.
  • Secrets. init.sh writes KEYSTONE_MASTER_KEY, which seals stored secrets (two-step secrets, SMTP passwords, webhook secrets). Keep .env readable only by the account that runs Docker (chmod 600 .env).
  • Backups. Encrypt each backup before it leaves the machine (for example age or gpg), and keep the key apart from the backup. See Back up and restore.
# encrypt last night's backup folder for one recipient key, then copy only the .age file off the machine
d=$(ls -d backup-* | tail -1)
tar czf - "$d" | age -r "$(cat ~/.docustay-backup.pub)" > "$d.tgz.age"

4. Choose providers that sign a Business Associate Agreement

Everything that sends, stores or reads your documents needs one when the documents hold health information.

  • Email. Set RESEND_API_KEY only if your Resend plan covers you, or use your own SMTP server in Settings → Email with a provider that signs a BAA. With health information on, emails never carry the document's name or the PDF.
  • Sign-in. The built-in sign-in (KEYSTONE_LOCAL_AUTH) keeps identities in your own database. Or connect your own OpenID Connect provider (DOCUSTAY_OIDC_ISSUER, see single sign-on).
  • AI. Leave ANTHROPIC_API_KEY empty. Health information keeps AI off in that workspace anyway.
  • Payments. Never put health details in a payment description or metadata.
  • Hosting. Your server or cloud provider holds the disks: it needs a BAA too.

5. Sign-in and sessions

  • Owners and admins need two-step sign-in in every workspace. Health information makes it everyone.
  • Turn on passkeys (KEYSTONE_PASSKEYS=1 and KEYSTONE_PASSKEY_ORIGINS) so people can use a device instead of a code.
  • Settings → Security lists where each person is signed in and ends any session.
  • When someone leaves, remove them from the team the same day: their sessions end at once.

6. Logs and monitoring

  • Server and worker logs leave out email addresses and credentials. Keep that on (it is unless KEYSTONE_LOG_REDACTION=off).
  • Send logs to a store you control, kept as long as your policy says.
  • Set KEYSTONE_ALERT_EMAIL so a failing backup or a paused sender reaches someone.
  • DOCUSTAY_TELEMETRY=off stops the one anonymous daily usage ping (it never carries document content).

7. Keep it current

  • Upgrade when a release comes out (upgrade guide). Release notes say when a fix is about security.
  • Run docker compose pull and rebuild at least monthly, so the operating system packages in each image stay patched.
  • Report a problem to security@docustay.app.

8. Check it

Before the first real document:

  1. Open https://your-address/ and confirm the padlock, then curl -sI https://your-address/ | grep -i strict-transport shows HSTS.
  2. From outside the host, confirm the database port (5432) and the file store port (8333) do not answer.
# run from another machine: each line must say "closed" (nc exits non-zero when nothing answers)
for p in 5432 8333 3000; do nc -z -w 3 your-address "$p" && echo "$p OPEN: close it" || echo "$p closed"; done
  1. Sign in as an owner without two-step: Docustay sends you to set it up.
  2. Leave a session idle past the limit: the next click asks you to sign in again.
  3. Send a test document to yourself: the email does not name it and has no attachment.
  4. Open a document, then check Settings → Security → Access log shows it.
  5. Restore last night's backup onto a spare machine and open a signed PDF. Write down how long it took.
CtrlI