Skip to main content

PrivateBin Deployment with Rootless Podman Using Ansible Role

ยท 7 min read
VoidQuark
Open-source enthusiast

PrivateBin Deployment with Rootless Podman Using Ansible Role

The PrivateBin Ansible Role deploys the PrivateBin service in a rootless container using Podman. This container operates within the user namespace and is managed by a systemd unit, ensuring a secure and efficient deployment.

This role is designed with simplicity in mind, featuring minimal variables to reduce complexity. It caters to both beginners who are comfortable with default configurations and advanced users looking to customize PrivateBin.

It's essential to note that the default deployment lacks HTTPS, making it insecure. To enhance security, consider either mounting SSL/TLS certificates into the container or utilizing a reverse proxy in front of PrivateBin.

What is PrivateBin ?โ€‹

PrivateBin is an open-source, self-hosted web application designed for secure and anonymous file sharing(limited) and text pasting. It provides a way for users to share text-based information, such as code snippets, messages, or documents, while maintaining their privacy and security. Here are some key features of PrivateBin:

  • ๐Ÿ” Encrypted Content: PrivateBin encrypts the content you share before storing it on the server.

  • ๐Ÿ•’ Self-Destruction: You can set expiration times for pastes, allowing them to self-destruct after a certain period. This feature enhances the confidentiality of shared content.

  • ๐Ÿ•ต๏ธ No Registration Required: Users don't need to create accounts or provide personal information to use PrivateBin. It's designed for anonymous sharing.

  • ๐ŸŒˆ Syntax Highlighting: PrivateBin supports syntax highlighting for various programming languages, making it useful for sharing code snippets.

  • ๐Ÿ›ก๏ธ Password Protection: You can protect pastes with passwords, adding an extra layer of security.

  • ๐Ÿ’ฌ Discussion Mode: PrivateBin offers discussion mode, allowing users to engage in conversations related to shared content.

  • ๐ŸŒ Open Source: PrivateBin is open-source software, which means its source code is freely available for review and modification.

PrivateBin is often used by individuals, organizations, or communities that value privacy and control over their data when sharing sensitive information online. It's a versatile tool that can be customized to suit various use cases, from sharing confidential documents to collaborating on code projects.

Ansible PrivateBin Role Rationaleโ€‹

PrivateBin offers various deployment options, but I noticed a gap where the combination of rootless Podman and Ansible was missing. To address this, I created this role. Before diving into the details, I highly recommend reading the role's README.md file for a comprehensive understanding.

How PrivateBin Container is Managed ?โ€‹

Enable Lingeringโ€‹

To ensure continuous operation of the PrivateBin container, we enable the lingering feature, allowing a user's session to persist even after they've logged out.

Here's how we enable lingering for the PrivateBin user:

- name: Check if privatebin user is lingering
ansible.builtin.stat:
path: "/var/lib/systemd/linger/{{ privatebin_user }}"
register: __user_lingering

- name: Enable lingering for user
ansible.builtin.command: "loginctl enable-linger {{ privatebin_user }}"
when: not __user_lingering.stat.exists

Enabling lingering ensures that the PrivateBin service remains active in the background, providing uninterrupted functionality even when there are no active user sessions. This step is crucial for the effective management of the PrivateBin container.

Container Creationโ€‹

To create the PrivateBin container in the created state, we use the Ansible module containers.podman.podman_container.

- name: Create privatebin container
containers.podman.podman_container:
name: "{{ privatebin_container_name }}"
image: "{{ privatebin_container_image }}"
state: "created"
image_strict: true
rm: true
publish: "{{ privatebin_container_publish }}"
detach: true
privileged: false
read_only: true
tty: false
log_driver: "journald"
user: "{{ __user_info.uid }}:{{ __user_info.group }}"
userns: "keep-id"
volume: "{{ privatebin_container_volumes }}"
become_user: "{{ privatebin_user }}"
notify:
- restart privatebin

It's important to note that this module's purpose is to create the container in the created state, not to manage its ongoing operation. Container management is handled through systemd. Additionally, this task is executed under the privatebin user, not as root.

Generate Systemd Unitโ€‹

To ensure that the PrivateBin container runs under a user namespace and starts after system boot, we generate a systemd unit in the user's home directory at /home/privatebin/.config/systemd/user. This unit, named container-privatebin.service, is created using the Ansible module containers.podman.podman_generate_systemd.

- name: Generate systemd unit file for privatebin container
containers.podman.podman_generate_systemd:
dest: "/home/{{ privatebin_user }}/.config/systemd/user"
name: "{{ privatebin_container_name }}"
new: true
no_header: true
restart_sec: 10
restart_policy: "always"
become_user: "{{ privatebin_user }}"
notify:
- restart privatebin

Please note that this task must be executed by the privatebin user, and it's crucial to have lingering enabled to ensure the generated systemd unit starts at system boot.

Ensuring Idempotencyโ€‹

To summarize the process:

  • Lingering is enabled.
  • The container is created.
  • A systemd unit is generated.

With these preparations, PrivateBin is almost ready to start. However, it's crucial to maintain idempotency, ensuring that PrivateBin behaves consistently even if there are configuration changes, such as PrivateBin config adjustments, modifications to php.ini or nginx settings, or changes to container tags, ports, or volumes.

To achieve idempotency, we use a handler task to restart the PrivateBin systemd unit:

- name: restart privatebin
ansible.builtin.systemd:
name: "container-{{ privatebin_container_name }}.service"
state: "restarted"
scope: "user"
daemon_reload: true
enabled: true
become_user: "{{ privatebin_user }}"
environment:
XDG_RUNTIME_DIR: "/run/user/{{ __user_info.uid }}"

During the restart procedure, the container is stopped and removed:

# Stop Part of container-privatebin.service
ExecStop=/usr/bin/podman stop \
--ignore -t 10 \
--cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
-f \
--ignore -t 10 \
--cidfile=%t/%n.ctr-id

Once the container is stopped and removed, systemd instructs the container to be created and started again:

Restart=always
RestartSec=10
ExecStart=/usr/bin/podman container run \
--cidfile=%t/%n.ctr-id \
--cgroups=no-conmon \
--rm \
--sdnotify=conmon \
-d \
--replace \
--name privatebin \
--publish 8080:8080 \
--privileged=False \
--read-only=True \
--tty=False \
--log-driver journald \
--user USERID:USERID \
--userns keep-id \
--volume /home/privatebin/privatebin/data:/srv/data:rw,Z \
--volume /home/privatebin/privatebin/conf.php:/srv/cfg/conf.php:ro,Z docker.io/privatebin/nginx-fpm-alpine:stable

This ensures that the running container matches the inventory, and PrivateBin is ready for end-users.

Please note that this role does not validate your configuration. If your PrivateBin instance behaves unexpectedly, you should consult the logs.

Accessing Logsโ€‹

You can find logs from the PrivateBin container in the journald system or access them by logging in as the root user and checking the /var/log/messages file. These logs in the file are prefixed with privatebin.

To access logs in the journal, run the following command as a user with sudo permissions. Please note that the privatebin user should not have sudo permissions for security reasons:

sudo journalctl -f CONTAINER_NAME=privatebin

Manually Stopping or Starting PrivateBinโ€‹

To manually stop or start the PrivateBin systemd unit from an interactive shell session:

  • Open an interactive shell session.
machinectl shell privatebin@
  • Inside the interactive shell session, use the following commands to stop or start the PrivateBin systemd unit:
systemctl --user stop container-privatebin.service
systemctl --user start container-privatebin.service

Tips to Considerโ€‹

Here are some tips for enhancing your PrivateBin deployment:

  • Remote Logging: Consider shipping logs to a remote logging system like Loki. This allows you to monitor paste access activity. For a quick Loki deployment, you can use the Loki Ansible role.

  • Access Log Parsing: You can parse the access logs of Nginx to monitor if a unique IP address is creating many pastes. This helps in identifying and optimizing rate limit settings. Check my dashboard for PrivateBin.

  • Additional Documentation: It's highly recommended to explore the PrivateBin documentation. This resource covers various topics, including running PrivateBin behind Cloudflare, enabling Read-Only mode, and more.

Additional Documentation


Thanks for reading. I'm entering the void. ๐Ÿ›ธ โžก๏ธ ๐Ÿ•ณ๏ธ