Skip to content

Instantly share code, notes, and snippets.

Last active May 25, 2023 15:41
What would you like to do?
lxc-arch2: a script to create a copy of my Arch Linux system in systemd-nspawn for testing
#!/bin/zsh -e
cd ~/tmpfs
mkdir -p .lxc-root .lxc-data/root/etc .lxc-work
sudo GDK_DPI_SCALE=$GDK_DPI_SCALE zsh -e - <<'EOF'
chown 0:0 .lxc-data/root .lxc-data/root/etc
modprobe overlay
mountpoint .lxc-root || mount -t overlay -o lowerdir=/,upperdir=$PWD/.lxc-data/root,workdir=$PWD/.lxc-root overlayfs $PWD/.lxc-root
# .lxc-root/etc/resolv.conf is protected
echo nameserver > .lxc-data/root/etc/resolv.conf
rm -f .lxc-root/etc/fstab
rm -r .lxc-root/var/log/journal
mkdir -p .lxc-root/var/log/journal
chgrp systemd-journal .lxc-root/var/log/journal
setfacl -Rnm g:systemd-journal:rx,d:g:systemd-journal:rx .lxc-root/var/log/journal
setopt null_glob extended_glob
ln -sf /usr/lib/systemd/system/ .lxc-root/etc/systemd/system/
rm -f .lxc-root/etc/systemd/system/*~*/sshd.service
rm -f .lxc-root/etc/systemd/user/
rm -f .lxc-root/etc/systemd/system/
rm -f .lxc-root/usr/lib/systemd/system/
rm -f .lxc-root/usr/lib/systemd/system/*.timer
rm -rf .lxc-root/usr/etc/systemd/system/
rm -rf .lxc-root/usr/lib/systemd/system/
rm -f .lxc-root//usr/lib/systemd/system-generators/nfs-server-generator
# this makes systemd-tmpfiles-setup.service fail on ro /sys
rm -f .lxc-root/usr/lib/tmpfiles.d/linux-firmware.conf
unsetopt null_glob
ln -sf /usr/lib/systemd/system/rc-local.service .lxc-root/etc/systemd/system/
cat > .lxc-root/etc/rc.local <<'RCLOCAL'
ip address add dev host0
ip link set host0 up
ip route add default via
chmod +x .lxc-root/etc/rc.local
echo lxc-arch2 > .lxc-root/etc/hostname
mkdir -p .lxc-data/root/home/lilydjwg
setfattr -n trusted.overlay.opaque -v y .lxc-data/root/home/lilydjwg
chown lilydjwg: .lxc-root/home/lilydjwg
touch .lxc-root/etc/.updated
mkdir -p .lxc-data/root/home/lilydjwg/.config/htop
cp {~,.lxc-data/root/home/lilydjwg}/.config/htop/htoprc
mkdir -p .lxc-data/root/home/lilydjwg/.local/share/applications
cp {~,.lxc-data/root/home/lilydjwg}/.local/share/applications/mimeinfo.cache
alsomount () {
local src=$1
local dest=${2:-$src}
local name=${${src##*/}#.}
if ! mountpoint .lxc-root$src; then
mkdir -p $PWD/.lxc-work/$name $PWD/.lxc-root$dest $PWD/.lxc-data/root$dest $PWD/.lxc-data/$name
mount -t overlay -o lowerdir=$src,upperdir=$PWD/.lxc-data/$name,workdir=$PWD/.lxc-work/$name overlayfs $PWD/.lxc-root$dest
mount --bind $PWD/.lxc-data/$name $PWD/.lxc-data/root$dest
bindmount () {
local p=$1
if ! mountpoint .lxc-root$p; then
mkdir -p .lxc-root$p
mount --bind $p .lxc-root$p
alsomount /home/lilydjwg/.zsh
for r in root home/lilydjwg; do
mkdir -p .lxc-root/$r/.ssh
chmod 700 .lxc-root/$r/.ssh
echo ZSH_PS_HOST=lxc-arch2 >> .lxc-root/$r/.zsh/zshrc.local
cp ~lilydjwg/.ssh/ .lxc-root/$r/.ssh/authorized_keys
cp ~lilydjwg/.zprofile .lxc-root/$r
chown -R ${r##*/}:${r##*/} .lxc-root/$r/.ssh .lxc-root/$r/.zsh/zshrc.local .lxc-root/$r/.zprofile
if [[ $r != root ]]; then
ln -s .zsh/zshrc .lxc-root/$r/.zshrc || true
chown -R ${r##*/}:${r##*/} .lxc-root/$r/.zshrc .lxc-root/$r/{.config,.local}
sed -i '/^root:/s/bash/zsh/' .lxc-root/etc/passwd
cat <<CONFIG >> .lxc-root/home/lilydjwg/.zsh/zshrc.local
export DISPLAY=
export GTK_IM_MODULE=xim QT_IM_MODULE=xim XMODIFIERS=@im=fcitx
alsomount /home/lilydjwg/.vim
alsomount /home/lilydjwg/.cache
chown lilydjwg: .lxc-root/home/lilydjwg/{.vim,.zsh,.cache}
bindmount /var/cache/pacman/pkg
# using systemd-nspawn:
sudo zsh -c "systemd-nspawn --network-bridge=br0 --boot -D .lxc-root; mount -o remount,rw .lxc-root"
# old way: use lxc. Remember to update network interface: host0 -> eth0.
# sudo zsh -c "lxc-start -F -n arch2; mount -o remount,rw .lxc-root"
# cleanup
# sudo umount -R .lxc-root .lxc-data/root/home/lilydjwg/{.cache,.vim,.zsh} && sudo rm -rf .lxc-data .lxc-root .lxc-work
# = arch2
lxc.autodev = 1
lxc.tty.max = 1
lxc.pty.max = 1024
lxc.rootfs.path = /home/lilydjwg/tmpfs/.lxc-root
# this prevents kbd and sound getting reset = proc sys
lxc.cap.drop = mknod sys_module mac_admin mac_override sys_time
#networking = veth = br0 = up = eth0 =
lxc.cgroup.devices.deny = a
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
lxc.cgroup.devices.allow = c 1:7 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# pts
lxc.cgroup.devices.allow = c 136:* rwm
Copy link

lilydjwg commented Mar 14, 2015

See my blog post for more (in Chinese).

It used to use lxc but now I run it with systemd-nspawn with a little modification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment