Some useful systemd nspawn containers configurations.
Find a file
2026-07-10 22:12:42 +08:00
container-prod-jenkins
container-prod-mail update spam pattern 2026-07-10 22:12:42 +08:00
container-prod-openresty
container-sandbox-browser
.gitignore
debootstrap.sh small change 2026-06-21 22:11:28 +08:00
prepare.sh use find -L 2026-04-30 21:43:12 +08:00
readme.org fix(mail-config): refine subject regexes and update README 2026-04-17 09:42:05 +08:00

main

Introduction

Why systemd-nspawn?

Because I want the fully control of container: running what, how to running. Docker is a highly encapsulated solution, it is easy and quick for normal users, and it is also inconvenience for hacking.

About this repository

Configuration files to run some systemd-nspawn containers. Notes that container image/directory itself is not stored here.

Where is image files

They are put at another repository on github. I prefer to exploit github ruthlessly, this is what they deserve, rather than consuming storage on codeberg.org.

Directory design

Concept

Assume container name is xxx

repository

                                overlay base path                                                         container base path
xxx          
|             link to                                                                                container's image/directory
xxx/default  ------->  /overlay_base_path/xxx/default            \                                    /container_base_path/xxx
                                                                  +-----  overlayfs                              |
                      /overlay_base_path/xxx/overlay (optional)  /                  \                 /----------v----
                                                                                     +-------------- +      container
                                                                                     /                \_______________
                                                                      other bind dirs
                                                                      
                                                                      for example:
                                                                      /path1
                                                                      /path2
                                                                         ^
                                                                         |
                                                             to store your persistent data. They will not be touched by prepare.sh
Explain
  • xxx, each container's config is put under its sub directory
  • xxx/default, for storing configurations files defaults. It should be modified as your need, before launching containers. Latter it will be linked to xxx/default under base overlay path, when you run prepare.sh's mkdir action.
  • xxx/default/path/to/.nspawn-container

    Current overlay implementation in systemd-nspawn is a little strange: when highest directory tree in overlay is set to empty, the owner of target directory in container will be nobody probably (when you enable PrivateUser), which makes it is impossible to create/delete/modify files under target directory direct level.

    The workaround is (notices below are only useful when you are using a empty string as highest overlay directory tree, like Overlay=+/container/path:/host/path::/container/path):

    • For modifying files under overlay's target directory direct level when you have a empty string as highest overlay directory tree, put real files you must modify to a special directory named .nspawn-container, then link them back to their original, appropriate location. And modify all related scripts or other launch files to process the link target file instead.
    • For creating new files under overlay's target directory direct level when you have a empty string as highest overlay directory tree, define them under xxx/default/path/to first. Under this case, if they are directories, I use a special file .placeholder to indicate these directories created in advance.
    • Modify all related scripts or other launch files to:

      • never delete files under target directory direct level

Currently supported containers

Prepare

Notes that this section only introduce the preparation before running containers.

common

(Optional) /var/lib/machines

You can store container image/directory at another location, then link it to /var/lib/machines.

Download and import the container root file system
# for example
bash prepare.sh [container_name] import https://github.com/emacs-gnu2/systemd-nspawn-image/releases/download/openresty-20251208/container-prod-openresty-20251208.tar.xz
# or
bash prepare.sh [container_name] import /path/to/xx.tar.xz

container-prod-mail

Install mariadb, then create user in mariadb manually.

bash prepare.sh container-prod-mail host
bash prepare.sh container-prod-mail mkdb
bash prepare.sh container-prod-mail mkdir

Then you can grant database permissions for specific user in mariadb

container-prod-jenkins

Download jdk archives and extract them under currently default bind source directory /data/app/jenkins-java-versions/

Notes that you must contain a jdk version used in jenkins.service at least.

bash prepare.sh container-prod-jenkins mkdir

container-prod-openresty

bash prepare.sh container-prod-openresty host
bash prepare.sh container-prod-openresty mkdir

Put your nginx config files under /data/app/openresty-nginx-conf/

container-sandbox-browser

Recommend run prepare.sh as a normal user.

Commands below are suitable for creating one or more instances

# import base container first
bash prepare.sh container-sandbox-browser import ...

bash prepare.sh container-sandbox-browser1 mkdir
# put necessary files under highest overlay dirs, then
bash prepare.sh container-sandbox-browser1 chown ...

Run containers

After appropriate preparation (see section above):

Execute bash prepare.sh xxx start normally.

For enable auto-start of container, run bash prepare.sh xxx enable

prepare.sh

Requirements

  • gawk sed xz-utils systemd-container

Arguments

  • first argument is the container name, use the directory name in this repository, like 'container-prod-mail'
  • second argument is the action, accepted values see section below.
  • rest arguments are passed to the specified action

Supported action

show

Display related paths of a container.

Example

prepare.sh xxx show
ls

List all releated files of a container, can be used to verify their existing, owner, permission etc.

Example

prepare.sh xxx ls | less
start
stop, poweroff
shell
login
rm

Shutdown and remove container

This also delete one container's:

  • all overlay destination directories, under overlay base path, including lower default/ and the highest overlay/. Overlay source directory in this repository will not be removed.
  • /etc/systemd/nspawn/xxx.nspawn
  • container's image/directory, under container base path
  • Other related host files if it has any (like: /etc/sysctl.d/xxx.conf, /etc/systemd/system/systemd-nspawn@xxx.service.d/)

But will NOT remove:

  • bind directories
host
mkdb
mkdir

Create the overlay/bind directories and change their owner automatically.

This action requires importing container root filesystem first.

chown

Explicitly requires changing owner of all overlay/bind directories again.

Example:

prepare.sh xxx chown 34346436
findchange
export
import
diff

Limitation

All overlay/bind directories preset are hard coded

If you want to use a different paths, like:

  • base dir to store containers image/directory, or in other words, container base dir
  • base dir to store overlay directories (including which named default), or in other words, overlay base dir
  • bind source directories

You should change these files by yourself:

  • xxx/xxx.nspawn, for changing overlay directories, bind source directories
  • prepare.sh, should keep consistency with corresponding .nspawn file

    • locate the # CUSTOM HERE comment

      • modify container_base_dir, for changing the base dir to store containers image/directory
      • modify data_base_dir, for changing base dir to store overlay directories
      • modify bind_dirs, for changing all bind source directories of this container

todo

TODO update container-prod-mail files

  • State "TODO" from [2026-02-27 五 09:57]