Production Setup
What you need
- A Linux server with systemd, root or sudo access, and a public IP or domain
- Podman 5.3+ with Quadlet support
CI builds the app as a container image and publishes it to ghcr.io/francoism90/stry, so your server doesn't need PHP, Composer or the source code to run stry. You do need a copy of the repository to generate two things once:
- the
.envfile - the Podman Quadlet units, the config files that tell Podman and systemd how to run each service
You can generate these on the server, on another machine, or in CI. See Generate the Podman files below.
Get the code and configure it
cd ~/projects
git clone https://github.com/francoism90/stry.git
cd stry
cp .env.example .env
Edit .env and set at least:
APP_ENV=productionandAPP_DEBUG=falseAPP_URLAPP_KEY: generate one withopenssl rand -base64 32and prefix it withbase64:- your database and S3 credentials
A later step stores this file as a Podman secret. See Application Configuration for all options.
Then install lpod, the CLI you use to install and manage the services. It's a single bash script, so it doesn't need PHP or Composer. The installer puts lpod and lpod-setup in ~/.local/bin, and offers to enable linger so the services start at boot:
curl -fsSL https://github.com/foxws/lpod/releases/latest/download/install.sh | bash
Generate the Podman files
The Quadlet files are generated by foxws/laravel-podman. It's a regular dependency, because the idle check runs its podman:idle command inside the containers. Pick the option that fits your server.
Option A: you can run Composer on the server
composer install
php artisan podman:setup
Option B: the server has Podman but no PHP
Use lpod-setup, which generates the files inside a temporary container. The installer already put it next to lpod. Run it through lpod:
lpod setup --install --secrets
This still needs a vendor/ folder. You need to have run composer install once, even if you did that on another machine and copied the folder over. See Setting up without PHP on the host for details.
Option C: generate the files elsewhere and copy them over
Run php artisan podman:setup on your own machine or in CI, then copy the generated podman/ folder to the server. You don't need to install anything else on the server.
With any option, you end up with a podman/ folder that contains the Quadlet files. See Podman Quadlet for what each service does.
If you know Quadlet well, you can skip all of the above. Copy the templates from containers/stubs/{preset}/quadlets/*.quadlets, fill in the {{placeholder}} values yourself (application name, image, UID/GID and so on), and install them with lpod install. You don't need to clone the repository or run podman:setup, but you then have to keep every file and secret up to date by hand on each upgrade.
Install and start the services
Skip this step if you used Option B: lpod setup --install --secrets already did it. For Option A or C:
lpod install production/app.quadlets --replace
# ...install every service you need, see podman/production/...
lpod stry secrets
# ...and set secrets for every service that needs them...
lpod stry up
To let the app and its services sleep when nobody uses them, install the on-demand socket and enable the idle check. Skip this with PODMAN_ONDEMAND_ENABLED=false:
lpod install ondemand/stry-ondemand.socket --replace
lpod idle enable stry
Next, set up object storage (see Object Storage (S3)) and prepare the database and search:
lpod stry artisan podman:s3-setup
lpod stry artisan migrate --force
lpod stry artisan db:seed --force
lpod stry artisan scout:sync --import
db:seedonly runsPermissionSeeder, which creates the roles and permissions. You need it once, and it's safe to run again.scout:sync --importsets up the Typesense collections and imports existing records. It's also safe to run again, but you only need to after a release adds new searchable models.
Then create an admin account with lpod stry artisan users:create --super-admin (see CLI Interaction).
By default, stry-horizon gets access to /dev/dri for hardware-accelerated transcoding, so the server needs a GPU that provides /dev/dri. See Hardware acceleration for driver setup, the SELinux setsebool step, and how to turn this off on a server without a GPU.
Check that everything works:
systemctl --user status stry
curl -I https://your-domain/
journalctl --user -u 'stry*' -f
Once the services are installed, you no longer need the cloned repository on the server. The app runs from the pre-built image, and Podman and systemd already have the Quadlet units and secrets. You can remove ~/projects/stry, or keep it only on the machine you use to regenerate the Quadlet files after upgrades.
Security checklist
-
Use strong, random secrets (
openssl rand -hex 32) for everything you store withlpod SERVICE secrets. Never reuse development credentials. -
Terminate HTTPS at your own reverse proxy in front of the app's port
8000, for example your router or NAS, Nginx Proxy Manager, Traefik or Cloudflare Tunnel. See Reverse Proxy for how the app routes subdomains internally. -
Only allow ports 22, 80 and 443 through the firewall.
-
Never run
AdminSeederor other demo or test seeders in production. Only the plaindb:seed(PermissionSeeder) from the setup above is safe to run again. -
Keep Podman and the base images up to date. See Upgrading.
-
Schedule automatic database backups:
# Every day at 2am 0 2 * * * lpod stry-pgsql run pg_dump -U user -d stry | gzip > /backups/stry-$(date +\%Y\%m\%d).sql.gz
Next steps
- Application Configuration for app settings
- CLI Interaction for everyday commands
- Upgrading for updating an existing install
https://your-domain/horizonto monitor the queues (super-admin only)
