Skip to content
Docs

Sites and versions

Every publish is a new version. The owner can publish without going live, open a preview link to any kept version, make it live, roll back, rename a site (old links keep working), take it offline, put a passcode on it, and download a copy with its saved data. A deleted site waits in Recently deleted (see Cleanup and retention).

Size. MAX_ARCHIVE_MB bounds one upload and one site. It is a guard against one upload filling a disk, not a budget: the median site on simple-host.app is about 25 KB. A proxy in front needs its own body limit raised to match. MAX_ARCHIVE_MB_OVERRIDES gives named accounts their own size; it holds new deploys only, so a larger site already live stays up. The admin page shows each site’s live copy (what the limit is about) and its total on disk (with kept versions).

Versions kept. Every version is a full copy of the site, so on a small disk the history, not the sites, is what fills it. The installer keeps one version (no rollback). Hosted Simple Host keeps 4; selected accounts default to 10. Only operator-allowed accounts can change their per-site count.

Hosted new sites from the 2026-10-05 deployment have a 200 MB whole-file allowance, and accounts have 1 GB. Earlier sites have no total cap. The live copy and retained versions count; backend storage stays separate. Checks use the resulting total after pruning. Self-hosted defaults have no account or site-total cap. See Website files and versions for exceptions and compression tips.

Site passcodes. An owner may put one passcode on a whole site. Every address of the site then shows a plain “This site is protected” page until the visitor enters it; a right passcode lets that browser in on that one address until the passcode changes or the owner signs everyone out. SITE_PASSCODES switches the feature; it also needs PASSCODE_ENC_KEY and a per-site address (SITE_HOSTS and PERSON_HOSTS on). A server where every site shares one address (a small box, an event box) refuses passcodes, because an unlock there would cover every site. Generate the key once with openssl rand -base64 32 and keep it secret like ADMIN_API_KEY: it seals every stored passcode so owners can read theirs back. Changing or losing it makes every stored passcode unreadable and signs every visitor out; owners then set new ones. PASSCODE_MIN_LENGTH is the shortest code allowed. Wrong tries are limited per address on a site (RATE_LIMIT_PASSCODE_IP, then PASSCODE_LOCKOUT_MINUTES) and per site from everyone together (RATE_LIMIT_PASSCODE_SITE, then PASSCODE_SITE_LOCKOUT_MINUTES); visitors already let in are not affected. A site with a passcode has a passcode file next to current in its folder, so addresses nginx or Caddy serve straight from disk hand the request to the app instead. The shipped vhosts and deploy/prod/nginx-suspended-marker.sh already do this; a hand-made nginx vhost that serves a site folder needs this line after its offline check:

if (-f <site folder>/passcode) { rewrite ^ /internal/passcode$uri last; }

and, when the block has no /internal/ proxy to the app, a location ^~ /internal/passcode/ one. nginx-suspended-marker.sh adds both to every block that serves a site folder.

Named viewers use the same marker and hand-off. An owner may open a whole site only to people named by email; each signs in on the site with that email (visitor sign-in, so the server needs email codes or Google set up), and the list is checked on every request. Like a passcode it needs a per-site address (SITE_HOSTS and PERSON_HOSTS on); a server where every site shares one address refuses it, because a sign-in there would cover every site. A site has named viewers or a passcode, never both. SITE_VIEWERS_MAX caps the list per site.

Setting Default Allowed What it does
IMPORT_LINK_TTL_MINUTES 30 1–1440 minutes How long a WordPress import page link works. Security-sensitive.
IMPORT_MAX_UPLOAD_MB 1024 1–10240 MB Maximum bytes in a WordPress import upload, in MiB.
IMPORT_MAX_XML_MB 100 1–1024 MB Maximum combined WordPress XML bytes, in MiB.
IMPORT_MAX_ARCHIVE_ENTRIES 20000 1–100000 count Maximum entries across import archives.
IMPORT_MAX_UNPACKED_MB 2048 1–20480 MB Maximum unpacked import bytes, in MiB.
IMPORT_MAX_CONCURRENT 1 1–16 count WordPress imports converting and publishing at once.
IMPORT_FETCH_MAX_MB 40 1–200 MB Maximum bytes fetched for one import file, in MiB.
IMPORT_FETCH_TOTAL_MB 1500 1–10240 MB Combined download budget for one import, in MiB.
MAX_SITES_PER_ACCOUNT 100 1–100000 sites Sites one account may hold (sites in Recently deleted count).
MAX_SITES_OVERRIDES none handle:sites Accounts that may hold a different number of sites than MAX_SITES_PER_ACCOUNT: comma-separated <handle>:<sites>, e.g. chhotabreak:2000 (1 to 100000 each). It follows the handle: an account that changes its handle keeps its override under the old one.
MAX_ARCHIVE_MB_OVERRIDES none handle:mb Accounts whose sites may be a different size than MAX_ARCHIVE_MB: comma-separated <handle>:<MB>, e.g. jot-transcribe:300 (1 to 500 each). It applies to new deploys only (a larger site already live stays up) and follows the handle like MAX_SITES_OVERRIDES. A proxy in front must accept bodies this large (4/3 of it for JSON and connector deploys), and the connector takes messages that large from every account, so keep values modest.
KEEP_VERSIONS_OVERRIDES none handle:versions Account defaults in place of KEEP_VERSIONS, as handle:n (1 to 1000). Current and old handles match.
MAX_SITE_TOTAL_OVERRIDES none handle:mb Account site-total limits in MB, as handle:MB (1 to 1000000); current and old handles match.
MAX_ACCOUNT_MB_OVERRIDES none handle:mb Account file allowances in MB, as handle:MB (1 to 1000000); current and old handles match.
MAX_SITE_TOTAL_MB 0 0–1000000 MB Whole website footprint after deploy and pruning: live files and all kept versions, including the separate live copy. 0: no cap. Applies only to sites created on or after SITE_TOTAL_CAP_FROM. Saved data and storage resources have separate limits and do not count.
MAX_ACCOUNT_MB 0 0–1000000 MB All account website files and kept versions, including Recently deleted sites and the separate live copies, after deploy and pruning. 0: no cap. Saved data and storage resources do not count.
KEEP_VERSIONS_SELF_SET none handles Handles allowed to change per-site version counts, comma-separated; current and old handles match. Unset: anyone may set their count. Other accounts use the default even if a site previously had its own setting.
SITE_TOTAL_CAP_FROM none RFC3339 RFC3339 creation cutoff for MAX_SITE_TOTAL_MB. Earlier sites are grandfathered. Unset: no site total cap.
MAX_FILES_PER_SITE 50000 100–50000 files Files in one upload. It can only be lowered.
PREVIEW_LINK_TTL_MINUTES 60 5–10080 minutes How long a preview link to a stored version works. Security-sensitive.
EXPORT_LINK_TTL_MINUTES 10 1–60 minutes How long a site or event archive download link works (it can hold private data). Security-sensitive.
SITE_PASSCODES on on / off on lets owners put a passcode on a site (it needs PASSCODE_ENC_KEY and a per-site address). off refuses new ones; sites that already have one keep asking for it.
PASSCODE_MIN_LENGTH 6 4–64 characters Shortest passcode an owner may set, in characters. Any characters count; digits only is fine.
SITE_VIEWERS_MAX 50 1–1000 viewers Most named viewers (people who may open a site that is open only to named viewers) one site can have.
PASSCODE_LOCKOUT_MINUTES 15 1–1440 minutes How long one address is refused on a site once it has used up RATE_LIMIT_PASSCODE_IP.
PASSCODE_SITE_LOCKOUT_MINUTES 15 1–1440 minutes How long a site refuses every passcode try once RATE_LIMIT_PASSCODE_SITE is used up (visitors already let in are not affected).
RATE_LIMIT_UPLOAD 30,10s any (warns past 10× looser) Uploads and deploys per client.
RATE_LIMIT_SITE_OPS 30,2s any (warns past 10× looser) Deleting, changing and restoring sites, and admin sign-in tries, per address.
RATE_LIMIT_EXPORT 10,10s any (warns past 10× looser) Site and account downloads per address.
RATE_LIMIT_ANALYTICS 30,2s any (warns past 10× looser) Top pages and referring domains reads, per address.
RATE_LIMIT_PASSCODE_IP 5,3m stricter freely; loosest 20,45s Wrong passcode tries on one site per address. Security-sensitive.
RATE_LIMIT_PASSCODE_SITE 60,1m stricter freely; loosest 240,15s Wrong passcode tries on one site from everyone together. Security-sensitive.
PHOTO_MAX_BYTES 1000000 at least 1 bytes Maximum bytes per prepared photo; the MCP picker also caps at 1 MiB. Positive integer; invalid values use the default.
PHOTO_MAX_DIMENSION 2048 at least 1 pixels Longest allowed side of a prepared photo. Positive integer; invalid values use the default.
PHOTO_MAX_CONCURRENT 3 at least 1 saves Concurrent photo saves across the process. Positive integer; invalid values use the default.
PHOTO_BODY_TIMEOUT_SECONDS 60 at least 1 seconds Read deadline for a photo-link upload body. Positive integer; invalid values use the default.
MAX_ARCHIVE_MB 100 at least 1 MB Largest upload, and the size one site may have.
KEEP_VERSIONS 0 at least 0 versions Deploys kept per site; 0 keeps all. install.sh sets 1, which means no rollback.
PASSCODE_ENC_KEY none secret Seals site passcodes, notification signing secrets and custom header tokens with AES-256-GCM (32 random bytes, base64: openssl rand -base64 32); without it new passcodes and notifications are refused, and changing it makes stored passcodes and notification secrets unreadable and signs every visitor out. Security-sensitive.
PREVIEW_ACCOUNTS none text Accounts (comma-separated) whose sites expire on their own.
WEB_PUSH_ACCOUNTS none text SIM-360: accounts (comma-separated handles) allowed to use Web Push as a notification channel; push routes 404 for everyone else. “all” or “*” enables it for every account. Empty: off.
PREVIEW_TTL_HOURS 48 at least 1 hours How long those accounts’ sites last.

Recipes

The installer’s defaults already fit: --max-site-mb 100 --keep-versions 1. To cap each participant too:

MAX_SITES_PER_ACCOUNT=20

Keep rollback on a bigger disk. Install with --keep-versions 5.

Existing-site summaries after an upgrade

After upgrading to a release with zi-site-search-summary.sql and running migrate, populate summaries from the existing active site files. The command only updates sites without a summary, so reruns are safe. Run it in the app container, whose environment and site volume are already configured. No key or connection string needs to be copied.

Small-box installer and DigitalOcean installations:

docker compose --project-directory /opt/simple-host --env-file /opt/simple-host/.env run --rm --no-deps -T app site-summary-backfill

For either Coolify recipe, open the app service’s terminal after migration and run simple-host site-summary-backfill. For a manual Compose checkout, run docker compose run --rm --no-deps -T app site-summary-backfill from its directory. The old pinned releases do not contain this command; run it after installing the new release. New deploys populate summaries automatically.

Add photos

PHOTO_MAX_BYTES sets the maximum bytes per prepared photo (default 1,000,000). PHOTO_MAX_DIMENSION sets the longest allowed side in pixels (default 2048). PHOTO_MAX_CONCURRENT bounds photo saves across the process (default 3). PHOTO_BODY_TIMEOUT_SECONDS sets the body-read deadline at both the owner and photo-token entry points (default 60 seconds; positive integers). Unsupported response writers continue without a deadline. Both signed-in and token saves acquire a slot before reading the request body; full capacity returns 429 “Busy, try again in a moment” and Retry-After: 2 without queueing. A slot is held through commit. Each request still allows 30 photos of 1,000,000 bytes plus bounded multipart overhead by default. The Add photos page prepares small WebP or JPEG copies on the device. The server validates them without decoding pixels or resizing. Each request takes up to 30 photos; the normal site upload, retained-version, account, and deploy rate limits also apply.

Upload and import behavior

MAX_SITES_PER_ACCOUNT applies to non-admin accounts; exceeding it returns 403 site_quota_reached. Malformed MAX_SITES_OVERRIDES or MAX_ARCHIVE_MB_OVERRIDES entries stop startup.

MAX_ARCHIVE_MB caps the upload and its uncompressed live copy, excluding kept versions. Archive overrides apply on every deploy path, including admin deploys. Existing larger sites can still be rolled back to. /v1/me and GET /v1/admin/users report the account cap as max_site_mb; exceeding it returns 413 site_too_large. JSON and connector deploys carry base64, hence the proxy body allowance of 4/3 of the largest override noted in the table.

The upload pipeline and disk are sized for at most 50,000 files. When MAX_ARCHIVE_MB is set, the effective file cap is the smaller of MAX_FILES_PER_SITE and one file per 4 KB of that budget.

create_import_link creates a link spent by one import. The proxy must accept IMPORT_MAX_UPLOAD_MB request bodies on /v1/imports/. Up to five imports wait behind the concurrent conversions; further requests ask the person to try again in a few minutes. Downloaded import files include photos missing from the media file and theme stylesheets. Export links are reusable and may hold private collections, so their lifetime is capped at an hour.

The longest site passcode is 128 characters, independently of the configured minimum.