Docs/ Deployment/ Templates

Templates

Deploy one of the 171 templates built into sh0: a ready-made set of containers, volumes and generated secrets, described in a YAML file.

The catalog

Version 1.10.2 ships 171 templates, compiled into the sh0 binary: the catalog is the same on every server running that version, and it changes only with an update of sh0. They are grouped in 24 categories:

CategoryTemplatesExamples
devtools20gitea-runner, dozzle, hoppscotch, code-server
productivity18baserow, excalidraw, homepage, docuseal
database17chroma, couchdb, cockroachdb, cassandra
media16immich, filebrowser, lidarr, jellyseerr
cms12ghost, laravel, october-cms, pocketbase
runtime10php-8.0, php-7.4, php-8.1, php-7.3
networking9adguard-home, headscale, nginx-pm, netmaker
analytics9influxdb, posthog, questdb, clickhouse
ai9anything-llm, dify, langfuse, n8n
communication7cal-com, chatwoot, zulip, matrix-synapse
auth7authentik, authelia, keycloak, logto
finance6akaunting, actual-budget, invoice-ninja, erp-next
service4homebridge, node-red, duplicati, restic-server
queue4kafka, nats, rabbitmq, redpanda
monitoring4changedetection, uptime-kuma, jaeger, loki
storage3minio, seaweedfs, garage
search3meilisearch, opensearch, typesense
forum3flarum, discourse, nodebb
cache3dragonfly, memcached, keydb
email2stalwart, docker-mailserver
ecommerce2saleor, prestashop
marketing1postiz
education1moodle
ai-ml1mindsdb

sh0 templates list prints the whole catalog with each template's category and description. In version 1.10.2 its SERVICES column always shows 0; use sh0 templates info <name> to see the services.

Some templates carry a notice in the dashboard: Frozen image when they use bitnamilegacy/* images, a frozen archive that no longer receives security patches, and Community image for the community rebuild of MinIO.

Deploying a template

In the dashboard, open Templates, find the template with the search box, and click Deploy. Give the Application Name, review the Variables (secrets marked Auto-generated are created for you), then confirm with Deploy Template.

From the CLI, sh0 templates info shows what a template will create:

Terminal
$ sh0 templates info ghost
  Template: ghost
  Description: Ghost publishing platform with MySQL database
  Category: cms
  Tags: cms, blog, publishing

  Services:
    - ghost (image: ghost:6-alpine, port: 2368, exposed)
    - mysql (image: mysql:8, port: 3306)

  Variables:
  KEY          REQUIRED  DEFAULT  DESCRIPTION
  -----------  --------  -------  ---------------------------
  DB_PASSWORD  auto      -        Database password for Ghost

Then sh0 templates deploy <template> --app-name <name> deploys it, with --var KEY=VALUE (repeatable) to set a variable yourself:

Terminal
$ sh0 templates deploy it-tools --app-name my-tools
[*] Deploying template 'it-tools' as 'my-tools'...
Error: Failed to parse response

Caused by:
    missing field `app_id` at line 1 column 650

$ sh0 apps
  NAME      STATUS   BRANCH  PORT  REPLICAS  UPDATED
  --------  -------  ------  ----  --------  -------
  my-tools  running  main    80    1         14s ago
Warning
In version 1.10.2, sh0 templates deploy ends with Failed to parse response although the server has accepted the request and the deployment goes on. Check the result with sh0 apps or in the dashboard rather than relying on the exit code.

A deployed template becomes one app whose services are listed in its page. Redeploying such an app (Deploy button or sh0 deploy) fails in version 1.10.2 with App has no repository URL configured; the services already running are not affected.

Variables

Values in a template may contain ${NAME} placeholders, resolved at deployment time from the template's variables list:

  • generated: secret_32 or secret_64 creates a random secret of that length (143 and 26 templates use them); password is also accepted.
  • default gives a value used when you set none; required: true makes the variable mandatory.
  • ${DOMAIN} needs no declaration: sh0 replaces it with the domain it assigns to the app.

Template format

Each template is one YAML file in the templates/ directory of the sh0 source. Here is ghost.yaml as shipped in version 1.10.2:

templates/ghost.yaml
# Ghost -- Modern publishing platform with MySQL backend
name: ghost
description: Ghost publishing platform with MySQL database
icon: ghost
category: cms
tags:
  - cms
  - blog
  - publishing

services:
  - name: ghost
    image: ghost:6-alpine
    port: 2368
    expose: true
    env:
      url: "https://${DOMAIN}"
      database__client: mysql
      database__connection__host: mysql
      database__connection__user: ghost
      database__connection__password: "${DB_PASSWORD}"
      database__connection__database: ghost
      NODE_ENV: production
    volumes:
      - ghost-data:/var/lib/ghost/content
    depends_on:
      - mysql
    memory_mb: 512
    cpu_cores: 0.5

  - name: mysql
    image: mysql:8
    port: 3306
    expose: false
    env:
      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
      MYSQL_DATABASE: ghost
      MYSQL_USER: ghost
      MYSQL_PASSWORD: "${DB_PASSWORD}"
    volumes:
      - db-data:/var/lib/mysql
    memory_mb: 512
    cpu_cores: 0.5

volumes:
  - name: ghost-data
  - name: db-data

variables:
  - name: DB_PASSWORD
    description: Database password for Ghost
    required: true
    generated: secret_32

Besides name, image, port, env, volumes, depends_on, memory_mb and cpu_cores, a service accepts command and entrypoint. expose: true marks the primary service, the one that receives the app's public address; a secondary service gets its own public address only with route: true. Services without either stay internal and are reached by their name, as mysql above.

Your own templates

Version 1.10.2 cannot load a template from a file or a URL: the catalog is the one compiled into the binary. To deploy your own multi-container stack, use a Docker Compose file.