Skip to main content

What are Workflows?

Workflows define the sequence of actions executed during server lifecycle events. They handle everything from copying template files to installing plugins and applying configurations.

How Workflows Work

During server preparation:
  1. Serverhost receives a start request from the Controller
  2. Loads the setup workflow from workflows/internal/setup.yml
  3. Executes each step in order with the server context
  4. Reports status back to the Controller
During cleanup:
  1. Server stop signal received
  2. Loads the cleanup workflow from workflows/internal/cleanup.yml
  3. Executes cleanup steps (cache push, directory deletion)

Workflow Structure

Workflows are YAML files in the workflows/ directory:
# workflows/internal/setup.yml
steps:
  - action: copy
    from: "{{templates}}/cache/{{group}}"
    to: "{{server-dir}}"

  - action: copy
    from: "{{templates}}/every"
    to: "{{server-dir}}"

  - action: plugins-load
    dir: "{{server-dir}}/plugins"

  - action: configurator
    configurator: "{{configurator}}"
    dir: "{{server-dir}}"

Built-in Workflows

Setup Workflow

The default setup workflow (workflows/internal/setup.yml) performs:
  1. Cache Pull - Copy cached files from previous runs
  2. Template Copy - Apply template hierarchy (every, type, software, tagged)
  3. Plugin Installation - Download and install plugins
  4. Configuration - Apply configurators for server software

Cleanup Workflow

The cleanup workflow (workflows/internal/cleanup.yml) performs:
  1. Cache Push - Save reusable files for faster future starts
  2. Directory Deletion - Remove the server directory

Workflow Actions

copy

Copies files or directories from source to destination.
FieldTypeDescription
frompathSource file or directory
topathDestination file or directory
replacebooleanOverwrite existing files (default: true)
create-dirsbooleanCreate parent directories if missing (default: true)
- action: copy
  from: "{{templates}}/every"
  to: "{{server-dir}}"
  replace: true

delete

Deletes a file or directory.
FieldTypeDescription
pathpathFile or directory to delete
forcebooleanForce deletion of non-empty directories (default: true)
min-agedurationOnly delete files/directories older than this duration (e.g. 30d, 12h, 60m, 90s)
- action: delete
  path: "{{server-dir}}"
  force: true
  min-age: "7d"

compress

Compresses a file or directory into an archive. Supported formats: .tar.gz, .tgz, .tar.bz2, .tbz2, .tar.xz, .txz, .zip, .tar, .7z
FieldTypeDescription
frompathSource file or directory to compress
topathDestination archive path
replacebooleanOverwrite existing archive (default: true)
- action: compress
  from: "{{server-dir}}/world"
  to: "{{cache}}/{{group}}/world.tar.gz"
  replace: true

decompress

Extracts files from an archive to a destination directory. Supported formats: .tar.gz, .tgz, .tar.bz2, .tbz2, .tar.xz, .txz, .zip, .tar, .7z
FieldTypeDescription
frompathPath to the archive file
topathDestination directory to extract into
replacebooleanOverwrite existing files (default: true)
- action: decompress
  from: "{{cache}}/{{group}}/world.tar.gz"
  to: "{{server-dir}}/world"
  replace: true

upload

Uploads a file to a remote URL via HTTP.
FieldTypeDescription
frompathPath to the local file to upload
tostringTarget URL
methodstringHTTP method (default: PUT)
authorization-bearerstringBearer token for authorization
After execution, the following context variables are set:
VariableDescription
upload.response.codeHTTP response status code
upload.response.bodyHTTP response body
- action: upload
  from: "{{server-dir}}/backup.tar.gz"
  to: "https://storage.example.com/backups/{{server-name}}.tar.gz"
  method: PUT
  authorization-bearer: "{{$.backup-token}}"

for-each

Iterates over a list and executes nested steps for each item.
FieldTypeDescription
itemslistItems to iterate over
asstringVariable name for current item
stepslistSteps to execute for each item
- action: for-each
  items: "{{tags}}"
  as: "tag"
  steps:
    - action: copy
      from: "{{templates}}/_tagged/{{tag}}"
      to: "{{server-dir}}"

plugins-load

Installs plugins from configured sources (Modrinth, Hangar, Spigot, URL).
FieldTypeDescription
dirpathDirectory to install plugins into
- action: plugins-load
  dir: "{{server-dir}}/plugins"
Plugins are defined at the group level and automatically downloaded based on:
  • Server software (Paper, Velocity, etc.)
  • Minecraft version
  • Platform compatibility

configurator

Applies a configurator to configure server files.
FieldTypeDescription
configuratorstringConfigurator name (from options/configurators/)
dirpathServer directory to configure
- action: configurator
  configurator: "paper_velocity"
  dir: "{{server-dir}}"
See Configurators for more details.

Placeholders

Workflows support dynamic placeholders replaced at runtime:

Server Context

PlaceholderDescription
{{server-dir}}Server’s working directory
{{server-name}}Server name (e.g., lobby-1)
{{group}}Group name
{{port}}Assigned port
{{max-players}}Maximum player count
{{memory}}Allocated memory (MB)

Path Context

PlaceholderDescription
{{templates}}Templates base directory
{{running}}Running servers directory
{{cache}}Cache directory

Blueprint Context

PlaceholderDescription
{{configurator}}Configurator name from blueprint
{{software}}Server software (paper, velocity, etc.)
{{minecraft-version}}Minecraft version
{{type}}Server type (proxy, server, lobby)

Custom Properties

Access custom properties from the server:
- action: copy
  from: "{{templates}}/{{$.custom-template}}"
  to: "{{server-dir}}"
The $. prefix accesses the server’s properties map.

Default Setup Flow

The built-in setup workflow follows this order:
steps:
  # 1. Pull from cache (faster restarts)
  - action: copy
    from: "{{templates}}/cache/{{group}}"
    to: "{{server-dir}}"

  # 2. Apply base templates
  - action: copy
    from: "{{templates}}/every"
    to: "{{server-dir}}"

  # 3. Apply type-specific templates
  - action: copy
    from: "{{templates}}/every_{{type}}"
    to: "{{server-dir}}"

  # 4. Apply software-specific templates
  - action: copy
    from: "{{templates}}/every_{{software}}"
    to: "{{server-dir}}"

  # 5. Apply tagged templates
  - action: for-each
    items: "{{tags}}"
    as: "tag"
    steps:
      - action: copy
        from: "{{templates}}/_tagged/{{tag}}"
        to: "{{server-dir}}"

  # 6. Apply server-specific template
  - action: copy
    from: "{{templates}}/{{server-name}}"
    to: "{{server-dir}}"

  # 7. Install plugins
  - action: plugins-load
    dir: "{{server-dir}}/plugins"

  # 8. Apply configurator
  - action: configurator
    configurator: "{{configurator}}"
    dir: "{{server-dir}}"

Customizing Workflows

Override Default Workflow

Create your own setup workflow:
# workflows/internal/setup.yml
steps:
  - action: copy
    from: "{{templates}}/my-base"
    to: "{{server-dir}}"

  - action: plugins-load
    dir: "{{server-dir}}/plugins"

  - action: configurator
    configurator: "{{configurator}}"
    dir: "{{server-dir}}"

Add Custom Steps

Extend the workflow with additional actions:
steps:
  # ... standard setup steps ...

  # Custom: Copy world from shared storage
  - action: copy
    from: "/shared/worlds/{{group}}"
    to: "{{server-dir}}/world"

  # Custom: Download additional resources
  - action: copy
    from: "{{templates}}/shared-configs"
    to: "{{server-dir}}/plugins"

Troubleshooting

Symptom: Server starts but workflow steps don’t run.Solution:
  1. Verify file exists: workflows/internal/setup.yml
  2. Validate YAML syntax (use a linter)
  3. Check serverhost logs: sc logs serverhost
Symptom: Files contain literal {{name}} instead of values.Solution:
  1. Check syntax: {{name}} (double braces, no spaces)
  2. Verify property exists in server context
  3. For custom properties use: {{$.property-name}}
Symptom: Workflow fails at copy step.Solution:
  1. Verify source path exists
  2. Check file permissions
  3. Add create-dirs: true if parent directories missing
Symptom: Plugins not downloaded during workflow.Solution:
  1. Check network connectivity to Modrinth/Hangar
  2. Verify plugin exists for your Minecraft version
  3. Check options/modrinth-platform-mappings.yml
Symptom: Workflow fails at compress or decompress step.Solution:
  1. Verify the archive format is supported (.tar.gz, .zip, .7z, etc.)
  2. Ensure the source path exists
  3. Check available disk space at the destination
Symptom: Workflow fails at upload step.Solution:
  1. Check network connectivity to the target URL
  2. Verify the bearer token is valid and correctly set
  3. Inspect the response code via upload.response.code context variable
  4. Ensure the source file exists and is not a directory