This document outlines the configuration of a systemd unit designed to run the Playwright MCP server. The setup is opinionated, adhering to the Filesystem Hierarchy Standard (FHS) and the curated SELinux policies found in Fedora and Red Hat Enterprise Linux distributions.
This systemd unit runs the Playwright MCP container in "rootful" mode, meaning the container is managed by a podman
process running as the root user. This is in contrast to Podman's default and more secure "rootless" mode, which allows non-privileged users to run containers. Running as root is a deliberate choice in this configuration, often necessitated by requirements like binding to privileged ports below 1024.
For seamless container communication, a dedicated container network named br-container
is created using the command:
sudo podman network create br-container
When containers are connected to this user-defined bridge network, Podman provides automatic DNS-based service discovery. This functionality is handled by aardvark-dns
, an authoritative DNS server that serves DNS records for containers within Podman-managed networks. This allows containers on the same network to resolve each other's IP addresses by their container names.
When using Podman on a system with SELinux in enforcing
mode, it is crucial to manage the security contexts of volumes mounted into containers.
The systemd unit file specifies the volume mount as --volume /srv/containers/%N/data:/data:Z
. The :Z
suffix instructs Podman to relabel the host directory (/srv/containers/playwright-mcp-server/data
) with a private, unshared SELinux label (container_file_t
). This makes the directory accessible only to the processes within that specific container.
The specified host path, /srv/containers/
, is intentionally chosen because standard SELinux policies on Fedora and RHEL-based systems are pre-configured to handle files in this directory. As shown below, files and directories created under /srv/containers/
will automatically inherit the container_file_t
context, which is necessary for container runtimes like Podman to access them.
berstuk ~ » sudo semanage fcontext -l | grep \/srv\/container
/srv/containers(/.*)? all files system_u:object_r:container_file_t:s0
/var/srv/containers(/.*)? all files system_u:object_r:container_file_t:s0
This pre-configured policy simplifies volume management, as you do not need to manually change the SELinux context of the host directory.
sudo mkdir -p /srv/containers/playwright/{conf,data}
# Setting ownership to match the uidnumber/gidnumber used in the playwright container
sudo chown -R 1000:1000 /srv/containers/playwright
sudo chmod -R g+rwX /srv/containers/playwright
While this systemd unit is designed for Podman, it can be adapted for Docker. However, there are some key differences to be aware of:
- Architecture: The most significant difference is that Docker uses a client-server architecture with a long-running daemon (
dockerd
) that manages all containers. Podman, on the other hand, is daemonless and launches containers as child processes of the user that starts them. - Systemd Integration: Podman offers superior integration with systemd. It includes tools like
podman generate systemd
to automatically create systemd unit files for containers, simplifying the process of managing containers as system services. - Security: Podman is generally considered more secure due to its default rootless operation. While Docker has a rootless mode, it is not the default and has some limitations.
- CLI Compatibility: For most common commands, Podman is a drop-in replacement for Docker, meaning you can often alias
docker
topodman
(alias docker=podman
) with minimal issues. - Image Building: Docker has built-in image building capabilities (
docker build
). Podman often relies on a separate tool called Buildah for more advanced image creation, though basicpodman build
functionality exists.
To adapt this unit file for Docker, you would primarily need to replace the podman
commands with their docker
equivalents. For example, using sed 's/podman/docker/g'
. However, be mindful that Docker's interaction with systemd and SELinux may require different configurations.
-
Create the systemd Unit File: Save the provided unit file content to
/etc/systemd/system/playwright-mcp-server.service
. This location is the standard directory for system-wide services managed by systemd. -
Create the Container Data Directory: The service expects a directory on the host system to mount as a volume inside the container. Create the necessary directory structure:
sudo mkdir -p /srv/containers/playwright-mcp-server/data
On SELinux-enforcing systems like Fedora or RHEL, the correct
container_file_t
security context will be automatically applied to this directory based on existing file context rules. -
Create the Podman Network: For automatic DNS resolution between containers, create the specified Podman network:
sudo podman network create br-container
This only needs to be done once. Any subsequent containers can be attached to this same network.
-
Reload the systemd Daemon: After creating a new unit file, you must inform systemd to scan for new or changed units:
sudo systemctl daemon-reload
Once the unit file is installed, you can manage the Playwright MCP server using standard systemctl
commands.
-
Enabling the Service: To have the service start automatically at boot, you need to enable it:
sudo systemctl enable playwright-mcp-server.service
This creates a symbolic link from the system's service startup directory to the unit file.
-
Starting and Stopping the Service: You can manually control the service with the following commands:
- To start the service:
sudo systemctl start playwright-mcp-server.service
- To stop the service:
sudo systemctl stop playwright-mcp-server.service
- To start the service:
-
Restarting the Service: If you make changes to the container image or need to restart the service for any reason:
sudo systemctl restart playwright-mcp-server.service
-
Checking the Service Status: To view the current status of the service, including whether it is active, and to see the latest log entries, use:
sudo systemctl status playwright-mcp-server.service
This will provide a snapshot of the service's state, including process IDs and recent log output.
-
Viewing Logs: For more detailed and historical logs, use the
journalctl
command. To follow the logs in real-time, which is useful for debugging:sudo journalctl -u playwright-mcp-server.service -f
This shows the logs specifically for this unit. Since the container is configured to use the
conmon
sdnotify mechanism, container logs will be directly ingested into the systemd journal. -
Troubleshooting: If the service fails to start, begin by checking the status and logs:
- Run
sudo systemctl status playwright-mcp-server.service
to see if there are immediate error messages. - Use
sudo journalctl -u playwright-mcp-server.service
to get a more complete picture of what might have gone wrong during the startup process. Common issues could include networking problems, SELinux permission errors, or issues with the container image itself. - You can also inspect the running containers using
sudo podman ps -a
to see if the container is being created and what its exit status is.
- Run