LogoFreestyle

Systemd Services

Configure background services and startup tasks in your VMs using systemd.

What is systemd?

Systemd is the standard init system and service manager for Linux. Freestyle VMs use systemd to manage services, startup tasks, and dependencies. You can define:

  • Background services - Long-running processes like web servers
  • One-time setup tasks - Installation scripts that run once
  • Service dependencies - Control startup order and requirements
  • Automatic restarts - Keep services running after failures

This documentation covers the systemd features most relevant to Freestyle VMs. For complete systemd documentation, see systemd.io and freedesktop.org systemd documentation.

Quick Start

import { freestyle } from "freestyle-sandboxes";

const { vm } = await freestyle.vms.create({
  systemd: {
    services: [
      {
        name: "my-web-server",
        mode: "service",
        exec: ["python3 -m http.server 8000"],
        workdir: "/app",
      },
    ],
  },
});

Service Modes

oneshot - Run Once

Use for installation scripts, setup tasks, or one-time operations.

systemd: {
  services: [
    {
      name: "install-dependencies",
      mode: "oneshot",
      exec: ["npm install"],
      workdir: "/app",
      wantedBy: ["multi-user.target"], // Start automatically on boot
      timeoutSec: 300,
    },
  ],
}

service - Keep Running

Use for web servers, APIs, background workers, or any long-running process.

systemd: {
  services: [
    {
      name: "api-server",
      mode: "service",
      exec: ["node server.js"],
      workdir: "/app",
      env: {
        PORT: "3000",
        NODE_ENV: "production",
      },
    },
  ],
}

Service Dependencies

Control the order services start and their requirements.

systemd: {
  services: [
    {
      name: "setup-database",
      mode: "oneshot",
      exec: ["./scripts/init-db.sh"],
      wantedBy: ["multi-user.target"],
    },
    {
      name: "web-app",
      mode: "service",
      exec: ["npm start"],
      workdir: "/app",
      // Wait for these to complete before starting
      after: [
        "setup-database.service",
        "network-online.target",
      ],
      // Require these services - fail if they fail
      requires: ["setup-database.service"],
    },
  ],
}

Common systemd targets

  • multi-user.target - Standard boot target for servers
  • network-online.target - Network is fully configured
  • freestyle-git-sync.service - Git repositories have been cloned

Environment Variables

Set environment variables for your services:

systemd: {
  services: [
    {
      name: "app",
      mode: "service",
      exec: ["python app.py"],
      env: {
        DATABASE_URL: "postgresql://localhost/mydb",
        API_KEY: "secret-key",
        LOG_LEVEL: "info",
      },
    },
  ],
}

User and Permissions

Run services as specific users:

systemd: {
  services: [
    {
      name: "web-server",
      mode: "service",
      exec: ["./server"],
      user: "www-data",
      group: "www-data",
      workdir: "/var/www",
    },
  ],
}

Restart Policies

Configure automatic restart behavior for services:

systemd: {
  services: [
    {
      name: "api-server",
      mode: "service",
      exec: ["node server.js"],
      restartPolicy: {
        policy: "on-failure", // "no" | "on-failure" | "always" | "on-abnormal"
        restartSec: 5, // Wait 5 seconds before restarting
        startLimitBurst: 3, // Max 3 restarts in the interval
        startLimitIntervalSec: 60, // Within 60 seconds
      },
    },
  ],
}

Restart policy options:

  • no - Never restart
  • on-failure - Restart on non-zero exit code
  • always - Always restart (except clean shutdown)
  • on-abnormal - Restart on crashes/signals

Cleanup Options

Delete after success

Useful for one-time setup that doesn't need to persist:

systemd: {
  services: [
    {
      name: "install-nodejs",
      mode: "oneshot",
      exec: ["bash /opt/install-nodejs.sh"],
      deleteAfterSuccess: true, // Remove after successful completion
      timeoutSec: 300,
    },
  ],
}

Keep alive after exit

For oneshot services that should keep the system waiting:

systemd: {
  services: [
    {
      name: "init-app",
      mode: "oneshot",
      exec: ["./initialize.sh"],
      remainAfterExit: true, // Mark as active even after exiting
      wantedBy: ["multi-user.target"],
    },
  ],
}

Watchdog and Health Checks

Ready signals

Signal when your service is fully initialized:

systemd: {
  services: [
    {
      name: "web-server",
      mode: "service",
      exec: ["python server.py"],
      readySignal: true, // Service must call sd_notify("READY=1")
    },
  ],
}

Watchdog

Monitor service health and restart if unresponsive:

systemd: {
  services: [
    {
      name: "background-worker",
      mode: "service",
      exec: ["./worker"],
      watchdogSec: 30, // Expect heartbeat every 30 seconds
      restartPolicy: {
        policy: "on-failure",
      },
    },
  ],
}

Triggering Other Services

Chain services on success or failure:

systemd: {
  services: [
    {
      name: "deploy-app",
      mode: "oneshot",
      exec: ["./deploy.sh"],
      onFailure: ["send-alert.service", "rollback.service"],
    },
    {
      name: "send-alert",
      mode: "oneshot",
      exec: ["./notify-team.sh"],
    },
    {
      name: "rollback",
      mode: "oneshot",
      exec: ["./rollback.sh"],
    },
  ],
}

Patching Existing Services

Modify services that are already defined in the base snapshot:

systemd: {
  patchedServices: [
    {
      name: "existing-service",
      env: {
        NEW_VAR: "value", // Add environment variable
      },
      after: ["another-service.service"], // Add dependency
    },
  ],
}

Enable/Disable Services

Control whether services start automatically:

systemd: {
  services: [
    {
      name: "optional-service",
      mode: "service",
      exec: ["./service"],
      enable: false, // Don't start automatically
    },
  ],
}

Start it manually later:

await vm.exec("systemctl start optional-service");

Common Patterns

Web server with installation

systemd: {
  services: [
    {
      name: "install-deps",
      mode: "oneshot",
      exec: ["npm install"],
      workdir: "/app",
      wantedBy: ["multi-user.target"],
    },
    {
      name: "web-server",
      mode: "service",
      exec: ["npm start"],
      workdir: "/app",
      after: ["install-deps.service"],
      env: {
        PORT: "3000",
        NODE_ENV: "production",
      },
      restartPolicy: {
        policy: "on-failure",
        restartSec: 5,
      },
    },
  ],
}

Database initialization

systemd: {
  services: [
    {
      name: "init-db",
      mode: "oneshot",
      exec: ["./scripts/create-tables.sql"],
      wantedBy: ["multi-user.target"],
      remainAfterExit: true,
    },
    {
      name: "run-migrations",
      mode: "oneshot",
      exec: ["./scripts/migrate.sh"],
      after: ["init-db.service"],
      requires: ["init-db.service"],
      wantedBy: ["multi-user.target"],
    },
  ],
}

Background worker with health check

systemd: {
  services: [
    {
      name: "queue-worker",
      mode: "service",
      exec: ["python worker.py"],
      workdir: "/app",
      env: {
        QUEUE_URL: "redis://localhost:6379",
      },
      watchdogSec: 60,
      restartPolicy: {
        policy: "on-failure",
        restartSec: 10,
        startLimitBurst: 5,
        startLimitIntervalSec: 300,
      },
    },
  ],
}

Debugging Services

Check service status:

await vm.exec("systemctl status my-service");

View service logs:

await vm.exec("journalctl -u my-service -n 50");

Follow logs in real-time:

await vm.exec("journalctl -u my-service -f");

List all services:

await vm.exec("systemctl list-units --type=service");

Restart a service:

await vm.exec("systemctl restart my-service");

On this page

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.