====== How to run SavaPage in Docker ======
https://www.docker.com/
===== Introduction =====
This is a guide by example on how to deploy SavaPage in a Docker container.
===== References =====
* Jérôme Boillot created a ''docker-compose.yml'' file to deploy SavaPage in a Docker container. See https://hub.docker.com/r/jboillot/savapage
* Markus Neuberger created a SavaPage [[https://podman.io/|Podman]] module for NethServer 8. See https://github.com/mrmarkuz/ns8-savapage
===== Install Docker =====
#install Docker + Compose
sudo apt install docker.io docker-compose-v2
# add yourself to docker group
sudo usermod -aG docker $(whoami)
===== Create Container =====
mkdir -p ~/Docker-containers/savapage
cd ~/Docker-containers/savapage
Copy files below to ''~/Docker-containers/savapage''
==== docker-compose.yml ====
Docker containers are ephemeral by default. Changes made to a container's filesystem won't persist after the container stops.
There are a few different approaches to managing persistent data. The most common is to use a Docker Volume. Volumes are storage units that are mounted into container filesystems. Any data in a volume will remain intact after its linked container stops, letting you connect another container in the future.
services:
savapage:
hostname: sp-server
image: savapage
container_name: savapage
environment:
TZ: Europe/Amsterdam
env_file: docker.env
ports:
# CUPS
- "127.0.0.1:6631:631"
- "[::1]:6631:631"
# http
#- "127.0.0.1:8641:8631"
#- "[::1]:8641:8631"
# https
- "127.0.0.1:8642:8632"
- "[::1]:8642:8632"
networks:
# IP address assigned by Docker ...
#- savapage_network
# IP address self assigned example
savapage_network:
ipv4_address: 172.20.0.10
aliases:
- sp-server
volumes:
- savapage_custom:/opt/savapage/server/custom
- savapage_data:/opt/savapage/server/data
- savapage_ext:/opt/savapage/server/ext
- savapage_logs:/opt/savapage/server/logs
- savapage_cups:/etc/cups
restart: always
postgres:
hostname: sp-postgres
image: postgres
container_name: postgres
ports:
- "5442:5432"
networks:
# IP address self assigned example
savapage_network:
ipv4_address: 172.20.0.20
aliases:
- savapage-postgres
volumes:
- savapage_database:/var/lib/postgresql/data
restart: always
networks:
savapage_network:
driver: bridge
# IP address self assigned example
ipam:
config:
- subnet: 172.20.0.0/16
volumes:
savapage_custom:
driver: local
savapage_data:
driver: local
savapage_ext:
driver: local
savapage_database:
driver: local
savapage_logs:
driver: local
savapage_cups:
driver: local
==== docker.env ====
^ Important | ''SP_CONTAINER=DOCKER'' is required for Docker container. |
# Namespace as prefix for SavaPage envvar names (mandatory)
SAVAPAGE_NS=SP_
# Required for Docker container **
SP_CONTAINER=DOCKER
# Unique SP_SRV_* variables with server.properties key/value
# separated by ':' like SP_SRV_n=key:value
# For example:
SP_SRV_01=visitor.organization:Acme Corporation
SP_SRV_02=server.port:8080
SP_SRV_03=server.ssl.port:8443
SP_SRV_11=database.type:PostgreSQL
SP_SRV_12=database.driver:org.postgresql.Driver
SP_SRV_13=database.url:jdbc:postgresql://savapage-postgres:5432/savapage
SP_SRV_14=database.user:sp-user
SP_SRV_15=database.password:my-password
# Do NOT redirect: disable http by not exposing
# port 8631 as 8641 in docker-compose.yml
# SP_SRV_20=server.html.redirect.ssl:true
==== Dockerfile ====
A Dockerfile describes how to run your service by installing required software and copying in files.
FROM debian:bookworm
RUN apt update && apt install --no-install-recommends --no-install-suggests -y binutils cpio \
cups cups-bsd debianutils default-jdk-headless gzip imagemagick librsvg2-bin perl poppler-utils \
qpdf supervisor wkhtmltopdf libheif-examples vim-tiny findutils apt-utils iputils-ping \
gnupg curl hplip
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY docker.env /etc/environment
RUN useradd -rmd /opt/savapage -s /bin/bash -G lpadmin savapage && chown savapage:savapage /opt/savapage
# Create persistent password for admin tasks in CUPS web interface.
RUN echo 'savapage:mysecret' | chpasswd
ENV SAVAPAGE_VERSION=1.6.0-rc
ENV SAVAPAGE_NS=SP_
ENV SP_CONTAINER=DOCKER
USER savapage
COPY ./savapage-setup-${SAVAPAGE_VERSION}-linux-x64.bin /opt/savapage/savapage-setup.bin
RUN ["bash", "/opt/savapage/savapage-setup.bin", "-n"]
USER root
RUN ["/opt/savapage/server/bin/linux-x64/roottasks", "pam"]
EXPOSE 631 8631 8632
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
==== supervisord.conf ====
[supervisord]
nodaemon=true
[program:cupsd]
command=/usr/sbin/cupsd -f
autostart=true
autorestart=true
[program:cupsctl]
command=/usr/sbin/cupsctl --remote-any
autostart=true
autorestart=true
[program:savapage-cups-notifier]
command=/opt/savapage/providers/cups/linux-x64/roottasks
autostart=true
autorestart=true
user=root
[program:savapage]
command=/opt/savapage/server/bin/linux-x64/app-server start
autostart=true
autorestart=true
user=savapage
===== Build Image =====
Before you start:
* Download the right ''${SAVAPAGE_VERSION}'' to ''./savapage-setup-${SAVAPAGE_VERSION}-linux-x64.bin''
* Make sure the build date is March 22, 2025 or later.
* Execute in ''~/Docker-containers/savapage''
#!/bin/bash
# Use Dockerfile to construct the image and tag as "savapage".
# Execute if any of the Docker files changed.
docker build -t savapage . 2>&1 | tee ./build.log
===== Run Container =====
#!/bin/bash
#--------------------------
# Start SavaPage container
#--------------------------
cd ~/Docker-containers/savapage
docker compose up -d
#!/bin/bash
#--------------------------
# Stop SavaPage container
#--------------------------
cd ~/Docker-containers/savapage
docker compose down
#!/bin/bash
#---------------------------------------
# Execute command in SavaPage container
#---------------------------------------
docker exec -it savapage bash
#!/bin/bash
#---------------------------------------
# Execute command in Postgres container
#---------------------------------------
docker exec -it postgres bash
# Check running containers
docker ps
# What's in the SavaPage-container?
docker exec -it savapage bash
# List docker volumes
docker volume ls
# List processes
docker ps -a
# List images
docker images
# List dangling images
docker images -f dangling=true
# Remove all the dangling images
docker system prune
===== CUPS =====
^ Note | Password for CUPS admin ''savapage'' is set in ''Dockerfile'' |
CUPS Web interface: http://127.0.0.1:6631/printers/
===== Admin Web App =====
https://localhost:8642/admin
===== Remove Container =====
https://docs.docker.com/reference/cli/docker/image/rm/
# List images
docker images
# ... and remove savapage
docker image rm savapage
https://docs.docker.com/reference/cli/docker/volume/rm/
# List volumes
docker volume ls
# ... and remove them
docker volume rm savapage_savapage_custom
docker volume rm savapage_savapage_data
docker volume rm savapage_savapage_database
docker volume rm savapage_savapage_ext
docker volume rm savapage_savapage_logs