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 serversnetwork-online.target- Network is fully configuredfreestyle-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 restarton-failure- Restart on non-zero exit codealways- 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");