Documentation

Deployment Targets

How to adapt DesertCMS from its OpenBSD-first deployment to other Unix-like operating systems.

Source: DEPLOYMENT_TARGETS.md

OpenBSD is the first-class DesertCMS target. Other Unix-like systems can run the app when they provide Perl, SQLite, an image processor, a CGI or FastCGI bridge, a static webroot, and equivalent filesystem permissions.

Porting should preserve the same boundaries:

  • Application code is root-owned or deploy-owned and not writable by the web user.
  • Runtime data is writable only by the CMS service user.
  • Original uploads are outside the public webroot.
  • Public output is static and served directly by the web server.
  • Dynamic endpoints are limited to admin, analytics, comments, ratings, forms, shop, and webhooks.
  • Secrets stay in the instance config, not in generated files.

Required Runtime Pieces

DesertCMS expects:

Perl 5
DBI
DBD::SQLite
Digest::SHA
JSON::PP
MIME::Base64
HTTP::Daemon for local development
libvips tools: vips, vipsthumbnail, vipsheader
tar
a web server that can serve static files
a CGI/FastCGI bridge for bin/desertcms.cgi

OpenBSD package names differ from Debian, Ubuntu, FreeBSD, and Alpine package names. The module names and commands above are the stable requirements.

Portable Filesystem Layout

You can keep the OpenBSD paths on other systems or map them to local conventions.

/opt/desertcms/                         application code
/etc/desertcms.conf                     instance config
/var/lib/desertcms/desertcms.sqlite     database
/var/lib/desertcms/originals/           private originals
/var/lib/desertcms/backups/             backup archives
/var/lib/desertcms/themes/              editable themes
/var/www/desertcms/                     generated public webroot
/run/desertcms/desertcms.sock           FastCGI or CGI bridge socket

The important rule is ownership, not the exact path:

  • App code: readable by the service user, writable only by root/deploy.
  • Data/theme/originals/backups: writable by the CMS service user.
  • Public root: writable by the CMS service user, readable by the web server.
  • Original uploads: not inside the public root.

Service User

Create a locked service user such as _desertcms, desertcms, or www-desertcms.

Example Linux-style commands:

useradd --system --home-dir /var/lib/desertcms --shell /usr/sbin/nologin desertcms
install -d -o desertcms -g desertcms -m 750 /var/lib/desertcms
install -d -o desertcms -g desertcms -m 750 /var/lib/desertcms/originals
install -d -o desertcms -g desertcms -m 750 /var/lib/desertcms/backups
install -d -o desertcms -g desertcms -m 750 /var/lib/desertcms/themes
install -d -o desertcms -g www-data -m 755 /var/www/desertcms

Adjust group names for the target operating system.

Config File

Start from etc/desertcms.conf.example and set all paths explicitly:

site_name = DesertCMS
site_url = https://example.com
data_dir = /var/lib/desertcms
db_path = /var/lib/desertcms/desertcms.sqlite
public_root = /var/www/desertcms
originals_dir = /var/lib/desertcms/originals
backup_dir = /var/lib/desertcms/backups
theme_dir = /var/lib/desertcms/themes
admin_asset_dir = /opt/desertcms/admin/assets
docs_source_dir = /opt/desertcms/docs
secure_cookies = 1

For production, keep the config readable by the CMS service user and writable only by root or the deployment account.

Initialization

Run migrations and create the first admin as the service user:

sudo -u desertcms env DESERTCMS_CONFIG=/etc/desertcms.conf perl /opt/desertcms/bin/desertcms-maint.pl init-db
sudo -u desertcms env DESERTCMS_CONFIG=/etc/desertcms.conf perl /opt/desertcms/bin/desertcms-maint.pl create-admin setup-admin
sudo -u desertcms env DESERTCMS_CONFIG=/etc/desertcms.conf perl /opt/desertcms/bin/desertcms-maint.pl rebuild

The temporary CMS admin must set a permanent username and password on first login.

Process Model

OpenBSD uses slowcgi. On other systems you can use:

  • fcgiwrap behind nginx.
  • Apache mod_cgi or mod_proxy_fcgi with fcgiwrap.
  • A supervisor-managed local CGI/FastCGI adapter.
  • A custom service wrapper that executes bin/desertcms.cgi with DESERTCMS_CONFIG.

Whichever bridge is used, it must pass normal CGI variables:

REQUEST_METHOD
SCRIPT_NAME
PATH_INFO or REQUEST_URI
QUERY_STRING
CONTENT_TYPE
CONTENT_LENGTH
REMOTE_ADDR
HTTPS
HTTP_HOST

TLS And Proxy Headers

Terminate TLS at the web server. If a reverse proxy sits in front of the CGI bridge, make sure DesertCMS still sees:

HTTPS=on
HTTP_HOST=example.com
REMOTE_ADDR=<visitor or trusted proxy address>

Do not trust arbitrary public X-Forwarded-For headers unless the web server strips client-supplied values and rewrites them from a trusted proxy boundary.

Validation

The OpenBSD validation script is OpenBSD-specific. For other systems, manually verify:

  • Required Perl modules load.
  • vips, vipsthumbnail, and vipsheader are available.
  • The service user can read config and app code.
  • The service user can write database, themes, backups, originals, and public root.
  • Original uploads are outside the public root.
  • Dynamic endpoints route to CGI.
  • Static files route from the public root.
  • HTTPS redirects work.
  • Upload body limits allow expected photo sizes.
  • sitemap.xml, robots.txt, /docs/, and /admin/login return expected responses.