Deployment guide

FlatPress

Overview

FlatPress is a lightweight, flat-file blogging engine and content management system, published at github.com/flatpressblog/flatpress. It needs no database at all. Every post, static page, comment, setting and account is stored as an ordinary file on disk, so there is nothing to install, secure, tune or back up beyond a folder of files.

This guide covers deploying and configuring FlatPress on Ubuntu 24.04 on Azure. The image installs FlatPress 1.5.1 served by nginx and PHP 8.3 FPM. Because the engine is entirely file-based, there is no database process anywhere in the image, which keeps the footprint tiny.

What you get:

  • FlatPress 1.5.1 served by nginx and PHP 8.3 FPM, with a strict nginx allowlist. It serves the theme, plugin and media assets, but never the configuration, the account files or the per-install secret.
  • One appliance, one web application. nginx and php8.3-fpm serve the whole site on port 80. There is no database and no mail engine, so port 80 is the only network-reachable service. FlatPress stores all of its state as files under fp-content/, which the web server never serves.
  • No administrator account in the image. A first-boot service mints a unique administrator password for each VM, completes installation, and proves the credentials before the site is reachable.
  • A bootstrap gate. It stops nginx and php-fpm from serving until provisioning is complete.
  • Unattended security upgrades, configured to keep the server patched on your running VM.

Security model

FlatPress ships a web setup wizard that would let an unauthenticated visitor complete installation and seize the administrator account on a fresh site. This image closes that hole completely. The setup wizard is removed from the image entirely, and the image ships no account, no configuration and no secret at all.

On the first boot of every VM, a one-shot service does the following:

  • Generates a unique administrator password.
  • Completes installation non-interactively.
  • Creates the single administrator account and the per-install security salt.
  • Proves that the new password signs in through the real login form, and that admin, a blank password and other common guesses do not.
  • Writes /root/flatpress-credentials.txt (mode 0600, root only).

The site cannot serve an unprovisioned instance. nginx and php8.3-fpm are each gated on a bootstrap marker that first boot writes only after the administrator account, configuration and salt are in place. Until that marker exists, systemd skips those units entirely. No half-provisioned or empty site is ever reachable. The units are still enabled, so the appliance comes straight back after a reboot.

Prerequisites

  • An Azure subscription and either the Azure Portal or the Azure CLI (az) signed in
  • An SSH key pair so you can read the generated credentials file
  • Inbound TCP port 80 open to the browsers that will reach the site, and port 22 for administration
1

Deploy from the Azure Portal

  • Open the SecureAnyCloud FlatPress Blog and CMS on Ubuntu 24.04 LTS offer in the Azure Marketplace and choose Create.
  • Pick a resource group and region. Keep the recommended Standard_B2s size, because FlatPress is tiny and runs comfortably on 2 vCPU / 4 GB. Provide your SSH public key for the azureuser account.
  • On the Networking step, allow inbound 80 (the web application) and 22 (SSH). FlatPress serves everything over port 80. Put it behind an Azure Application Gateway or a reverse proxy if you want TLS.
  • Create the VM and note its public IP address.
2

Deploy from the Azure CLI

RG="flatpress-prod"; LOCATION="eastus"; VM_NAME="flatpress" IMAGE_URN="sac1647283583153:flatpress-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:flatpress-ubuntu-24-04:default:latest
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$IMAGE_URN" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002
3

First boot and your credentials

On first boot, the image does the following:

  • Mints the per-instance administrator password.
  • Completes the FlatPress installation and creates the administrator account and the per-install salt.
  • Opens the bootstrap gate and starts nginx and php-fpm.
  • Verifies that the new credentials work and that the common defaults are rejected.
  • Writes /root/flatpress-credentials.txt.

This completes within a minute or two. SSH in as azureuser and read the details:

sudo cat /root/flatpress-credentials.txt

The file is mode 0600 and owned by root, so only a privileged user can read it. It contains the site URL, the login URL, and the admin username (admin) and password.

4

Confirm the appliance is running

Both services must report active. ss confirms that the web application is on port 80. It also confirms that there is no database or mail listener, because FlatPress needs neither.

systemctl is-active php8.3-fpm.service nginx.service php -r 'echo "PHP ".PHP_VERSION."\n";' nginx -v ss -tulnp | grep ':80 ' | sed 's/users:.*//'
5

View your blog

Browse to http://<your-vm-ip>/. FlatPress renders your blog immediately, with a seeded welcome post so that the site is not empty. The theme, the sidebar menu, categories, archives and search are all wired up.

6

Sign in to the admin panel

Browse to http://<your-vm-ip>/login.php. Sign in with the admin username (admin) and the password from the credentials file.

7

The administration area

After you sign in, you land on the FlatPress administration area. From here you manage entries, static pages, the media uploader, sidebar widgets, plugins, themes and the site configuration.

8

Write your first post

Open Entries -> Write Entry. Give your post a subject and content with the built-in BBCode editor. Optionally set categories, a description and keywords, then select Publish.

Your post appears on the blog immediately. FlatPress stores it as a plain file, with no database write.

9

Change the administrator password

Open Configuration, or the Users area, and set a new administrator password. From then on, use your own password. The generated one in the credentials file only gets you in.

10

Prove that the per-VM administrator works and defaults are rejected

The image ships no shared credential. The credentials file is root-only, and the account file is not world-readable. The real login form accepts only the per-VM administrator password:

ls -l /root/flatpress-credentials.txt stat -c 'credentials mode %a owner %U:%G' /root/flatpress-credentials.txt stat -c 'admin account file mode %a owner %U:%G' /var/www/flatpress/fp-content/users/admin.php
# the per-VM administrator password signs in through the real login form:
sudo /usr/local/sbin/flatpress-login-check.sh admin '<FLATPRESS_ADMIN_PASSWORD>' \
  && echo "per-VM administrator: SIGNED IN" \
  || echo "per-VM administrator: run this on your VM (the password is substituted from the credentials file)"
# every guessable default is rejected: for p in admin password flatpress 123456 ""; do if
sudo /usr/local/sbin/flatpress-login-check.sh admin "$p"; then echo " '$p' ACCEPTED (unexpected)" else echo " '$p' rejected (correct)" fi done
# the account file and the per-install salt are never web-served:
curl -s -o /dev/null -w ' GET /fp-content/users/admin.php -> HTTP %{http_code} (404 = not served)\n' http://127.0.0.1/fp-content/users/admin.php
curl -s -o /dev/null -w ' GET /fp-content/config/hashsalt.conf.php -> HTTP %{http_code} (404 = not served)\n' http://127.0.0.1/fp-content/config/hashsalt.conf.php
11

The flat-file model: no database

Everything FlatPress stores is a file under fp-content/. Your posts live under fp-content/content/, the configuration and per-install salt under fp-content/config/, and your account under fp-content/users/.

There is no database engine anywhere on the machine.

ls /var/www/flatpress/fp-content/
sudo find /var/www/flatpress/fp-content/content -name 'entry*.txt' | head -3 systemctl list-units 'mariadb*' 'mysql*' 'postgresql*' --all --no-legend | head -3 || echo ' (no database units — FlatPress needs none)' curl -s http://127.0.0.1/ | grep -o 'Welcome to your FlatPress blog' | head -1
12

How the first-boot gate protects an unprovisioned instance

The key security property of this image is that the web tier cannot serve until provisioning is complete. Each web unit carries a ConditionPathExists drop-in on the bootstrap-ready marker. First boot writes the marker only after the administrator has been created. An empty site is therefore never reachable, and a visitor can never run the installer or become the first administrator.

for u in php8.3-fpm nginx; do printf '%-12s %s\n' "$u" "$(grep -h ConditionPathExists /etc/systemd/system/$u.service.d/sac-bootstrap-gate.conf)" done ls -l /var/lib/sac/data/ systemctl is-enabled php8.3-fpm.service nginx.service
# the removed installer is not reachable:
curl -s -o /dev/null -w ' GET /setup.php -> HTTP %{http_code} (404 = installer removed)\n' http://127.0.0.1/setup.php
13

Static pages, menus, comments and themes

From the admin area, you can create standalone static pages, such as an About or Contact page. You can also edit the sidebar menu, moderate reader comments with the built-in spam controls, arrange sidebar and footer widgets, and switch or restyle the theme.

FlatPress ships with the Leggero theme. A set of plugins is enabled out of the box: BBCode editor, comments, search, archives and RSS.

14

Back up and restore

FlatPress is entirely file-based, so a full backup is just a copy of the content directory. There is no database to dump:

sudo tar czf "flatpress-backup-$(date +%F).tar.gz" -C /var/www/flatpress fp-content ls -lh flatpress-backup-*.tar.gz

To restore, extract the archive back over fp-content on a fresh instance, after its first boot has run. This preserves your posts, pages, comments, configuration and account.

15

Security recommendations

  • Put FlatPress behind TLS. The image serves plain HTTP on port 80. Terminate HTTPS at an Azure Application Gateway, a load balancer or a reverse proxy in front of the VM. Restrict port 80 to that front end.
  • Restrict SSH to your administration network with an NSG rule.
  • Rotate the administrator password (Step 9) and keep the credentials file (/root/flatpress-credentials.txt) readable only by root.
  • Keep the OS patched. Unattended security upgrades are enabled. Reboot periodically to pick up new kernels.
  • Back up regularly (Step 14). It is only a folder of files.
16

Support and licensing

FlatPress is distributed under the GNU General Public License, version 2 (GPL-2.0). This SecureAnyCloud image bundles FlatPress 1.5.1 with nginx and PHP from Ubuntu 24.04, configured and hardened as described above.

SecureAnyCloud provides 24/7 support for this image by email at sales@secureanycloud.com. Support covers initial setup, blog and page authoring, themes and styling, plugins, navigation menus and widgets, comment moderation and spam control, media uploads, file-based backup and restore, and FlatPress version upgrades.

All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.

Deploy on Azure

Launch FlatPress 1.5.1 Blog and CMS on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure