All guides
Containers · 6 min · Intermediate

Run systemd in an LXC Container

What an LXC container is, when you need one, and how services behave differently from a standard container.

A standard SparkCloud container has no init system. Its first process is sshd, so `systemctl` does nothing, and anything you start by hand is gone the next time the container stops. That is fine for a single app you launch from /app/start.sh, and a genuine wall for software that expects to be installed on a machine.

An LXC container is the answer to that: a full Linux system running the distribution's own systemd as PID 1. `systemctl enable --now nginx` behaves exactly as it does on a VM, and the service is back on its own after any restart, sleep, or wake from deep sleep.

When you actually want one

  • Software whose install instructions say `systemctl enable`, PostgreSQL, nginx, Redis, MariaDB, Docker-less service stacks.
  • Anything built around systemd itself: timers instead of cron, socket activation, journald, per-service resource limits.
  • A distro package that ships a unit file and expects it to be started for you.
  • Multi-service boxes where you would otherwise be reinventing an init system inside /app/start.sh.

If you are running one web app, a bot, or a worker, a standard container is smaller, starts faster, and snapshots far more cheaply. Reach for LXC when you need the init system, not by default.

Deploying one

  1. Containers → New Container. Pick LXC under Runtime.
  2. Choose Dynamic or Persistent exactly as you would otherwise, the runtime choice is independent of the billing type, and pricing is identical.
  3. Pick an image and disk size, then Deploy. First boot takes a little longer than a standard container because a real init system is coming up.
  4. SSH in with the host, port, and password on the container detail page.

Managing services

bash
apt update && apt install -y nginx
systemctl enable --now nginx
systemctl status nginx

# survives a restart, a sleep, and a wake from deep sleep:
reboot

Your app still needs to listen on port 80 to be reachable at your subdomain. /app/start.sh also still runs at every boot (as sparkcloud-app.service), so existing habits keep working. But a unit file is the better home for anything long-lived.

What is different

  • Snapshots cover the whole filesystem instead of just your changes, so deep sleep and waking from it take longer and use more of your storage quota. Sleeping and waking a dynamic LXC container is still a couple of seconds.
  • You get root inside the container, but that root is an unprivileged user on the host, nested Docker, loading kernel modules, and raw device access are all unavailable by design.
  • Outbound SMTP on port 25 is blocked, as it is for every container. Send mail through a provider on 587 or 465.