PhotoStructure for Docker
These are instructions for advanced users, wanting to run PhotoStructure for Servers via Docker.
Background reading #
-
You should read the pros and cons of both Docker and Node editions before continuing.
-
Docker-compose may be easier to use than these instructions, which use
docker
directly, because:- upgrades are automatic
- adding and removing volumes to scan into your library is easy
The downside is that it’s one more software package that you need to install, and it may not be available on your host machine. The instructions for docker-compose are here.
-
If you want imported volumes in your library to be portable across machines, please read what’s a “volume?” (hint: skip to the last section and create
.uuid
files for all the volumes you import).
System requirements #
The docker images run under linux x64 Docker hosts.
PhotoStructure containers require at least 2GB of RAM during imports. You’ll see
ENOMEM
errors if you run within a 1GB container. PhotoStructure imports run
faster when more RAM and more CPU are allocated to the container.
Install Docker #
Follow these instructions for docker. If you’re on Ubuntu, follow these steps.
Note you need to use either Docker or Docker Compose: don’t use both simultaneously.
Docker volume setup #
PhotoStructure writes into 4 directories that must be mounted via docker volumes.
The following examples set up PhotoStructure to scan both a mounted external
hard drive at /mnt/Photos backup
and all files found in $HOME/Pictures
.
You’ll want to edit these examples to be relevant to your setup.
/ps/library
#
This is where your PhotoStructure Library will be stored. It must be readable and writable by the PhotoStructure container, and have sufficient free space.
If your library is on a remote volume (mounted from a NAS to your docker
host, for example), you must add -e PS_FORCE_LOCAL_DB_REPLICA=1
to your docker
run command (or uncomment the line in the example docker-compose.yml
).
SQLite’s WAL mode doesn’t work reliably on remote filesystems, and this flag
tells PhotoStructure to read and write from a local SQLite database replica
(stored in /ps/tmp
) to work around this issue.
/ps/tmp
#
This is PhotoStructure’s “scratch” directory.
/ps/tmp
must be on a local disk.- This volume should have at least 16-32 GB free.
- If you’ve got an SSD, use that: this directory will see a lot of reads and writes.
- If you can pick (or create) a volume that doesn’t have data integrity protection, on-the-fly compression, or on-the-fly file de-duplication. This will make imports faster as well as reduce system load.
- PhotoStructure automatically prunes old and unused files from the scratch directory: it shouldn’t take much space unless an import is running.
/ps/config
#
This is where PhotoStructure stores system settings.
/ps/logs
#
This is where PhotoStructure stores logfiles. Normally PhotoStructure should be
mostly quiet, unless you “send recent logs,” or set
PS_LOG_LEVEL
to something like info
.
PhotoStructure deletes logfiles older than 1 week automatically (as of v0.8.4).
Directories to import #
-
To add directories you want to import into your PhotoStructure library, simply add them as bind volumes to your container. The following example configurations include a couple examples.
-
PhotoStructure changes the default of
PS_SCAN_ALL_DRIVES
to be true when run under Docker. -
If you would like to ensure that PhotoStructure doesn’t change anything in the directories you import, you can mount these volumes read-only, with 2 caveats:
-
You will need to drop a .uuid file in the root of these volumes if you want your library to be portable.
-
This will prevent PhotoStructure from being able to write sidecars next to your originals to save metadata changes you make from within the UI.
-
Directories to omit #
PhotoStructure will import all mounted directories recursively. PhotoStructure
respects NoMedia
files, and will exclude those directories from being
imported. (learn more)
Advanced settings #
PhotoStructure has a bunch of settings that are only configurable outside of the PhotoStructure UI.
Docker users may find it’s easiest to use environment variables to override settings. Read more about PhotoStructure’s use of environment variables.
Library ownership #
Dockerized applications run as root by default. This results in the files in your library as being owned by root.
Running PhotoStructure as a non-root user is more secure.
The following script runs docker run
with the --user
option, which makes
PhotoStructure run as the current user. This user needs to be able to read and
write to /ps/library
, /ps/tmp
, /ps/config
, and /ps/logs
(and read from
any bind mounts that contain photos and videos).
Note that the photostructure/server
image is set up to run with a user id of
1000
. If you need to use a different userid, you’ll need to use Docker’s
userns-remap
feature.
Networking setup #
-
The
PS_HTTP_PORT
environment variable defaults to 1787 but can be changed to a different port to suit. -
If you set up a reverse HTTPS proxy via nginx and find that dynamic updates (like the progress status) aren’t showing up, add this to your nginx config:
proxy_http_version 1.1;
proxy_set_header Connection "";
Example Docker setup #
(On a Synology NAS? Skip down to those instructions.)
This shell script can be saved to make future upgrades easier. See the docker documentation for more details.
PSLIBRARY="$HOME/PhotoStructure" # < CHANGE THIS LINE
mkdir -p $PSLIBRARY
# This must be a fast, local disk with many gigabytes free:
PSTMP="/tmp/ps-$USER"
mkdir -p "$PSTMP"
# This directory stores your "system settings". This directory must not be
# the same as the one used by PhotoStructure for Desktops.
PSCONFIG="$HOME/.config/PhotoStructure-docker"
mkdir -p "$PSCONFIG"
# This directory stores PhotoStructure logfiles.
PSLOGS="$HOME/.config/PhotoStructure/logs"
mkdir -p "$PSLOGS"
docker run \
--name photostructure \
--detach \
--user $(id -u):$(id -g) `# < optional: see the "Library ownership" section above.` \
--restart on-failure `# < optional: starts PhotoStructure on boot.` \
--stop-timeout 120 `# < gives PhotoStructure 2 minutes to shut down cleanly.` \
--publish 1787:1787 \
-e TZ="$(cat /etc/timezone)" \
-v "$PSLIBRARY":/ps/library \
-v "$PSTMP":/ps/tmp \
-v "$PSCONFIG":/ps/config \
-v "$PSLOGS":/ps/logs \
-v "/mnt/Photos backup":/photos-backup/ `# < CHANGE THIS LINE` \
-v "$HOME"/Pictures:/pictures/ `# < CHANGE THIS LINE` \
photostructure/server
In case of error #
If the PhotoStructure doesn’t spin up successfully, try replacing the
--detach
line with these lines:
-e PS_LOG_LEVEL=info
-e PS_TAIL_LOGS=1
This runs PhotoStructure in --verbose
mode. Note that this can be pretty
chatty, but good for debugging why PhotoStructure is grumpy. Use
PS_LOG_LEVEL=warn
for less output, and PS_LOG_LEVEL=debug
for more output.
Still stuck? Click the chat button and we’ll help diagnose what’s amiss.
Once you’ve fixed the issue, replace these lines back to --detach
.
Welcome to PhotoStructure! #
Open http://localhost:1787
in a browser to complete installation.
Firefox, Chrome, and Safari are supported.
While you wait for your import to complete, check out these getting-started tips!
How to stop PhotoStructure #
docker stop photostructure
(replace photostructure
with the name of your PhotoStructure docker container)
If you’re wondering why it’s taking a while to shut down, this is why.
How to restart PhotoStructure #
docker start photostructure
How to upgrade PhotoStructure #
Automatic upgrades via Watchtower (recommended) #
If you don’t mind all of your Docker containers to be upgraded automatically, use Watchtower:
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower
If you only want your PhotoStructure container to be upgraded automatically,
refer to the Watchtower
documentation, and how
the watchtower
container is set up with
docker-compose.
Manual upgrade process #
Step 1: Pull the new image #
docker pull photostructure/server
Step 2: Shut down the outdated container #
Select “Shutdown” from the nav menu within the PhotoStructure, or run:
docker stop -t 60 photostructure
Step 3: Rename the outdated container #
docker rename photostructure photostructure_old
Step 4: Start a new container #
docker run \
--name photostructure \
--volumes-from photostructure_old \
`# <copy and paste all the non-volume options you set in step 3, like --user, --expose and -e >`
photostructure/server
Step 5: Remove the outdated container #
docker rm photostructure_old
Uninstalling PhotoStructure #
docker rm --force photostructure
- As you see fit, remove your
LIBRARY
,CONFIG
,LOG
, andTMP
directories, but take care not to delete photos and videos you want to keep! If you want to keep the originals in your library, but remove PhotoStructure’s preview images and videos, you can delete the$LIBRARY/.photostructure/previews
directory.
Synology docker instructions #
PhotoStructure’s docker image runs happily on intel x64 compatible Synology NAS
devices. First install the Docker package via Main Menu > Package Center
.
Install on Synology #
Unfortunately, Synology DSM’s Docker interface doesn’t support running
containers with --user
. This results in your library files being owned by
root
. It also is less secure to run PhotoStructure as root (even within a Docker container).
Because of these two issues, we recommend setting up the docker container via ssh rather than via the pointy-clicky Synology DSM interface.
Via ssh #
- Enable ssh on your NAS
- Set up the above instructions, but change
docker run
tosudo docker run
.
Via Synology DSM #
- Click
Main Menu > Docker
- Click the
Image
tab - Click
Add > Add from URL
- Enter
https://hub.docker.com/r/photostructure/server
- Pick
latest
- Wait for the image to download (it’s 300MB, it may take a minute). You’ll see a system notification when it’s done.
- Click
Launch
- Do not select high privilege. You can select resource limitation, but give PhotoStructure at least 2GB.
- Click
Advanced Settings
. - You may want to enable auto-start under the
Advanced Settings
tab. - Click the
Volume
tab. Read about the required volumes, and then add entries for/ps/library
/ps/tmp
/ps/logs
/ps/config
- and any existing directories you want to import into your library.
- Configure the network port as you’d like it. You can just map port 1787 directly.
- Click the Network tab, select “bridge”, click “Manage”, click “Add”, then select “PhotoStructure”.
- Launch the new container by clicking the power switch to the right, and wait for it to start successfully. If it fails, check under the Log tab. Email us if you need help!
Extra credit: if you click on the Container tab, double-click photostructure
,
and then click the Terminal tab, you can type --status
(and hit return) to
have PhotoStructure run health checks. (You can also run --pause
, --resume
,
and --exit
).
Upgrade on Synology #
Consider using Watchtower, which will upgrade all your docker images automatically: just ssh into your NAS, and run this:
sudo docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower
(Click “remove container” in the DSM Docker interface to uninstall watchtower).
If you’d rather upgrade manually, it’s a simple 16 step process:
- Click
Main Menu > Docker
- Click the
Container
tab - Click your PhotoStructure container to select it
- Click
Settings > Export
- Select
Export container settings
(you don’t need to store the container contents). - The export should be a small JSON file. Store it locally or on your NAS.
- With your PhotoStructure container still selected, make sure it isn’t running. If it is, select
Action > Stop
. - Click
Action > Delete
. (this is scary, but as long as you correctly mounted/ps/library
, your library will be on your NAS, not inside this container). - Click the
Image
tab - Click
Add > Add from URL
- Enter
https://hub.docker.com/r/photostructure/server
- Pick
latest
- Wait for the image to download (it’s 300MB, it may take a minute). You’ll see a system notification when it’s done.
- Return to the Container tab, and click
Settings > Import
- Import the JSON file you exported in step 6.
- Launch the new container by clicking the power switch to the right
QNAP docker instructions #
QNAP’s docker support is a bit persnickety as well.
First, open Container Station, click the “Create” tab on the left, then click " + Create Application" in the upper right:

QNAP’s Container Station
At least as of November 2020, QNAP uses a version of docker-compose from the
mid-17th century, which means the docker-compose recipe has
to be downgraded to version 3.0: the main result of this is that bind-mount
volumes must be formated as - $src:$dest
, as the below example.
The other issue is that it seems that the user
argument to services doesn’t
work correctly: (or at least it didn’t work on my QNAP correctly). The impact
of omitting the user
argument is that the library and contents will be owned
by root.
So, copy and paste this into the YAML text area, and then make sure you edit
every line that says CHANGE THIS LINE
.:
version: "3"
services:
photostructure:
image: photostructure/server:stable
restart: on-failure
stop_grace_period: 2m
# This is the user id and group id you want PhotoStructure to run as.
# Unfortunately this doesn't seem to work on QNAP. Omitting
# this parameter will make your library and contents be owned by root,
# which stinks. If you can get this working, please email us!
# user: 1000:100
volumes:
# This is where your PhotoStructure Library will be stored.
# It must be readable, writable, and have sufficient free space.
# If it is a remote volume, uncomment the PS_FORCE_LOCAL_DB_REPLICA
# environment line below. It needs to already exist!
# (use mkdir -p as the user that runs PhotoStructure)
- /share/homes/PhotoStructure:/ps/library # < CHANGE THIS LINE
# This must be fast, local disk with many gigabytes free.
# PhotoStructure will use this directory for file caching
# and for storing a temporary database replica when your
# library is on a remote volume.
- /tmp/photostructure-tmp:/ps/tmp
# This directory stores your "system settings". It needs to already exist!
# (use mkdir -p as the user that runs PhotoStructure)
- /share/homes/user/.photostructure:/ps/config # < CHANGE THIS LINE
# This directory stores PhotoStructure logfiles. It needs to already exist!
# (use mkdir -p as the user that runs PhotoStructure)
- /share/homes/user/.photostructure-logs:/ps/logs # < CHANGE THIS LINE
# Example additional directories to import into your library.
# Add as many as you'd like.
# You can set the mount point to anything like /media, or /pictures, ...
# (the name doesn't matter, as long as it is unique,
# and not in a system directory, like /usr/lib)
- /share/homes/path/to/photos:/pictures # < CHANGE THIS LINE
# Add more lines like the one above to scan additional directories.
ports:
- 1787:1787/tcp
environment:
- "PS_IS_DOCKER=1"
labels:
# See https://containrrr.dev/watchtower/container-selection/
- "com.centurylinklabs.watchtower.enable=true"
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Check for updates every couple hours: (3h * 60m * 60s)
command: --interval 10800
environment:
- "WATCHTOWER_LABEL_ENABLE=true"
For the Application name:
, use lower-case letters: photostructure
works.
Then click “Validate YAML”, and then click “Create”.
Your NAS will then download the images and start the new containers. Once it’s
done, click the Containers tab, then click the black triangle by
photostructure
. You should see something like this:

QNAP’s Container Station Containers
Click the awesomely-named “photostructure_photostructure_1” link to view the console and other information, including a clickable URL to view your PhotoStructure library.
Edit history #
November 17, 2020 #
- Added QNAP instructions
September 22, 2020 #
- Switched to
--restart on-failure
- Added
--stop-timeout 120
August 7, 2020 #
- Set up
--user
instructions - Normal users don’t have read/write to docker volumes, so
/ps/log
and/ps/cache
defaults are bind mounts in the example now.
August 4, 2020 #
- Added more detail about the different volumes
- Removed
--init
from thedocker run
command, as v0.8.3 doesn’t require it anymore - Added section for docker on Synology
- Pulled docker-compose instructions into new doc
July 31, 2020 #
- Systemd start-on-boot configurations were replaced with docker’s built-in
restart: unless-stopped
functionality. - Added config fix for https reverse proxy issues with Server-side events.
- Clarified when
.uuid
files were needed (only for imported volumes, not the library itself).
July 20, 2020 #
- If you used versions prior to 0.8, these instructions have changed. We simplified the instructions to be vanilla Docker,although you’re free to use docker-compose if you prefer.