Attach and Safely Replace a systemd Portable Service Image
You will inspect a portable service image, attach its matching units to the host, confirm the attachment state, and remove it cleanly. The examples use the portablectl shipped by systemd 255.4-1ubuntu8.17 on Ubuntu. Allow roughly 10 minutes if the image already exists. You need root access for operations that change the system manager.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
A portable service image is an operating system tree containing systemd unit files. It can be a directory, a btrfs subvolume, or a regular .raw disk image. This guide assumes an image at /srv/portable/myservice.raw. Replace that path with a real image and do not run the mutating examples against an image you have not inspected.
Images without a slash are looked up in portable image search paths. A path containing a slash is used directly. The usual persistent storage location is /var/lib/portables/; /etc/portables/ and /run/systemd/portables/ are normally better used for links to images stored elsewhere.
Checkpoint
Continue only when you know which units the image is meant to provide and where its files came from. Attaching copies unit files and adds drop-ins to the host. It is not a read-only preview.
1. Check what is already discoverable
Start with a non-mutating list. Disable the pager so the result is predictable in a terminal or script:
portablectl --no-pager list
This lists images found in the configured search paths, with brief metadata and state. It does not limit other commands to those images. An image at /srv/portable may therefore be inspected by its full path even if it is absent from this list.
Inspect the candidate directly. The normal form summarises its operating system metadata and matching unit files:
portablectl --no-pager inspect /srv/portable/myservice.raw
Use --cat when you need the unprocessed os-release data and unit file contents:
portablectl --no-pager --cat inspect /srv/portable/myservice.raw
Check that the listed units have the prefix you expect. By default, attach derives a prefix from the image filename, removes .raw, and stops at the first underscore. For example, myservice_2026.09.raw selects names beginning myservice-, myservice., or myservice@. You can supply explicit prefixes after the image path if that default does not match your unit names.
2. Attach it persistently
Elevated command: attach the image only after inspecting it:
sudo portablectl --no-pager attach /srv/portable/myservice.raw
On success, matching .service, .socket, .target, .timer, and .path files become available through the host service manager. Service units receive a root setting pointing into the image. The default security profile is named default. It is fairly restrictive while allowing logging and system D-Bus access. The built-in alternatives are nonetwork, strict, and trusted; the last is deliberately relaxed and runs services with full privileges.
For example, choose a profile explicitly when the image should have no network access:
sudo portablectl --no-pager --profile=nonetwork attach /srv/portable/myservice.raw
Do not use trusted as a troubleshooting shortcut without reviewing the service and its image. A profile changes the restrictions applied to the attached units and can materially change the host's security boundary.
Persistent attachment places generated files under /etc/systemd/system.attached/. To attach only until the next reboot, use --runtime; those files go under /run/systemd/system.attached/ instead:
sudo portablectl --no-pager --runtime attach /srv/portable/myservice.raw
The manager is reloaded after attach by default. --no-reload suppresses that reload, so use it only when you have a deliberate plan to reload later.
3. Verify the result before starting anything
Ask portablectl for the attachment state:
portablectl --no-pager is-attached /srv/portable/myservice.raw
The output is one of states such as attached, attached-runtime, enabled, or running. The --quiet option suppresses the text and leaves the exit status as the useful result:
if portablectl --quiet is-attached /srv/portable/myservice.raw; then
echo "portable image is attached"
else
echo "portable image is not attached" >&2
exit 1
fi
Attaching does not automatically start or enable the service. If you have identified the intended service unit, you can request that behaviour during attachment with --now and --enable. Both affect live host state, so check the unit names and image contents first:
sudo portablectl --no-pager --now --enable attach /srv/portable/myservice.raw
Checkpoint
After a start, inspect the unit with systemctl status myservice.service and review its journal before treating the deployment as healthy. If the service fails, undo the enablement and stop it before detaching:
sudo portablectl --no-pager --now --enable detach /srv/portable/myservice.raw
4. Replace an image with less interruption
When a new image replaces an existing one, reattach detaches the old image and attaches the new one. It permits versioned names that share the part before the first underscore and will not detach the old image if the replacement does not exist:
sudo portablectl --no-pager reattach /srv/portable/myservice_2026.09.raw
Running units are not stopped during the basic reattach operation. If the service must be restarted or enabled as part of the change, add --now and, where appropriate, --enable. That is a service-disrupting action. Plan a maintenance window and verify the new image with inspect first.
5. Detach or remove it
Warning
Detach removes the host-side unit copies, drop-ins, and image link. It does not remove the image itself. Stop services and disable them first, or let --now stop and --enable disable the associated units:
sudo portablectl --no-pager --now --enable detach /srv/portable/myservice.raw
portablectl --no-pager is-attached /srv/portable/myservice.raw
The final command should report detached. To delete an image itself, use remove only after confirming the exact path and retaining any backup you need:
sudo portablectl --no-pager remove /srv/portable/myservice.raw
If the argument is a symbolic link, remove removes the link rather than the image it points to. The command is still destructive to that directory entry, so verify with readlink -f and ls -l before running it.
Done means
inspectshowed the expected metadata and unit files.- The chosen profile and persistent or runtime lifetime were intentional.
is-attachedreturned the state you expected.- Any started unit was checked with
systemctland its journal. - Detach was used before removal, and the image path was verified before any deletion.