Deploying Dancer Apps – The Next Generation

Deploying Dancer Apps

Last summer, I wrote a couple of posts about my lightweight, roll-your-own approach to deploying PSGI (Dancer) web apps:

In those posts, I described how I avoided heavyweight deployment tools by writing a small, custom Perl script (app_service) to start and manage them. It was minimal, transparent, and easy to replicate.

It also wasn’t great.

What Changed?

The system mostly worked, but it had a number of growing pains:

  • It didn’t integrate with the host operating system in a meaningful way.
  • Services weren’t resilient — no automatic restarts on failure.
  • There was no logging consolidation, no dependency management (e.g., waiting for the network), and no visibility in tools like systemctl.
  • If a service crashed, I’d usually find out via curl, not journalctl.

As I started running more apps, this ad-hoc approach became harder to justify. It was time to grow up.

Enter psgi-systemd-deploy

So today (with some help from ChatGPT) I wrote psgi-systemd-deploy — a simple, declarative deployment tool for PSGI apps that integrates directly with systemd. It generates .service files for your apps from environment-specific config and handles all the fiddly bits (paths, ports, logging, restart policies, etc.) with minimal fuss.

Key benefits:

    • Declarative config via .deploy.env
    • Optional .env file support for application-specific settings
    • Environment-aware templating using envsubst
    • No lock-in — it just writes systemd units you can inspect and manage yourself
  • Safe — supports a --dry-run mode so you can preview changes before deploying
  • Convenient — includes a run_all helper script for managing all your deployed apps with one command

A Real-World Example

You may know about my Line of Succession web site. This is one of the Dancer apps I’ve been talking about. To deploy it, I wrote a .deploy.env file that looks like this:

And optionally a .env file for app-specific settings (e.g., database credentials). Then I run:

And that’s it. The app is now a first-class systemd service, automatically started on boot and restartable with systemctl.

Managing All Your Apps with run_all

Once you’ve deployed several PSGI apps using psgi-systemd-deploy, you’ll probably want an easy way to manage them all at once. That’s where the run_all script comes in.

It’s a simple but powerful wrapper around systemctl that automatically discovers all deployed services by scanning for .deploy.env files. That means no need to hard-code service names or paths — it just works, based on the configuration you’ve already provided.

Here’s how you might use it:

And if you want machine-readable output for scripting or monitoring, there’s a --json flag:

Under the hood, run_all uses the same environment-driven model as the rest of the system — no surprises, no additional config files. It’s just a lightweight helper that understands your layout and automates the boring bits.

It’s not a replacement for systemctl, but it makes common tasks across many services far more convenient — especially during development, deployment, or server reboots.

A Clean Break

The goal of psgi-systemd-deploy isn’t to replace Docker, K8s, or full-featured PaaS systems. It’s for the rest of us — folks running VPSes or bare-metal boxes where PSGI apps just need to run reliably and predictably under the OS’s own tools.

If you’ve been rolling your own init scripts, cron jobs, or nohup-based hacks, give it a look. It’s clean, simple, and reliable — and a solid step up from duct tape.

➡️ View the code on GitHub

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.