<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.csclub.uwaterloo.ca/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=M5choo</id>
	<title>CSCWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.csclub.uwaterloo.ca/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=M5choo"/>
	<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/Special:Contributions/M5choo"/>
	<updated>2026-06-01T19:10:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.44.5</generator>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=Systemd-nspawn&amp;diff=5648</id>
		<title>Systemd-nspawn</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=Systemd-nspawn&amp;diff=5648"/>
		<updated>2026-05-30T20:40:35Z</updated>

		<summary type="html">&lt;p&gt;M5choo: Add info for migrating resource limit infos and nspawn configs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn] is a simpler alternative to [https://wiki.csclub.uwaterloo.ca/Virtualization_(LXC_Containers) LXC] which works well on modern versions of Debian (and, unlike LXC, it does not break very critical systemd services running in containers). For &amp;quot;pet&amp;quot; containers, we should be using systemd-nspawn; for &amp;quot;cattle&amp;quot; containers, [[Podman]] is more appropriate.&lt;br /&gt;
&lt;br /&gt;
Some light reading:&lt;br /&gt;
&lt;br /&gt;
* https://wiki.debian.org/nspawn&lt;br /&gt;
* https://wiki.archlinux.org/title/Systemd-nspawn&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
In the example below, we will create a container called &#039;machine1&#039;.&lt;br /&gt;
&lt;br /&gt;
Create a directory for the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/lib/machines/machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or, if you are using an LVM volume, just create a symlink in /var/lib/machines to where the LV is mounted:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ln -s /vm/machine1 /var/lib/machines/machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now bootstrap the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
debootstrap --variant=minbase --include=dbus,systemd-container,vim bookworm . http://mirror.csclub.uwaterloo.ca/debian&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that the &amp;lt;code&amp;gt;systemd-container&amp;lt;/code&amp;gt; package &amp;lt;b&amp;gt;must&amp;lt;/b&amp;gt; be installed in the guest.&lt;br /&gt;
&lt;br /&gt;
Now do a bit of setup in the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chroot /var/lib/machines/machine1&lt;br /&gt;
# Only do this if you want to use `machinectl login`&lt;br /&gt;
passwd -d root&lt;br /&gt;
cat &amp;lt;&amp;lt;EOF &amp;gt;&amp;gt;/etc/securetty&lt;br /&gt;
pts/0&lt;br /&gt;
pts/1&lt;br /&gt;
pts/2&lt;br /&gt;
pts/3&lt;br /&gt;
EOF&lt;br /&gt;
# set hostname&lt;br /&gt;
echo machine1 &amp;gt; /etc/hostname&lt;br /&gt;
# set FQDN&lt;br /&gt;
nano /etc/hosts&lt;br /&gt;
# Use systemd-networkd for network management. See &lt;br /&gt;
vim /etc/systemd/network/10-hostbr0.network&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now paste the following into /etc/systemd/nspawn/machine1.nspawn:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Exec]&lt;br /&gt;
Boot=yes&lt;br /&gt;
Hostname=machine1&lt;br /&gt;
PrivateUsers=no&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
Bridge=br0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Replace &#039;br0&#039; by the bridge interface on the host to which the container should be attached (a veth pair will be created when the container starts up).&lt;br /&gt;
&lt;br /&gt;
Also make sure to set &#039;PrivateUsers=no&#039;, because by default systemd-nspawn uses some randomized UID/GID mapping which makes it difficult to migrate the container to a different system.&lt;br /&gt;
&lt;br /&gt;
Now start the container:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl start systemd-nspawn@machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or alternatively, using &amp;lt;code&amp;gt;machinectl&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl start machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To login to a container via an emulated serial console (I don&#039;t recommend doing this, since the TTY gets screwed up):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl login machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attach to a running container (similar to &amp;lt;code&amp;gt;lxc-attach&amp;lt;/code&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl shell machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Note&amp;lt;/b&amp;gt;: if you see the error &amp;lt;code&amp;gt;sh: 2: exec: : Permission denied&amp;lt;/code&amp;gt;, append /bin/bash to the end of the command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl shell machine1 /bin/bash&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Important&amp;lt;/b&amp;gt;: make sure the container starts up at boot:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl enable systemd-nspawn@machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Multiple network interfaces ==&lt;br /&gt;
Unfortunately systemd does not have a built-in way to create [https://github.com/systemd/systemd/issues/11087 multiple bridged network interfaces]. Thankfully, it&#039;s not too difficult to accomplish this using the &amp;lt;code&amp;gt;VirtualEthernetExtra&amp;lt;/code&amp;gt; option and a systemd drop-in; the idea is to create some extra veth pairs and then manually attach them to the bridge.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have three bridges on the host: br0, br1 and br2, and you want the container to be attached to all three. Make your nspawn file look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
[Network]&lt;br /&gt;
Bridge=br0&lt;br /&gt;
# These will be manually bridged to the host&lt;br /&gt;
VirtualEthernetExtra=ve-machine1-1:veth1&lt;br /&gt;
VirtualEthernetExtra=ve-machine1-2:veth2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now run &amp;lt;code&amp;gt;systemctl edit systemd-nspawn@machine1&amp;lt;/code&amp;gt; and paste the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Service]&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 master br1&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 up&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 master br2&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 up&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the container, there will be three interfaces:&lt;br /&gt;
&lt;br /&gt;
* host0, which is attached to br0 on the host&lt;br /&gt;
* veth1, which is attached to br1 on the host&lt;br /&gt;
* veth2, which is attached to br2 on the host&lt;br /&gt;
&lt;br /&gt;
Make sure you update /etc/systemd/network/10-hostbr.network in the container accordingly.&lt;br /&gt;
&lt;br /&gt;
== Migrate to LXC ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
* Assumption is made that the original &amp;lt;code&amp;gt;systemd-nspawn&amp;lt;/code&amp;gt; runs on Debian.&lt;br /&gt;
* Source machine running the systemd-nspawn container (Debian 12 base architecture).&lt;br /&gt;
* Target Proxmox VE node with CLI access.&lt;br /&gt;
* Network connectivity (or storage media) to transfer the container archive.&lt;br /&gt;
* Matching processor architectures between source and destination (e.g., both amd64).&lt;br /&gt;
&lt;br /&gt;
=== Step 1: Package the Source Container ===&lt;br /&gt;
To prevent data inconsistency or race conditions during the compression phase, the running instance must be gracefully halted.&lt;br /&gt;
&lt;br /&gt;
# Log into the nspawn host and terminate the target container instance:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl stop &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Confirm the container is inactive and no lingering worker threads exist:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl list&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Navigate to the root filesystem directory (typically located under &amp;lt;code&amp;gt;/var/lib/machines/&amp;lt;/code&amp;gt;). Create a compressed tarball archive using relative path positioning:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;tar -cvzf container_backup.tar.gz -C /var/lib/machines/&amp;lt;container_name&amp;gt; .&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
#: &#039;&#039;Note: Utilizing the &amp;lt;code&amp;gt;-C&amp;lt;/code&amp;gt; flag preserves the nested structures directly inside the top level of the archive, omitting parent folder descriptors that break standard LXC unpacking loops.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Step 1.1: Extract Resource Limits and Metadata ====&lt;br /&gt;
Systemd-nspawn stores resource constraints and execution settings in &amp;lt;code&amp;gt;.nspawn&amp;lt;/code&amp;gt; files or systemd unit overrides. These should be referenced to ensure the Proxmox LXC matches the original performance profile.&lt;br /&gt;
&lt;br /&gt;
# Locate the specific settings for the container:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;systemctl cat nspawn@&amp;lt;container_name&amp;gt;.service&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Check for a manual configuration file (usually in &amp;lt;code&amp;gt;/etc/systemd/nspawn/&amp;lt;/code&amp;gt;):&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;cat /etc/systemd/nspawn/&amp;lt;container_name&amp;gt;.nspawn&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Note the following values to be used during the &amp;lt;code&amp;gt;pct create&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;pct set&amp;lt;/code&amp;gt; phase:&lt;br /&gt;
#* &#039;&#039;&#039;CPU Shares:&#039;&#039;&#039; Look for &amp;lt;code&amp;gt;CPUWeight&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;CPUShares&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &#039;&#039;&#039;Memory Limits:&#039;&#039;&#039; Look for &amp;lt;code&amp;gt;MemoryMax&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;MemoryLimit&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &#039;&#039;&#039;Environment Variables:&#039;&#039;&#039; Look for &amp;lt;code&amp;gt;Environment=&amp;lt;/code&amp;gt; lines.&lt;br /&gt;
#* &#039;&#039;&#039;Bind Mounts:&#039;&#039;&#039; Look for &amp;lt;code&amp;gt;Bind=&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;BindReadOnly=&amp;lt;/code&amp;gt; entries which will need to be recreated as &amp;quot;Mount Points&amp;quot; in Proxmox.&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Transfer the Payload to Proxmox ===&lt;br /&gt;
Transport the generated payload file to the centralized Proxmox storage pool designated for distribution packages.&lt;br /&gt;
&lt;br /&gt;
# Push the file to the default template cache path of your Proxmox server via secure copy protocol:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;scp container_backup.tar.gz root@&amp;lt;proxmox_ip&amp;gt;:/var/lib/vz/template/cache/&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3: Provision and Initialize the LXC Instance ===&lt;br /&gt;
Execute the container initialization binary via the Proxmox Command Line Interface. Select an unallocated Virtual Machine Identifier (VMID) code (e.g., &amp;lt;code&amp;gt;105&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
# Run the &amp;lt;code&amp;gt;pct create&amp;lt;/code&amp;gt; string mapping configuration details appropriately. The following should work fine in most scenarios, but don&#039;t forget to verify it for each migration case:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct create &amp;lt;VMID&amp;gt; /var/lib/vz/template/cache/container_backup.tar.gz \&lt;br /&gt;
  --hostname my-migrated-container \&lt;br /&gt;
  --storage vm \&lt;br /&gt;
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \&lt;br /&gt;
  --ostype debian \&lt;br /&gt;
  --arch amd64&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Parameter Breakdown ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 85%; text-align: left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #f2f2f2;&amp;quot;&lt;br /&gt;
! Parameter !! Type !! Purpose / Operational Notes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&amp;lt;VMID&amp;gt;&#039;&#039;&#039; || Integer || Target ID assignment for isolation reference.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Path String&#039;&#039;&#039; || Filepath || Literal path pointing directly toward the moved &amp;lt;code&amp;gt;.tar.gz&amp;lt;/code&amp;gt; bundle.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--storage&#039;&#039;&#039; || Target Storage || Defines where the newly expanded disk images live. (Can use &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;local-lvm&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--ostype&#039;&#039;&#039; || String ID || Configures automated networking script hooks inside guest boundaries. Use &#039;&#039;&#039;debian&#039;&#039;&#039; even if host hypervisor builds use an upstream point release.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--net0&#039;&#039;&#039; || Interface String || Sets the internal interface name, upstream virtualization bridge, and network configuration method (e.g., DHCP).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Step 4: Post-Migration Integration Tasks ===&lt;br /&gt;
Before setting the automated power-on directive, minor discrepancies must be assessed:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Resource Alignment:&#039;&#039;&#039; Reference the metrics extracted in &#039;&#039;&#039;Step 1.1&#039;&#039;&#039; (CPU, RAM, Mounts) and apply them via the Proxmox UI under the &#039;&#039;&#039;Resources&#039;&#039;&#039; tab or via &amp;lt;code&amp;gt;pct set &amp;lt;vmid&amp;gt; -memory &amp;lt;MB&amp;gt; -cores &amp;lt;number&amp;gt;&amp;lt;/code&amp;gt; to maintain performance parity.&lt;br /&gt;
* &#039;&#039;&#039;Systemd Nesting:&#039;&#039;&#039; Enable nesting to allow the guest systemd to manage its internal units. Navigate to &#039;&#039;&#039;Options&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Features&#039;&#039;&#039; -&amp;gt; Check &#039;&#039;&#039;nesting&#039;&#039;&#039;, or run:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct set &amp;lt;VMID&amp;gt; --features nesting=1&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;User Privilege Level Constraints:&#039;&#039;&#039; By default, Proxmox creates unprivileged namespaces for safety. If the nspawn container expects hardware node execution access, or special system task levels, go to the &#039;&#039;&#039;Options&#039;&#039;&#039; pane within the web terminal and modify state permissions to Privileged.&lt;br /&gt;
* &#039;&#039;&#039;Network Manager Hooks:&#039;&#039;&#039; If &amp;lt;code&amp;gt;systemd-networkd&amp;lt;/code&amp;gt; or localized static loops exist inside the original container structure, it may conflict with parameters injected via Proxmox. Consider clearing internal static state binds if link interface problems materialize.&lt;br /&gt;
&lt;br /&gt;
=== Step 5: Start and Verify Instance Health ===&lt;br /&gt;
# Start the newly provisioned infrastructure slice:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct start &amp;lt;VMID&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Intercept terminal standard streams to execute verification checks internally:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct enter &amp;lt;VMID&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Review service status tables inside the active root environment:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;systemctl status&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 6: Decommission the Source Instance ===&lt;br /&gt;
Once the container is confirmed functional on Proxmox, the original files and configurations should be removed from the nspawn host to reclaim storage.&lt;br /&gt;
&lt;br /&gt;
# Permanently delete the container image and its associated configuration files:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl terminate &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl remove &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Verify the machine is no longer indexed:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl list-images&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Manually remove the transferred tarball from the nspawn host&#039;s local storage:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;rm container_backup.tar.gz&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== (Optional) Step 7: Update container ===&lt;br /&gt;
It&#039;s time to update apt repos and upgrade packages!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update&lt;br /&gt;
apt upgrade -y&lt;br /&gt;
apt full-upgrade -y&lt;br /&gt;
apt autoremove --purge&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally, if the container is running on Debian 12 and you want Debian 13, upgrade the container to Debian 13 after consulting other Syscom members. (Good luck dealing with &amp;lt;code&amp;gt;/etc/apt/sources.list{,.d}&amp;lt;/code&amp;gt; configs)&lt;/div&gt;</summary>
		<author><name>M5choo</name></author>
	</entry>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=Systemd-nspawn&amp;diff=5647</id>
		<title>Systemd-nspawn</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=Systemd-nspawn&amp;diff=5647"/>
		<updated>2026-05-30T20:23:28Z</updated>

		<summary type="html">&lt;p&gt;M5choo: Add optional step for upgrading packages&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn] is a simpler alternative to [https://wiki.csclub.uwaterloo.ca/Virtualization_(LXC_Containers) LXC] which works well on modern versions of Debian (and, unlike LXC, it does not break very critical systemd services running in containers). For &amp;quot;pet&amp;quot; containers, we should be using systemd-nspawn; for &amp;quot;cattle&amp;quot; containers, [[Podman]] is more appropriate.&lt;br /&gt;
&lt;br /&gt;
Some light reading:&lt;br /&gt;
&lt;br /&gt;
* https://wiki.debian.org/nspawn&lt;br /&gt;
* https://wiki.archlinux.org/title/Systemd-nspawn&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
In the example below, we will create a container called &#039;machine1&#039;.&lt;br /&gt;
&lt;br /&gt;
Create a directory for the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/lib/machines/machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or, if you are using an LVM volume, just create a symlink in /var/lib/machines to where the LV is mounted:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ln -s /vm/machine1 /var/lib/machines/machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now bootstrap the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
debootstrap --variant=minbase --include=dbus,systemd-container,vim bookworm . http://mirror.csclub.uwaterloo.ca/debian&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that the &amp;lt;code&amp;gt;systemd-container&amp;lt;/code&amp;gt; package &amp;lt;b&amp;gt;must&amp;lt;/b&amp;gt; be installed in the guest.&lt;br /&gt;
&lt;br /&gt;
Now do a bit of setup in the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chroot /var/lib/machines/machine1&lt;br /&gt;
# Only do this if you want to use `machinectl login`&lt;br /&gt;
passwd -d root&lt;br /&gt;
cat &amp;lt;&amp;lt;EOF &amp;gt;&amp;gt;/etc/securetty&lt;br /&gt;
pts/0&lt;br /&gt;
pts/1&lt;br /&gt;
pts/2&lt;br /&gt;
pts/3&lt;br /&gt;
EOF&lt;br /&gt;
# set hostname&lt;br /&gt;
echo machine1 &amp;gt; /etc/hostname&lt;br /&gt;
# set FQDN&lt;br /&gt;
nano /etc/hosts&lt;br /&gt;
# Use systemd-networkd for network management. See &lt;br /&gt;
vim /etc/systemd/network/10-hostbr0.network&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now paste the following into /etc/systemd/nspawn/machine1.nspawn:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Exec]&lt;br /&gt;
Boot=yes&lt;br /&gt;
Hostname=machine1&lt;br /&gt;
PrivateUsers=no&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
Bridge=br0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Replace &#039;br0&#039; by the bridge interface on the host to which the container should be attached (a veth pair will be created when the container starts up).&lt;br /&gt;
&lt;br /&gt;
Also make sure to set &#039;PrivateUsers=no&#039;, because by default systemd-nspawn uses some randomized UID/GID mapping which makes it difficult to migrate the container to a different system.&lt;br /&gt;
&lt;br /&gt;
Now start the container:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl start systemd-nspawn@machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or alternatively, using &amp;lt;code&amp;gt;machinectl&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl start machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To login to a container via an emulated serial console (I don&#039;t recommend doing this, since the TTY gets screwed up):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl login machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attach to a running container (similar to &amp;lt;code&amp;gt;lxc-attach&amp;lt;/code&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl shell machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Note&amp;lt;/b&amp;gt;: if you see the error &amp;lt;code&amp;gt;sh: 2: exec: : Permission denied&amp;lt;/code&amp;gt;, append /bin/bash to the end of the command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl shell machine1 /bin/bash&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Important&amp;lt;/b&amp;gt;: make sure the container starts up at boot:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl enable systemd-nspawn@machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Multiple network interfaces ==&lt;br /&gt;
Unfortunately systemd does not have a built-in way to create [https://github.com/systemd/systemd/issues/11087 multiple bridged network interfaces]. Thankfully, it&#039;s not too difficult to accomplish this using the &amp;lt;code&amp;gt;VirtualEthernetExtra&amp;lt;/code&amp;gt; option and a systemd drop-in; the idea is to create some extra veth pairs and then manually attach them to the bridge.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have three bridges on the host: br0, br1 and br2, and you want the container to be attached to all three. Make your nspawn file look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
[Network]&lt;br /&gt;
Bridge=br0&lt;br /&gt;
# These will be manually bridged to the host&lt;br /&gt;
VirtualEthernetExtra=ve-machine1-1:veth1&lt;br /&gt;
VirtualEthernetExtra=ve-machine1-2:veth2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now run &amp;lt;code&amp;gt;systemctl edit systemd-nspawn@machine1&amp;lt;/code&amp;gt; and paste the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Service]&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 master br1&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 up&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 master br2&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 up&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the container, there will be three interfaces:&lt;br /&gt;
&lt;br /&gt;
* host0, which is attached to br0 on the host&lt;br /&gt;
* veth1, which is attached to br1 on the host&lt;br /&gt;
* veth2, which is attached to br2 on the host&lt;br /&gt;
&lt;br /&gt;
Make sure you update /etc/systemd/network/10-hostbr.network in the container accordingly.&lt;br /&gt;
&lt;br /&gt;
== Migrate to LXC ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
* Assumption is made that the original &amp;lt;code&amp;gt;systemd-nspawn&amp;lt;/code&amp;gt; runs on Debian.&lt;br /&gt;
* Source machine running the systemd-nspawn container (Debian 12 base architecture).&lt;br /&gt;
* Target Proxmox VE node with CLI access.&lt;br /&gt;
* Network connectivity (or storage media) to transfer the container archive.&lt;br /&gt;
* Matching processor architectures between source and destination (e.g., both amd64).&lt;br /&gt;
&lt;br /&gt;
=== Step 1: Package the Source Container ===&lt;br /&gt;
To prevent data inconsistency or race conditions during the compression phase, the running instance must be gracefully halted.&lt;br /&gt;
&lt;br /&gt;
# Log into the nspawn host and terminate the target container instance:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl stop &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Confirm the container is inactive and no lingering worker threads exist:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl list&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Navigate to the root filesystem directory (typically located under &amp;lt;code&amp;gt;/var/lib/machines/&amp;lt;/code&amp;gt;). Create a compressed tarball archive using relative path positioning:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;tar -cvzf container_backup.tar.gz -C /var/lib/machines/&amp;lt;container_name&amp;gt; .&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
#: &#039;&#039;Note: Utilizing the &amp;lt;code&amp;gt;-C&amp;lt;/code&amp;gt; flag preserves the nested structures directly inside the top level of the archive, omitting parent folder descriptors that break standard LXC unpacking loops.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Transfer the Payload to Proxmox ===&lt;br /&gt;
Transport the generated payload file to the centralized Proxmox storage pool designated for distribution packages.&lt;br /&gt;
&lt;br /&gt;
# Push the file to the default template cache path of your Proxmox server via secure copy protocol:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;scp container_backup.tar.gz root@&amp;lt;proxmox_ip&amp;gt;:/var/lib/vz/template/cache/&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3: Provision and Initialize the LXC Instance ===&lt;br /&gt;
Execute the container initialization binary via the Proxmox Command Line Interface. Select an unallocated Virtual Machine Identifier (VMID) code (e.g., &amp;lt;code&amp;gt;105&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
# Run the &amp;lt;code&amp;gt;pct create&amp;lt;/code&amp;gt; string mapping configuration details appropriately. The following should work fine in most scenarios, but don&#039;t forget to verify it for each migration case:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct create &amp;lt;VMID&amp;gt; /var/lib/vz/template/cache/container_backup.tar.gz \&lt;br /&gt;
  --hostname my-migrated-container \&lt;br /&gt;
  --storage vm \&lt;br /&gt;
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \&lt;br /&gt;
  --ostype debian \&lt;br /&gt;
  --arch amd64&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Parameter Breakdown ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 85%; text-align: left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #f2f2f2;&amp;quot;&lt;br /&gt;
! Parameter !! Type !! Purpose / Operational Notes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&amp;lt;VMID&amp;gt;&#039;&#039;&#039; || Integer || Target ID assignment for isolation reference.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Path String&#039;&#039;&#039; || Filepath || Literal path pointing directly toward the moved &amp;lt;code&amp;gt;.tar.gz&amp;lt;/code&amp;gt; bundle.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--storage&#039;&#039;&#039; || Target Storage || Defines where the newly expanded disk images live. (Can use &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;local-lvm&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--ostype&#039;&#039;&#039; || String ID || Configures automated networking script hooks inside guest boundaries. Use &#039;&#039;&#039;debian&#039;&#039;&#039; even if host hypervisor builds use an upstream point release.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--net0&#039;&#039;&#039; || Interface String || Sets the internal interface name, upstream virtualization bridge, and network configuration method (e.g., DHCP).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Step 4: Post-Migration Integration Tasks ===&lt;br /&gt;
Before setting the automated power-on directive, minor discrepancies must be assessed:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Systemd Nesting:&#039;&#039;&#039; Enable nesting to allow the guest systemd to manage its internal units. Navigate to &#039;&#039;&#039;Options&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Features&#039;&#039;&#039; -&amp;gt; Check &#039;&#039;&#039;nesting&#039;&#039;&#039;, or run:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct set &amp;lt;VMID&amp;gt; --features nesting=1&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;User Privilege Level Constraints:&#039;&#039;&#039; By default, Proxmox creates unprivileged namespaces for safety. If the nspawn container expects hardware node execution access, or special system task levels, go to the &#039;&#039;&#039;Options&#039;&#039;&#039; pane within the web terminal and modify state permissions to Privileged.&lt;br /&gt;
* &#039;&#039;&#039;Network Manager Hooks:&#039;&#039;&#039; If &amp;lt;code&amp;gt;systemd-networkd&amp;lt;/code&amp;gt; or localized static loops exist inside the original container structure, it may conflict with parameters injected via Proxmox. Consider clearing internal static state binds if link interface problems materialize.&lt;br /&gt;
&lt;br /&gt;
=== Step 5: Start and Verify Instance Health ===&lt;br /&gt;
# Start the newly provisioned infrastructure slice:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct start &amp;lt;VMID&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Intercept terminal standard streams to execute verification checks internally:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct enter &amp;lt;VMID&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Review service status tables inside the active root environment:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;systemctl status&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 6: Decommission the Source Instance ===&lt;br /&gt;
Once the container is confirmed functional on Proxmox, the original files and configurations should be removed from the nspawn host to reclaim storage.&lt;br /&gt;
&lt;br /&gt;
# Permanently delete the container image and its associated configuration files:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl terminate &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl remove &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Verify the machine is no longer indexed:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl list-images&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Manually remove the transferred tarball from the nspawn host&#039;s local storage:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;rm container_backup.tar.gz&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== (Optional) Step 7: Update container ===&lt;br /&gt;
It&#039;s time to update apt repos and upgrade packages!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update&lt;br /&gt;
apt upgrade -y&lt;br /&gt;
apt full-upgrade -y&lt;br /&gt;
apt autoremove --purge&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally, if the container is running on Debian 12 and you want Debian 13, upgrade the container to Debian 13 after consulting other Syscom members. (Good luck dealing with &amp;lt;code&amp;gt;/etc/apt/sources.list{,.d}&amp;lt;/code&amp;gt; configs)&lt;/div&gt;</summary>
		<author><name>M5choo</name></author>
	</entry>
	<entry>
		<id>https://wiki.csclub.uwaterloo.ca/index.php?title=Systemd-nspawn&amp;diff=5646</id>
		<title>Systemd-nspawn</title>
		<link rel="alternate" type="text/html" href="https://wiki.csclub.uwaterloo.ca/index.php?title=Systemd-nspawn&amp;diff=5646"/>
		<updated>2026-05-30T20:17:10Z</updated>

		<summary type="html">&lt;p&gt;M5choo: Add migration guide for Proxmox LXC&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn] is a simpler alternative to [https://wiki.csclub.uwaterloo.ca/Virtualization_(LXC_Containers) LXC] which works well on modern versions of Debian (and, unlike LXC, it does not break very critical systemd services running in containers). For &amp;quot;pet&amp;quot; containers, we should be using systemd-nspawn; for &amp;quot;cattle&amp;quot; containers, [[Podman]] is more appropriate.&lt;br /&gt;
&lt;br /&gt;
Some light reading:&lt;br /&gt;
&lt;br /&gt;
* https://wiki.debian.org/nspawn&lt;br /&gt;
* https://wiki.archlinux.org/title/Systemd-nspawn&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
In the example below, we will create a container called &#039;machine1&#039;.&lt;br /&gt;
&lt;br /&gt;
Create a directory for the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /var/lib/machines/machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or, if you are using an LVM volume, just create a symlink in /var/lib/machines to where the LV is mounted:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ln -s /vm/machine1 /var/lib/machines/machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now bootstrap the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
debootstrap --variant=minbase --include=dbus,systemd-container,vim bookworm . http://mirror.csclub.uwaterloo.ca/debian&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that the &amp;lt;code&amp;gt;systemd-container&amp;lt;/code&amp;gt; package &amp;lt;b&amp;gt;must&amp;lt;/b&amp;gt; be installed in the guest.&lt;br /&gt;
&lt;br /&gt;
Now do a bit of setup in the rootfs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chroot /var/lib/machines/machine1&lt;br /&gt;
# Only do this if you want to use `machinectl login`&lt;br /&gt;
passwd -d root&lt;br /&gt;
cat &amp;lt;&amp;lt;EOF &amp;gt;&amp;gt;/etc/securetty&lt;br /&gt;
pts/0&lt;br /&gt;
pts/1&lt;br /&gt;
pts/2&lt;br /&gt;
pts/3&lt;br /&gt;
EOF&lt;br /&gt;
# set hostname&lt;br /&gt;
echo machine1 &amp;gt; /etc/hostname&lt;br /&gt;
# set FQDN&lt;br /&gt;
nano /etc/hosts&lt;br /&gt;
# Use systemd-networkd for network management. See &lt;br /&gt;
vim /etc/systemd/network/10-hostbr0.network&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now paste the following into /etc/systemd/nspawn/machine1.nspawn:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Exec]&lt;br /&gt;
Boot=yes&lt;br /&gt;
Hostname=machine1&lt;br /&gt;
PrivateUsers=no&lt;br /&gt;
&lt;br /&gt;
[Network]&lt;br /&gt;
Bridge=br0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Replace &#039;br0&#039; by the bridge interface on the host to which the container should be attached (a veth pair will be created when the container starts up).&lt;br /&gt;
&lt;br /&gt;
Also make sure to set &#039;PrivateUsers=no&#039;, because by default systemd-nspawn uses some randomized UID/GID mapping which makes it difficult to migrate the container to a different system.&lt;br /&gt;
&lt;br /&gt;
Now start the container:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl start systemd-nspawn@machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or alternatively, using &amp;lt;code&amp;gt;machinectl&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl start machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To login to a container via an emulated serial console (I don&#039;t recommend doing this, since the TTY gets screwed up):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl login machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attach to a running container (similar to &amp;lt;code&amp;gt;lxc-attach&amp;lt;/code&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl shell machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Note&amp;lt;/b&amp;gt;: if you see the error &amp;lt;code&amp;gt;sh: 2: exec: : Permission denied&amp;lt;/code&amp;gt;, append /bin/bash to the end of the command:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
machinectl shell machine1 /bin/bash&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Important&amp;lt;/b&amp;gt;: make sure the container starts up at boot:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl enable systemd-nspawn@machine1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Multiple network interfaces ==&lt;br /&gt;
Unfortunately systemd does not have a built-in way to create [https://github.com/systemd/systemd/issues/11087 multiple bridged network interfaces]. Thankfully, it&#039;s not too difficult to accomplish this using the &amp;lt;code&amp;gt;VirtualEthernetExtra&amp;lt;/code&amp;gt; option and a systemd drop-in; the idea is to create some extra veth pairs and then manually attach them to the bridge.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have three bridges on the host: br0, br1 and br2, and you want the container to be attached to all three. Make your nspawn file look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
[Network]&lt;br /&gt;
Bridge=br0&lt;br /&gt;
# These will be manually bridged to the host&lt;br /&gt;
VirtualEthernetExtra=ve-machine1-1:veth1&lt;br /&gt;
VirtualEthernetExtra=ve-machine1-2:veth2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now run &amp;lt;code&amp;gt;systemctl edit systemd-nspawn@machine1&amp;lt;/code&amp;gt; and paste the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Service]&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 master br1&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-1 up&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 master br2&lt;br /&gt;
ExecStartPost=/usr/sbin/ip link set dev ve-machine1-2 up&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the container, there will be three interfaces:&lt;br /&gt;
&lt;br /&gt;
* host0, which is attached to br0 on the host&lt;br /&gt;
* veth1, which is attached to br1 on the host&lt;br /&gt;
* veth2, which is attached to br2 on the host&lt;br /&gt;
&lt;br /&gt;
Make sure you update /etc/systemd/network/10-hostbr.network in the container accordingly.&lt;br /&gt;
&lt;br /&gt;
== Migrate to LXC ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
* Assumption is made that the original &amp;lt;code&amp;gt;systemd-nspawn&amp;lt;/code&amp;gt; runs on Debian.&lt;br /&gt;
* Source machine running the systemd-nspawn container (Debian 12 base architecture).&lt;br /&gt;
* Target Proxmox VE node with CLI access.&lt;br /&gt;
* Network connectivity (or storage media) to transfer the container archive.&lt;br /&gt;
* Matching processor architectures between source and destination (e.g., both amd64).&lt;br /&gt;
&lt;br /&gt;
=== Step 1: Package the Source Container ===&lt;br /&gt;
To prevent data inconsistency or race conditions during the compression phase, the running instance must be gracefully halted.&lt;br /&gt;
&lt;br /&gt;
# Log into the nspawn host and terminate the target container instance:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl stop &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Confirm the container is inactive and no lingering worker threads exist:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl list&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Navigate to the root filesystem directory (typically located under &amp;lt;code&amp;gt;/var/lib/machines/&amp;lt;/code&amp;gt;). Create a compressed tarball archive using relative path positioning:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;tar -cvzf container_backup.tar.gz -C /var/lib/machines/&amp;lt;container_name&amp;gt; .&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
#: &#039;&#039;Note: Utilizing the &amp;lt;code&amp;gt;-C&amp;lt;/code&amp;gt; flag preserves the nested structures directly inside the top level of the archive, omitting parent folder descriptors that break standard LXC unpacking loops.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Transfer the Payload to Proxmox ===&lt;br /&gt;
Transport the generated payload file to the centralized Proxmox storage pool designated for distribution packages.&lt;br /&gt;
&lt;br /&gt;
# Push the file to the default template cache path of your Proxmox server via secure copy protocol:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;scp container_backup.tar.gz root@&amp;lt;proxmox_ip&amp;gt;:/var/lib/vz/template/cache/&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3: Provision and Initialize the LXC Instance ===&lt;br /&gt;
Execute the container initialization binary via the Proxmox Command Line Interface. Select an unallocated Virtual Machine Identifier (VMID) code (e.g., &amp;lt;code&amp;gt;105&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
# Run the &amp;lt;code&amp;gt;pct create&amp;lt;/code&amp;gt; string mapping configuration details appropriately. The following should work fine in most scenarios, but don&#039;t forget to verify it for each migration case:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct create &amp;lt;VMID&amp;gt; /var/lib/vz/template/cache/container_backup.tar.gz \&lt;br /&gt;
  --hostname my-migrated-container \&lt;br /&gt;
  --storage vm \&lt;br /&gt;
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \&lt;br /&gt;
  --ostype debian \&lt;br /&gt;
  --arch amd64&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Parameter Breakdown ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 85%; text-align: left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #f2f2f2;&amp;quot;&lt;br /&gt;
! Parameter !! Type !! Purpose / Operational Notes&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&amp;lt;VMID&amp;gt;&#039;&#039;&#039; || Integer || Target ID assignment for isolation reference.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Path String&#039;&#039;&#039; || Filepath || Literal path pointing directly toward the moved &amp;lt;code&amp;gt;.tar.gz&amp;lt;/code&amp;gt; bundle.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--storage&#039;&#039;&#039; || Target Storage || Defines where the newly expanded disk images live. (Can use &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;local-lvm&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--ostype&#039;&#039;&#039; || String ID || Configures automated networking script hooks inside guest boundaries. Use &#039;&#039;&#039;debian&#039;&#039;&#039; even if host hypervisor builds use an upstream point release.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;--net0&#039;&#039;&#039; || Interface String || Sets the internal interface name, upstream virtualization bridge, and network configuration method (e.g., DHCP).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Step 4: Post-Migration Integration Tasks ===&lt;br /&gt;
Before setting the automated power-on directive, minor discrepancies must be assessed:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Systemd Nesting:&#039;&#039;&#039; Enable nesting to allow the guest systemd to manage its internal units. Navigate to &#039;&#039;&#039;Options&#039;&#039;&#039; -&amp;gt; &#039;&#039;&#039;Features&#039;&#039;&#039; -&amp;gt; Check &#039;&#039;&#039;nesting&#039;&#039;&#039;, or run:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct set &amp;lt;VMID&amp;gt; --features nesting=1&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;User Privilege Level Constraints:&#039;&#039;&#039; By default, Proxmox creates unprivileged namespaces for safety. If the nspawn container expects hardware node execution access, or special system task levels, go to the &#039;&#039;&#039;Options&#039;&#039;&#039; pane within the web terminal and modify state permissions to Privileged.&lt;br /&gt;
* &#039;&#039;&#039;Network Manager Hooks:&#039;&#039;&#039; If &amp;lt;code&amp;gt;systemd-networkd&amp;lt;/code&amp;gt; or localized static loops exist inside the original container structure, it may conflict with parameters injected via Proxmox. Consider clearing internal static state binds if link interface problems materialize.&lt;br /&gt;
&lt;br /&gt;
=== Step 5: Start and Verify Instance Health ===&lt;br /&gt;
# Start the newly provisioned infrastructure slice:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct start &amp;lt;VMID&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Intercept terminal standard streams to execute verification checks internally:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;pct enter &amp;lt;VMID&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Review service status tables inside the active root environment:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;systemctl status&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 6: Decommission the Source Instance ===&lt;br /&gt;
Once the container is confirmed functional on Proxmox, the original files and configurations should be removed from the nspawn host to reclaim storage.&lt;br /&gt;
&lt;br /&gt;
# Permanently delete the container image and its associated configuration files:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl terminate &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl remove &amp;lt;container_name&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Verify the machine is no longer indexed:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;machinectl list-images&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# Manually remove the transferred tarball from the nspawn host&#039;s local storage:&lt;br /&gt;
#: &amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;rm container_backup.tar.gz&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>M5choo</name></author>
	</entry>
</feed>