Skip to content

Deployments

Billy.Zheng edited this page Apr 13, 2026 · 7 revisions

Deployments

Procodile supports running multiple independent supervisors on the same machine.

For example, these two application roots can each run their own supervisor without interfering with each other:

  • /apps/foo
  • /apps/bar

Each application root has its own Procfile, supervisor PID, control socket, logs, and managed processes.

Multiple Supervisors on One Host

Running multiple supervisors is a normal deployment model.

For example:

procodile -r /apps/foo start
procodile -r /apps/bar start

These are two separate supervisors, not one shared supervisor.

What Must Stay Separate

Different application roots work safely as long as you do not configure conflicting shared paths or ports.

Pay particular attention to:

  • pid_root
  • log_path and log_root
  • proxy_port and proxy_address
  • allocate_port_from

If two applications are configured to use the same PID directory, log path, proxy listener, or port allocation range, they can still conflict even if their roots are different.

Using /etc/procodile

The global /etc/procodile file is only used to help the CLI determine which application root to operate on.

It does not create a shared supervisor. Each configured application still runs as its own independent supervisor.

A single-app configuration can look like this:

root: /apps/foo

A multi-app configuration can look like this:

- name: Foo
  root: /apps/foo
- name: Bar
  root: /apps/bar

This is equivalent to running commands with -r /apps/foo or -r /apps/bar manually.

A Practical Deployment Pattern

A practical pattern is to create a dedicated Unix user for each application, for example deployer, and keep the application under that user's home directory:

/home/deployer/apps/myapp_production

This keeps process ownership, logs, sockets, PID files, and deploy-time permissions isolated per application.

If you are deploying a Ruby application and rely on tools such as RVM, it is usually a good idea to invoke Procodile through bash -lc "...". This helps ensure that shell startup files are loaded and that Ruby, Bundler, PATH, and related environment setup are initialized correctly before Procodile starts.

Starting Procodile with a systemd User Service

If you still want Procodile itself to remain the process manager, a reasonable compromise is to use systemd --user only to start the Procodile daemon at boot.

Example:

[Unit]
Description=procodile
StartLimitIntervalSec=0

[Service]
LimitCORE=infinity
LimitNOFILE=infinity
LimitNPROC=infinity
Type=oneshot
ExecStart=bash -lc '/usr/local/bin/procodile -r /home/deployer/apps/myapp_production start --clean'
ExecStop=bash -lc '/usr/local/bin/procodile -r /home/deployer/apps/myapp_production stop --stop-supervisor --wait'
RemainAfterExit=yes

[Install]
WantedBy=default.target

This approach uses systemd only as a one-shot bootstrap mechanism to start Procodile and the application services it manages. Procodile still manages the application processes, restarts, logs, scheduling, and runtime issues.

Using -r /path/to/app is usually enough to avoid setting WorkingDirectory in the systemd unit. Procodile uses the application root to load configuration, and when it starts managed processes it also changes into that application root before executing them.

If you deploy through release directories and a current symlink, always point Procodile at the stable current path rather than a specific release directory. Otherwise, if Procodile is started from a concrete release path, later restarts may continue using that old release instead of the new current target.

For example:

procodile -r /home/deployer/apps/myapp/current start
# not
procodile -r /home/deployer/apps/myapp/releases/20260414-120001 start

Procodile also exposes the resolved application root to managed processes through the APP_ROOT environment variable.

Starting Without Login

To allow a user service to start even when the user has not logged in, enable lingering for that user:

sudo loginctl enable-linger deployer

Then install and enable the user unit as that user, for example:

systemctl --user daemon-reload
systemctl --user enable procodile.service
systemctl --user start procodile.service

Caveats of the Oneshot Pattern

This pattern works, but it has one important limitation: once procodile start exits successfully, systemd only knows that the start command completed. It does not directly supervise the long-running Procodile daemon after that.

That means:

  • if the Procodile supervisor later dies unexpectedly, the user service may still appear active
  • Restart=on-failure does not behave like normal long-running service supervision here, because the ExecStart command itself already exited successfully

So this pattern is best understood as:

  • systemd starts Procodile at boot
  • Procodile manages the application afterwards

Operating the Application Afterwards

After the user service has started the Procodile daemon, you still manage the application with normal procodile commands. A common pattern is to use one of these approaches:

  • define a shell alias that always runs Procodile with the correct -r application root. For example:

    alias procodile_myapp="procodile -r /home/deployer/apps/myapp_production"

With this alias, you can run commands like:

procodile_myapp status
procodile_myapp reload
procodile_myapp restart
  • change into the application root and run procodile there directly. For example:
cd /home/deployer/apps/myapp_production
procodile status

Alternatives

If you want systemd to supervise Procodile itself more strictly, run Procodile in the foreground under systemd instead:

ExecStart=bash -lc '/usr/local/bin/procodile start --foreground --clean'
Type=simple

That gives systemd a real long-running main process to track, but it also means systemd is now supervising Procodile more directly.

If your goal is to avoid relying on systemd as the primary process manager, the user-service bootstrap pattern above is a reasonable compromise.

Updating a Deployment

A simple deployment flow is:

  1. Deploy the new release.
  2. Run procodile reload if only configuration changed.
  3. Run procodile restart for long-running process changes.
  4. Use procodile status to confirm the new state.

For command details, see CLI Reference.

Clone this wiki locally