Running applications in containers on a dedicated server requires more than simply downloading an image and starting a container. Production environments need reliable service management, automatic startup, persistent storage, appropriate security controls and a straightforward way to recover from failures.
Rootless Podman containers provide an effective way to run containerized applications on Ubuntu 24.04 without granting the container process root privileges on the host. Podman is a daemonless container engine that supports OCI-compatible images and provides an alternative to Docker for many Linux container workloads.
When combined with systemd and Podman Quadlet, administrators can manage containers as system services. This approach makes it possible to configure automatic startup, restart policies, persistent volumes and service dependencies without maintaining complicated startup scripts.
In this tutorial, you will learn how to install Podman on Ubuntu 24.04, configure a dedicated Linux user for rootless container execution, deploy an Nginx container and manage its lifecycle using systemd and Quadlet. By the end, you will have a working container deployment that can start automatically after a server reboot and operate independently of an interactive SSH session.
Podman is an open-source container management tool used to create, run and manage Linux containers. It supports OCI-compatible container images and provides commands similar to those used by Docker.
One of its main advantages is its ability to run containers without requiring root privileges. In a traditional rootful container deployment, the container engine or container-management process operates with elevated host privileges. Rootless Podman instead uses Linux user namespaces to map container identities to unprivileged user IDs on the host.
This means that the container's internal root user does not automatically receive root privileges on the underlying Ubuntu server. Rootless container execution can help reduce security risks, particularly when hosting multiple applications or workloads on the same dedicated server.
Podman and Docker provide similar container-management capabilities, but their architectures differ.
| Feature | Podman | Docker Engine |
|---|---|---|
| Container engine | Daemonless architecture | Uses Docker daemon |
| Rootless execution | Supported | Supported |
| OCI image compatibility | Yes | Yes |
| systemd integration | Native Quadlet support | Additional integration commonly used |
| Container management | Podman CLI | Docker CLI |
| Container lifecycle | systemd and Quadlet integration | Docker Engine and related tools |
Podman is particularly useful when administrators want daemonless container management, rootless execution and native systemd integration. However, Docker may remain preferable for environments that depend on Docker-specific tooling or established Docker Compose workflows.
Podman Quadlet is a systemd generator that converts declarative configuration files into systemd service units. Instead of manually creating systemd service files for individual containers, administrators define container settings in files such as:
.container – Defines container configuration.
.volume – Defines persistent container volumes.
.network – Defines container networks.
For rootless deployments, these files are commonly stored in ~/.config/containers/systemd/. After reloading the user's systemd manager, Quadlet processes the configuration and generates the corresponding service units. This makes Podman Quadlet a practical solution for managing long-running containers on Ubuntu servers.
Before deploying rootless Podman containers, install the container engine on your Ubuntu server. Connect to your server through SSH using an account with sudo privileges.
First, update the package index and upgrade installed packages:
sudo apt update
sudo apt upgrade -y
Install Podman using Ubuntu's package manager:
sudo apt install -y podman
Ubuntu 24.04 provides Podman through its official package repositories, making APT the straightforward installation method.
After installation, verify the installed version:
podman --version
Check the container engine configuration:
podman info
You should also verify that the server uses cgroup v2, which is required by Quadlet:
podman info --format '{{.Host.CgroupsVersion}}'
The expected output is v2. If the server reports a different cgroup version, investigate the host configuration before continuing.
Important: Ubuntu 24.04's packaged Podman version is 4.9.3 in the documented Noble package. This tutorial uses Quadlet features supported by that release rather than relying on newer Podman 5.x or 6.x functionality.
Running every container under the root account defeats an important security advantage of rootless Podman. A better approach is to create a dedicated Linux user for container workloads. In this example, the account will be named podapp.
Create the user:
sudo adduser --disabled-password --gecos "" podapp
This creates a separate account without requiring an interactive password.
Verify the account:
id podapp
Configure Subordinate UID and GID Ranges
Rootless Podman uses subordinate user IDs (UIDs) and group IDs (GIDs) to map identities inside containers to unprivileged identities on the host.
Check whether the new account already has subordinate ID ranges:
grep '^podapp:' /etc/subuid /etc/subgid
If suitable ranges do not exist, allocate unused ranges. For example:
sudo usermod --add-subuids 200000-265535 podapp
sudo usermod --add-subgids 200000-265535 podapp
These are example ranges, not universal defaults. Before assigning them, check /etc/subuid and /etc/subgid to ensure they do not overlap existing allocations.
Verify the configuration:
grep '^podapp:' /etc/subuid /etc/subgid
The account should now have subordinate UID and GID ranges available for rootless container execution.
Rootless Podman runs containers within the permissions and environment of the Linux user who owns them. For server deployments, however, there is another important requirement: containers should continue running after the user disconnects from SSH.
Linux systemd provides a feature called lingering to support this behaviour. When lingering is enabled, systemd maintains the user's service manager even when the user does not have an active login session.
Enable lingering for the dedicated container account:
sudo loginctl enable-linger podapp
Verify the configuration:
loginctl show-user podapp -p Linger
Expected output: Linger=yes
Now switch to the dedicated account:
sudo -iu podapp
Check whether Podman can initialise its rootless environment:
podman info
If the command completes successfully, the user-level container environment is ready. You can now use Podman without running container commands through sudo.
Security recommendation: Keep application containers under their dedicated unprivileged account. Avoid switching between rootful and rootless Podman because they maintain separate container storage, images and volumes.
Before configuring systemd, test whether the dedicated user can download and run a container image. For this tutorial, we will use Nginx, a widely used web server and reverse proxy.
Pull the official Nginx image:
podman pull docker.io/library/nginx:stable
After downloading the image, start a temporary container:
podman run -d \
--name nginx-test \
-p 8080:80 \
docker.io/library/nginx:stable
Here is what each option does:
-d runs the container in the background.
--name assigns a name to the container.
-p 8080:80 forwards host port 8080 to container port 80.
docker.io/library/nginx:stable specifies the container image.
Check whether the container is running:
podman ps
View its logs:
podman logs nginx-test
Test the Nginx service locally:
curl -I http://127.0.0.1:8080
A successful response should include an HTTP status such as 200 OK. If you want to access the service externally, configure your server firewall to permit TCP port 8080. Only expose ports that your application actually requires.
Once the test is complete, remove the temporary container:
podman stop nginx-test
podman rm nginx-test
The next step is to replace this manually started container with a systemd-managed deployment.
Podman Quadlet simplifies rootless container management by allowing administrators to describe container settings in configuration files. Instead of manually maintaining long podman run commands, you can define the required settings once and allow systemd to manage the container.
First, create the Quadlet configuration directory:
mkdir -p ~/.config/containers/systemd
Create a container configuration file:
nano ~/.config/containers/systemd/web.container
Add the following configuration:
[Unit]
Description=Rootless Nginx Web Container
Wants=network-online.target
After=network-online.target
[Container]
ContainerName=colobird-web
Image=docker.io/library/nginx:stable
PublishPort=8080:80
Volume=web-data.volume:/usr/share/nginx/html
NoNewPrivileges=true
[Service]
Restart=always
TimeoutStartSec=900
[Install]
WantedBy=default.target
Save the file.
Understanding the Quadlet Configuration
Each section has a specific purpose.
[Unit]
Defines the systemd service description and its dependencies. Description identifies the container service, while Wants and After express a dependency on network availability.
[Container]
Contains the Podman-specific container configuration.
ContainerName assigns a recognizable container name.
Image specifies the image to run.
PublishPort exposes the container's web server.
Volume mounts persistent storage.
NoNewPrivileges prevents the container process from gaining additional privileges through mechanisms such as setuid or setgid execution.
[Service]
Controls the systemd service lifecycle. Restart=always tells systemd to restart the service when the container process exits. TimeoutStartSec=900 allows up to 15 minutes for startup, which is useful when an image needs to be downloaded.
[Install]
Defines how the generated service should be connected to the user's systemd startup target. WantedBy=default.target allows the service to start automatically with the user's systemd manager. This is particularly useful for long-running applications hosted on dedicated servers.
Container filesystems are not always suitable for storing application data permanently. When a container is removed and recreated, data stored only in its writable container layer may be lost. Persistent volumes help prevent this problem by storing application data separately from the container itself.
Podman supports named volumes that can be mounted into containers whenever they start. For this deployment, we will create a named volume for the Nginx website directory.
Create the volume configuration file:
nano ~/.config/containers/systemd/web-data.volume
Add:
[Volume]
VolumeName=colobird-web-data
Save the configuration. The .volume extension tells Quadlet to create a systemd-managed Podman volume.
In the previous web.container configuration, we referenced this volume using: Volume=web-data.volume:/usr/share/nginx/html
This mounts the persistent volume inside the Nginx container at /usr/share/nginx/html. The volume is created automatically when the container service starts.
Verify the Persistent Volume
After starting the container service in the next step, inspect the available volumes:
podman volume ls
Inspect the named volume:
podman volume inspect colobird-web-data
For production applications, use persistent volumes for database files, uploaded content and other information that must survive container replacement. Remember that persistent storage is not a backup. Important application data should also be backed up to a separate storage location.
Now that the Quadlet configuration and persistent volume definition are ready, you can load them into the systemd user manager.
First, reload the systemd configuration:
systemctl --user daemon-reload
Quadlet reads the configuration files and generates the corresponding systemd service units. The file web.container generates web.service.
Check whether the generated service is available:
systemctl --user list-unit-files
Check its status:
systemctl --user status web.service
Start the container:
systemctl --user start web.service
Verify that the service is running:
systemctl --user status web.service
You can also check the container directly:
podman ps
Test the Nginx web server:
curl -I http://127.0.0.1:8080
If everything is configured correctly, the Nginx container should now be running as a rootless Podman service managed by systemd.
Enable Automatic Startup
One important difference between Quadlet-generated services and conventional systemd services is that you do not normally enable the generated service directly using systemctl enable.
Instead, Quadlet reads the [Install] section in the original configuration file and applies the requested startup relationship when generating the service.
Combined with the previously enabled user lingering, this allows the container to start automatically when the user's systemd manager starts, including after a server reboot.
Once Podman Quadlet has generated the service, you can manage the container through systemd. This provides a consistent way to start, stop, restart and monitor containerized applications.
The following commands should be executed as the podapp user.
Start the Container:
systemctl --user start web.service
Stop the Container:
systemctl --user stop web.service
Restart the Container:
systemctl --user restart web.service
Check the Service Status:
systemctl --user status web.service
View Container Service Logs:
journalctl --user -u web.service
To follow the logs continuously, use journalctl --user -u web.service -f. To display the latest 100 log entries, use journalctl --user -u web.service -n 100 --no-pager.
Inspect the Container with Podman
Although systemd manages the service lifecycle, Podman remains useful for inspecting container-level information.
List running containers:
podman ps
List all containers, including stopped containers:
podman ps -a
View container logs, inspect configuration, and monitor resource consumption:
podman logs colobird-web
podman inspect colobird-web
podman stats
Using systemd for lifecycle management and Podman for container inspection provides a practical administration workflow for rootless container deployments.
Networking is an important part of running production containers on dedicated servers. Podman allows administrators to publish container ports, create private container networks and control communication between applications.
In our example, the Quadlet configuration contains PublishPort=8080:80. This forwards connections from port 8080 on the Ubuntu host to port 80 inside the Nginx container.
You can verify the published port using:
podman port colobird-web
Create a Dedicated Container Network
When hosting multiple applications, it is often better to use a dedicated network rather than exposing every container port directly. Podman Quadlet supports .network files for defining container networks.
Create a network configuration:
nano ~/.config/containers/systemd/app-network.network
Add:
[Network]
NetworkName=app-network
Save the file. You can then reference the network in the [Container] section of an applicable container configuration by adding Network=app-network.network.
Reload the user systemd manager after changing Quadlet files and restart the affected container service:
systemctl --user daemon-reload
systemctl --user restart web.service
For applications involving databases, backend services and frontend containers, private container networking can reduce unnecessary exposure of internal application ports.
Production recommendation: For public-facing websites, consider placing a reverse proxy such as Nginx or Caddy in front of your containers. This allows you to manage HTTPS certificates, request routing and external access without publishing every application port.
Even when Podman and systemd are configured correctly, container startup problems can occur because of incorrect configuration files, unavailable images, port conflicts or user namespace restrictions. Understanding how to inspect these problems is important for maintaining reliable container workloads.
Problem 1: The systemd Service Cannot Be Found
You may encounter an error such as: Failed to start web.service: Unit web.service not found. This usually means Quadlet did not generate the expected service.
Check the configuration directory:
ls -la ~/.config/containers/systemd/
Verify that the container file uses the correct .container extension. Reload the user systemd manager with systemctl --user daemon-reload.
If the service is still unavailable, run the Quadlet generator in diagnostic mode:
/usr/lib/systemd/system-generators/podman-system-generator --user --dryrun
Problem 2: The Container Stops Immediately After Starting
If a container exits unexpectedly, inspect its service status and application logs.
systemctl --user status web.service
journalctl --user -u web.service -n 100 --no-pager
podman ps -a
podman logs colobird-web
Common causes include incorrect application configuration, missing environment variables, invalid startup commands and unavailable dependencies.
Problem 3: Rootless Container Permission Errors
Rootless Podman depends on Linux user namespaces and subordinate UID/GID mappings. If you encounter permission-related errors, check the subordinate ID configuration:
grep '^podapp:' /etc/subuid /etc/subgid
id podapp
command -v newuidmap
command -v newgidmap
If the mappings are missing or incorrect, review the account's subordinate ID allocation before attempting to recreate containers. Do not delete the Podman storage directory as a routine troubleshooting measure because it may contain important container and image data.
Problem 4: Containers Do Not Start After a Server Reboot
If your rootless containers do not automatically start after restarting Ubuntu, verify that lingering is enabled: loginctl show-user podapp -p Linger (Expected output: Linger=yes).
Next, check that your Quadlet file includes WantedBy=default.target under the [Install] section. Remember that rootless container services depend on the correct user-level systemd configuration.
Problem 5: The Container Port Is Already in Use
A port conflict occurs when another application is already listening on the port you want to publish. Check active listeners:
sudo ss -ltnp | grep ':8080'
If the port is occupied, choose another available host port. Update your Quadlet configuration (e.g., PublishPort=8081:80), reload systemd, and restart the container.
Problem 6: Container Image Downloads Take Too Long
When Quadlet starts a container, Podman may need to download the required image. Large container images or slow network connections can increase startup time. To avoid unnecessary delays, download the image before starting the service: podman pull docker.io/library/nginx:stable.
You can also configure a longer startup timeout in the Quadlet file (TimeoutStartSec=900).
Deploying rootless Podman containers is only one part of maintaining a reliable production environment. When running containerized applications on dedicated servers, administrators should also consider security, resource allocation, monitoring and data protection.
Here are some important practices:
1. Use dedicated Linux accounts: Run separate application workloads under dedicated unprivileged Linux users whenever practical. This helps isolate container storage, permissions and processes.
2. Keep container images updated: Regularly review container image updates and security advisories. Use controlled image versions or immutable image digests for production deployments rather than relying blindly on a moving tag.
3. Protect application secrets: Avoid embedding passwords, API keys and other sensitive credentials directly into container images or public configuration files. Use appropriately protected environment files or secret-management mechanisms.
4. Configure persistent storage: Use named volumes or carefully permissioned bind mounts for application data that must survive container recreation.
5. Monitor resource consumption: Monitor CPU usage, memory consumption, storage capacity and network activity. Dedicated server resources should be allocated according to actual application requirements.
6. Configure firewall rules: Only expose ports required by your applications. Keep database services and internal application interfaces inaccessible from the public internet unless there is a specific requirement.
7. Implement regular backups: Back up persistent container data and application configurations. Store backups separately from the production server and periodically test restoration.
8. Monitor systemd services: Use systemd status information and journal logs to identify container failures and investigate unexpected restarts.
9. Apply operating system updates: Keep Ubuntu, Podman and the underlying container runtime updated to receive security and stability improvements.
10. Test recovery procedures: A production deployment should have documented steps for restoring application data, recreating containers and recovering services after a failure.
For organizations running multiple containerized workloads, dedicated server infrastructure can provide predictable CPU, memory, NVMe storage and network capacity. Selecting suitable hardware is important when applications have sustained resource requirements.
Both Podman and Docker are capable container platforms, but choosing between them depends on your infrastructure and application requirements. Podman is particularly attractive for administrators who prefer daemonless container execution, rootless security and native systemd integration.
Docker remains a strong choice for teams that already depend on Docker Compose, Docker-specific tooling and established deployment workflows.
For dedicated server environments, consider the following factors:
| Requirement | Recommended consideration |
|---|---|
| Rootless container execution | Podman |
| Native systemd integration | Podman Quadlet |
| Existing Docker Compose workflows | Docker ecosystem |
| Multiple isolated application workloads | Both |
| Automated container startup | systemd integration |
| Container resource management | Both |
There is no universal winner. Evaluate application compatibility, security requirements, operational complexity and the experience of your server administration team before choosing a container platform.
Running rootless Podman containers with systemd on Ubuntu 24.04 provides a practical approach to managing containerized applications without relying on root-level container execution.
Throughout this tutorial, you learned how to install Podman, create a dedicated Linux user, configure subordinate UID and GID mappings, enable rootless execution and deploy an Nginx container. You also explored how Podman Quadlet integrates with systemd to manage container services, configure persistent storage, handle automatic startup and troubleshoot common deployment problems.
For production environments, combining rootless container execution with appropriate firewall rules, persistent storage, regular backups and system monitoring can help establish a more manageable and secure application infrastructure. Whether you are deploying web applications, backend services or development environments, Podman Quadlet offers a straightforward way to manage containers on Ubuntu dedicated servers.
Yes. Podman supports rootless container execution on Ubuntu 24.04. It uses Linux user namespaces and subordinate UID/GID mappings to run containers under an unprivileged Linux account.
Podman Quadlet is a systemd generator that converts declarative configuration files into systemd service units. It allows administrators to manage Podman containers, volumes and networks using systemd.
Create a Quadlet configuration file in ~/.config/containers/systemd/, add an [Install] section containing WantedBy=default.target, and enable lingering for the container user using: sudo loginctl enable-linger podapp. This allows the user's systemd manager to start without an interactive login.
Use the systemctl --user restart command with the generated service name. For example: systemctl --user restart web.service.
The standard per-user configuration directory is: ~/.config/containers/systemd/. Administrators can also use system-managed rootless Quadlet directories such as /etc/containers/systemd/users/.
Rootless Podman reduces the privileges available to container processes on the host by using unprivileged users and Linux user namespaces. However, it does not eliminate every container security risk. Administrators should also implement operating system updates, network restrictions, access controls and application security practices.
Yes. Podman supports OCI-compatible container images and offers many familiar container-management commands. Its daemonless architecture, rootless execution and systemd integration make it a useful Docker alternative for many Linux server workloads.
Yes. Podman can run production application containers on dedicated servers. For reliable deployments, configure persistent storage, systemd service management, monitoring, firewall restrictions and regular backups.
When deploying containerized applications, choosing the right server infrastructure is important for maintaining consistent application performance and resource availability. Explore these COLO BIRD resources:
Dedicated Servers – Explore dedicated server configurations for production applications and containerized workloads.
AMD Dedicated Servers – Explore AMD-powered server platforms for compute-intensive applications and virtualization workloads.
Intel Dedicated Servers – Explore Intel-powered dedicated server configurations for business applications and server infrastructure.