Setting up rootless podman on a fresh Ubuntu 24.10 server.
Warning
Perform sudo apt update && sudo apt upgrade
immediately. Reboot system.
SSH is optional, but highly encouraged. OpenSSH is installed by default and sshd is running by default.
## Generate strong key on your laptop or workstation/desktop
## If you already have keys DO NOT overwrite your previous keys
ssh-keygen -t ed25519 -a 32 -f ~/.ssh/$localhost-to-$remotehost
## Optionally set a passphrase
## Copy key to Ubuntu
ssh-copy-id username@remote_host
We don't want to allow anyone to login as root remotely ever. You must be a
sudoer
with public key auth to elevate to root.
SSH into your server and run
printf '%s\n' 'PermitRootLogin no' | sudo tee /etc/ssh/sshd_config.d/01-root.conf
printf '%s\n' \
'PubkeyAuthentication yes' \
'PasswordAuthentication no' | sudo tee /etc/ssh/sshd_config.d/01-pubkey.conf
Save file and then run systemctl restart ssh
Before closing your session, open
a new terminal and test SSH is functioning correctly.
Podman is a daemonless container hypervisor. This document prepares a fully rootless environment for our containers to run in.
sudo apt install podman systemd-container
## Make sure podman is running
systemctl enable --now podman
Note
Read the docs. man podman-systemd.unit
Note
As of Podman 5.0 Pasta is the default rootless networking tool.
Podman 5.0 is available in standard Ubuntu repo since 24.10.
Both are installed with podman see rootless networking for configuration
Note
This is only necessary if you are setting up the reverse proxy (or any service on ports <1024).
printf '%s\n' 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-unprivileged-port-binding.conf
sysctl -w 'net.ipv4.ip_unprivileged_port_start=80'
This user will be the owner of all containers with no login shell or root privileges.
Container user should have range of uid/gid automatically generated. See subuid and subgid tutorial to verify range or create if it does not exist.
Note $ctuser is a placeholder, replace with your username
# Prepare a group id outside of the normal range
sudo groupadd --gid 2000 $ctuser
# Create user with restrictions
# We need the $HOME to live in
sudo useradd --create-home \
--shell /usr/bin/false \
--password $ctuser_pw \
--no-user-group \
--gid $ctuser \
--groups systemd-journal \
--uid 2000 \
$ctuser
# Lock user from password login
sudo usermod --lock $ctuser
# Start $ctuser session at boot without login
loginctl enable-linger $ctuser
Note
Consider removing bash history entry that contains the password entered above
Note
Use machinectl instead of sudo or su to get a shell that is fully isolated from the original session. See the developers comments on the problem with su as well as the purpose of machinectl shell
# Switch to $ctuser
# Note do not remove the trailing @
machinectl shell $ctuser@ /bin/bash
# Create dirs
mkdir -p ~/.config/{containers/systemd,environment.d}
# Prepare `systemd --user` env
echo 'XDG_RUNTIME_DIR=/run/user/2000' >> ~/.config/environment.d/10-xdg.conf
# Enable container auto-update
podman system migrate
# WARNING: Set strict versions for all containers or risk catastrophe
systemctl --user enable --now podman-auto-update
exit
In Podman < 5.3 containers may fail to autostart because user level units cannot depend on system level units (in this case network-online.target
)
Podman >= 5.3 should ship with a workaround user unit that can be used podman-user-wait-network-online.service
, use that instead of the fix below.
See this github issue for workarounds, the workaround below is what worked for me. The google.com ping can be replaced with your preferred (reachable) ip/host
To fix this, create the following
# ~/.config/systemd/user/network-online.service
[Unit]
Description=User-level proxy to system-level network-online.target
[Service]
Type=oneshot
ExecStart=sh -c 'until ping -c 1 google.com; do sleep 5; done'
[Install]
WantedBy=default.target
# ~/.config/systemd/user/network-online.target
[Unit]
Description=User-level network-online.target
Requires=network-online.service
Wants=network-online.service
After=network-online.service
Then enable the service systemctl --user enable network-online.service
In quadlets add the following:
[Unit]
After=network-online.target