Portainer Templates logo

Portainer Templates

PrivateBin PrivateBin

Container

CloudProductivityToolsWeb

PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data!

Image details

Pulls: 33.6M
Architecture: amd64, arm64, arm/v7, arm/v6, 386, ppc64le, s390x
Image size: 39 MB
Latest: 2.0.6
User: privatebin
Created: May 29, 2018
Updated: 4 hours ago
Status: active

Configuration

Type
Container
Platform
linux
Image
privatebin/nginx-fpm-alpine:latest
Privileged
Yes
Ports
8080:8080/tcp
Volumes
/srv/data : /portainer/Files/AppData/PrivateBin/srv/cfg : /portainer/Files/AppData/Config/PrivateBin
Env vars
PUID=1000PGID=1000
Restart
unless-stopped

Template by novaspirit

Notes

Template created by Pi-Hosted Series
Check our Github page: https://github.com/pi-hosted/pi-hosted

Official Webpage: https://privatebin.info/
Official Docker Documentation: https://hub.docker.com/r/privatebin/nginx-fpm-alpine


Standalone Install

Select an install method, to see config/commands for deploying PrivateBin

Installation method

Install on Portainer

Import all app templates into your Portainer instance, for easy 1-click deploys

  1. Ensure both Docker and Portainer are installed, and up-to-date
  2. Log into your Portainer web UI
  3. Under Settings → App Templates, paste the below URL
  4. Head to Home → App Templates, and the list of apps will show up
  5. Select PrivateBin, fill in any config options, and hit Deploy

Template Import URL

https://raw.githubusercontent.com/Lissy93/portainer-templates/main/templates.json
Show Me demo

More install options in our documentation.

PrivateBin on Nginx, php-fpm & Alpine

PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted and decrypted in the browser using 256bit AES in Galois Counter mode.
This repository contains the Dockerfile and resources needed to create a Docker image with a pre-installed PrivateBin instance in a secure default configuration. The images are based on the docker hub Alpine image, extended with the GD module required to generate discussion avatars and the Nginx webserver to serve static JavaScript libraries, CSS & the logos. All logs of php-fpm and Nginx (access & errors) are forwarded to docker logs.

Image variants

This is the all-in-one image (Docker Hub / GitHub) that can be used with any storage backend supported by PrivateBin - file based storage, databases, Google Cloud or S3 Storage. We also offer dedicated images for each backend:

Image tags

All images contain a release version of PrivateBin and are offered with the following tags:
  • latest is an alias of the latest pushed image, usually the same as nightly, but excluding edge
  • nightly is the latest released PrivateBin version on an upgraded Alpine release image, including the latest changes from the docker image repository
  • edge is the latest released PrivateBin version on an upgraded Alpine edge image
  • stable contains the latest PrivateBin release on the latest tagged release of the docker image git repository - gets updated when important security fixes are released for Alpine or upon new Alpine releases
  • 1.5.1 contains PrivateBin version 1.5.1 on the latest tagged release of the docker image git repository - gets updated when important security fixes are released for Alpine or upon new Alpine releases, same as stable
  • 1.5.1-... are provided for selecting specific, immutable images

If you update your images automatically via pulls, the stable, nightly or latest are recommended. If you prefer to have control and reproducibility or use a form of orchestration, the numeric tags are probably preferable. The edge tag offers a preview of software in future Alpine releases and serves as an early warning system to detect image build issues in these.

Image registries

These images are hosted on the Docker Hub and the GitHub container registries:

Running the image

Assuming you have docker successfully installed and internet access, you can fetch and run the image from the docker hub like this:
$ docker run -d --restart="always" --read-only -p 8080:8080 -v $PWD/privatebin-data:/srv/data --tmpfs /tmp:nodev,noexec,mode=1777 --tmpfs /run:nodev,exec,mode=1777 privatebin/nginx-fpm-alpine

The parameters in detail:
  • -v $PWD/privatebin-data:/srv/data - replace $PWD/privatebin-data with the path to the folder on your system, where the pastes and other service data should be persisted. This guarantees that your pastes aren't lost after you stop and restart the image or when you replace it. May be skipped if you just want to test the image or use database or Google Cloud Storage backend.
  • --tmpfs /tmp:nodev,noexec,mode=1777 --tmpfs /run:nodev,exec,mode=1777 - attaches temporary, in-memory file systems for use by the service manager and small temporary files. These should get removed when restarting the service. You can skip these, but may have to clean them up manually, for example when the image upgrades PHP.
  • -p 8080:8080 - The Nginx webserver inside the container listens on port 8080, this parameter exposes it on your system on port 8080. Be sure to use a reverse proxy for HTTPS termination in front of it in production environments.
  • --read-only - This image supports running in read-only mode. Using this reduces the attack surface slightly, since an exploit in one of the images services can't overwrite arbitrary files in the container. Only /tmp, /run, /var/lib/nginx/tmp & /srv/data may be written into.
  • -d - launches the container in the background. You can use docker ps and docker logs to check if the container is alive and well.
  • --restart="always" - restart the container if it crashes, mainly useful for production setups

Note that the volume mounted must be owned by UID 65534 / GID 82. If you run the container in a docker instance with "userns-remap" you need to add your subuid/subgid range to these numbers.

Custom configuration

In case you want to use a customized conf.php file, for example one that has file uploads enabled or that uses a different template, add the file as a second volume:
$ docker run -d --restart="always" --read-only -p 8080:8080 -v $PWD/conf.php:/srv/cfg/conf.php:ro -v $PWD/privatebin-data:/srv/data --tmpfs /tmp:nodev,noexec,mode=1777 --tmpfs /run:nodev,exec,mode=1777 privatebin/nginx-fpm-alpine

Note: The Filesystem data storage is supported out of the box. The image includes PDO modules for MySQL and PostgreSQL, required for the Database one, but you still need to keep the /srv/data persisted for the server salt and the traffic limiter when using a release before 1.4.0.

Environment variables

The following variables are passed down to the PHP application to support various scenarios. This allows certain settings to be changed via the environment instead of a configuration file. Most of these variables relate to the storage backends:
Amazon Web Services variables used by the S3 backend
  • AWS_ACCESS_KEY_ID
  • AWS_CONTAINER_AUTHORIZATION_TOKEN
  • AWS_CONTAINER_CREDENTIALS_FULL_URI
  • AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
  • AWS_DEFAULT_REGION
  • AWS_PROFILE
  • AWS_ROLE_ARN
  • AWS_ROLE_SESSION_NAME
  • AWS_SECRET_ACCESS_KEY
  • AWS_SESSION_TOKEN
  • AWS_STS_REGIONAL_ENDPOINTS
  • AWS_WEB_IDENTITY_TOKEN_FILE
  • AWS_SHARED_CREDENTIALS_FILE
Google Cloud variables used by the GCS backend
  • GCLOUD_PROJECT
  • GOOGLE_APPLICATION_CREDENTIALS
  • GOOGLE_CLOUD_PROJECT
  • PRIVATEBIN_GCS_BUCKET
Custom backend settings
The following variables are not used by default, but can be enabled in your custom configuration file, to keep sensitive information out of it:
  • STORAGE_HOST
  • STORAGE_LOGIN
  • STORAGE_PASSWORD
  • STORAGE_CONTAINER
Configuration folder
  • CONFIG_PATH
Timezone settings
The image supports the following two environment variables to adjust the timezone. This is especially useful to ensure the logs show the correct local time.
  • TZ
  • PHP_TZ

Note: The application internally handles expiration of pastes based on a UNIX timestamp that is calculated based on the timezone set during its creation. Changing the PHPTZ will affect this and leads to earlier (if the timezone is increased) or later (if it is decreased) expiration than expected.

Adjusting nginx or php-fpm settings

You can attach your own php.ini or nginx configuration files to the folders /etc/php/conf.d/ and /etc/nginx/http.d/ respectively. This, for example, would let you adjust the maximum size that these two services accept for file uploads, if you need more than the default 10 MiB.

Kubernetes deployment

If you use helm, you may want to take a look at this helm chart
. Below is an example deployment for Kubernetes.

```yaml

apiVersion: apps/v1 kind: Deployment metadata: name: privatebin-deployment labels:
app: privatebin
spec: replicas: 3 selector:
matchLabels:
  app: privatebin
template:
metadata:
  labels:
    app: privatebin
spec:
  automountServiceAccountToken: false
  securityContext:
    runAsUser: 65534
    runAsGroup: 82
    fsGroup: 82
  containers:
  - name: privatebin
    image: privatebin/nginx-fpm-alpine:stable
    ports:
    - containerPort: 8080
    env:
    - name: TZ
      value: Antarctica/South_Pole
    - name: PHP_TZ
      value: Antarctica/South_Pole
    securityContext:
      readOnlyRootFilesystem: true
      privileged: false
      allowPrivilegeEscalation: false
    livenessProbe:
      httpGet:
        path: /
        port: 8080
    readinessProbe:
      httpGet:
        path: /
        port: 8080
    volumeMounts:
    - mountPath: /srv/data
      name: privatebin-data
      readOnly: False
    - mountPath: /run
      name: run
      readOnly: False
    - mountPath: /tmp
      name: tmp
      readOnly: False
    - mountPath: /var/lib/nginx/tmp
      name: nginx-cache
      readOnly: False
volumes:
- name: run
  emptyDir:
    medium: "Memory"
- name: tmp
  emptyDir:
    medium: "Memory"
- name: nginx-cache
  emptyDir: {}
Note that the volume `privatebin-data` has to be a shared, persisted volume across all nodes, i.e. on an NFS share. As of PrivateBin 1.4.0 it is no longer required, when using a database or Google Cloud Storage.

## Running administrative scripts

The image includes two administrative scripts, which you can use to migrate from one storage backend to another, delete pastes by ID, removing empty directories when using the Filesystem backend, to purge all expired pastes and display statistics. These can be executed within the running image or by running the commands as alternative entrypoints with the same volumes attached as in the running service image. The former option is recommended.

```console
# assuming you named your container "privatebin" using the option: --name privatebin

$ docker exec -t privatebin administration --help
Usage:
  administration [--delete <paste id> | --empty-dirs | --help | --purge | --statistics]

Options:
  -d, --delete      deletes the requested paste ID
  -e, --empty-dirs  removes empty directories (only if Filesystem storage is
                    configured)
  -h, --help        displays this help message
  -p, --purge       purge all expired pastes
  -s, --statistics  reads all stored pastes and comments and reports statistics

$ docker exec -t privatebin migrate --help
migrate - Copy data between PrivateBin backends

Usage:
  migrate [--delete-after] [--delete-during] [-f] [-n] [-v] srcconfdir
          [<dstconfdir>]
  migrate [-h|--help]

Options:
  --delete-after   delete data from source after all pastes and comments have
                   successfully been copied to the destination
  --delete-during  delete data from source after the current paste and its
                   comments have successfully been copied to the destination
  -f               forcefully overwrite data which already exists at the
                   destination
  -h, --help       displays this help message
  -n               dry run, do not copy data
  -v               be verbose
  <srcconfdir>     use storage backend configuration from conf.php found in
                   this directory as source
  <dstconfdir>     optionally, use storage backend configuration from conf.php
                   found in this directory as destination; defaults to:
                   /srv/bin/../cfg/conf.php

Note that in order to migrate between different storage backends, you will need to use the all-in-one image called privatebin/nginx-fpm-alpine, as it includes all the necessary drivers and libraries for the supported backends. When using the variant images, you will only be able to migrate between two backends of the same storage type - for example, two filesystem paths or two database backends.

Rolling your own image

To reproduce the image, run:
$ docker build -t privatebin/nginx-fpm-alpine .

Behind the scenes

The two processes, Nginx and php-fpm, are started by s6.
Nginx is required to serve static files and caches them, too. Requests to the index.php (which is the only PHP file exposed in the document root at /var/www) are passed to php-fpm via a socket at /run/php-fpm.sock. All other PHP files and the data are stored under /srv.
The Nginx setup supports only HTTP, so make sure that you run a reverse proxy in front of this for HTTPS offloading and reducing the attack surface on your TLS stack. The Nginx in this image is set up to deflate/gzip text content.
During the build of the image, the PrivateBin release archive is downloaded from Github. All the downloaded Alpine packages and the PrivateBin archive are validated using cryptographic signatures to ensure they have not been tempered with, before deploying them in the image.

Serve PrivateBin on your own domain behind Caddy, Nginx or Traefik. Fill in your domain and copy the result. It's a starting point, some apps need their own base URL or extra headers set too.

Proxying privatebin.example.com to http://privatebin:8080

Add this to your Caddyfile

privatebin.example.com {
	reverse_proxy http://privatebin:8080
}

Check the logs first

Nine times out of ten the logs tell you exactly what went wrong.

  • In Portainer, go to Containers, click the container, then Logs. Or run docker logs privatebin
  • Exit codes help too: 137 means killed, usually out of memory. 126 or 127 means the command inside the image is broken.

Port already in use

If deployment fails with "Bind for 0.0.0.0:8080 failed: port is already allocated", something else on your server is using that port.

  • Find what's using it: sudo ss -tlnp | grep :8080
  • Stop the other service, or pick a different host port. In 8080:8080 only the left number is yours to change, the right one belongs to the app.

Running but the page won't load

The container is up but nothing appears in your browser.

  • Use your server's real IP: http://your-server-ip:8080. The 0.0.0.0 link Portainer shows isn't a real address.
  • Give it a minute after first deploy, privatebin can take a while to initialise.
  • Make sure your firewall allows the port, e.g. sudo ufw allow 8080

Permission denied on volumes

If the logs show "permission denied", the app can't write to its data folder on the host.

  • Fix the ownership: sudo chown -R 1000:1000 /portainer/Files/AppData/PrivateBin (and the same for the other mapped folders)
  • Or set the PUID and PGID variables (defaults 1000:1000) to match your own user, found with id $USER

Image won't pull

Test the pull directly on the host: docker pull privatebin/nginx-fpm-alpine:latest

  • "manifest unknown" means the tag no longer exists. This template uses latest, so try pinning a specific version instead.
  • "toomanyrequests" is the Docker Hub rate limit. Log in with docker login to raise it.
  • "no space left on device" means a full disk. Reclaim space with docker system prune

"exec format error"

This means the image was built for a different CPU architecture than your server.

  • This image supports: amd64, arm64, arm/v7, arm/v6, 386, ppc64le, s390x
  • Check yours with uname -m: x86_64 is amd64, aarch64 is arm64. Raspberry Pi and other ARM boards are the usual culprits.

Container keeps restarting

The unless-stopped restart policy relaunches the app after every crash, so the real error can scroll past.

  • Check the logs right after a restart, the last few lines before it died are the useful ones.
  • Get the exit code with docker inspect privatebin --format '{{.State.ExitCode}}'
  • Still stuck? Redeploy once with the restart policy set to no so the failure stays visible.

Privileged mode

This template runs the container in privileged mode, giving it full access to your host.

  • Only deploy it if you trust the app.
  • If deployment is blocked, your Portainer security settings or hardened host may not allow privileged containers.

Raise an issue

Found something which isn't working as it should? Here's how to report it.

A single container

PrivateBin runs as one container, the simplest kind of app here. Just the one image to pull and nothing else wired up alongside it.

The app image

An image is the app packed up ready to go, everything PrivateBin needs bundled into one download. This template pulls privatebin/nginx-fpm-alpine:latest, which Docker fetches once (about 39 MB) and then starts your own copy from.

Where the image comes from

Docker pulls its images from registries, public libraries of ready-built apps. PrivateBin's comes from Docker Hub, published by privatebin.

Version tags

The bit after the colon in the image name is the version tag. Here it's latest, which always points at the newest build, so a redeploy can bump you to a newer release without you asking. Newest right now is 2.0.6. Pin a specific tag if you would rather stay on one version.

Which machines it runs on

Every image is built for particular CPU types. This one ships for amd64, arm64, arm/v7, arm/v6, 386, ppc64le, s390x, so it runs on both regular x86 servers and ARM boards like a Raspberry Pi.

Ports

A port is the door the app answers on. A mapping like 8080:8080 means it's reachable on port 8080 of your server, where the left number is yours to change and the right one belongs to the app. Once it's running, open http://your-server-ip:8080 in a browser. It opens:

  • 8080:8080, likely the web interface

Volumes

A volume is where PrivateBin keeps its files so they survive an update or a restart. Without one, anything it saves would sit inside the container and vanish the moment it's recreated. This template mounts:

  • /srv/data from /portainer/Files/AppData/PrivateBin on the host
  • /srv/cfg from /portainer/Files/AppData/Config/PrivateBin on the host

Environment variables

Environment variables are the settings you hand over when you deploy, things like a password or a timezone. PrivateBin takes 2 of them, all with defaults you can leave alone or tweak:

  • PUID, defaults to 1000
  • PGID, defaults to 1000

Restart policy

The restart policy here is unless-stopped, so Docker restarts PrivateBin after a crash or reboot, but leaves it off when you stop it on purpose. You can change this on the deploy screen. The choices are no (never restart), on-failure (only after a crash), unless-stopped (restart unless you stop it), and always (bring it back no matter what).

Users and permissions

The PUID and PGID settings tell it which user and group to act as on your host. Point them at your own account (find yours with id $USER) so the files it writes into your mounted folders come out owned by you rather than root.

Networking

Nothing custom is set, so PrivateBin sits on Docker's default bridge network: its own private space that reaches the outside world only through the ports it publishes.

Container name

Once it's deployed, Portainer names the container privatebin. That's what you'll spot in the containers list and use in commands like docker logs privatebin.

Privileged mode

This template runs PrivateBin in privileged mode, which gives it nearly as much access to your server as the system itself. Some apps genuinely need it to reach hardware or manage the host, so it's one to run only if you trust the source.

Platform

The platform is linux, the kind of system the container is built to run on. Docker and Portainer handle this on a normal Linux server.

Portainer app templates

Zooming out, this whole page comes from a Portainer app template: a short recipe telling Portainer how to set PrivateBin up. Add the template list to Portainer once, then deploying PrivateBin is a click rather than a wall of config.