bolt Valebyte VPS from $4/mo — NVMe, 60s deploy.

Get a VPS arrow_forward
eco Beginner Tutorial/How-to

How to Install PhotoPrism on a

calendar_month Aug 09, 2026 schedule 23 min read visibility 26 views
Установка PhotoPrism на VPS: Docker, автоматическая индексация и доступ по домену
info

Need a server for this guide? We offer dedicated servers and VPS in 50+ countries with instant setup.

Need a server for this guide?

Deploy a VPS or dedicated server in minutes.

Installing PhotoPrism on VPS: Docker, Automatic Indexing, and Domain Access

TL;DR

In this detailed guide, we will step-by-step set up PhotoPrism – a powerful, self-hosted application for managing photos and videos – on your Virtual Private Server (VPS) or Dedicated Server using Docker. You will learn how to install PhotoPrism, configure automatic media file indexing, and ensure secure access to your photo library via a domain name with HTTPS, using the Caddy reverse proxy server.

  • Setting up PhotoPrism and its dependencies (MariaDB) using Docker Compose.
  • Ensuring secure access to PhotoPrism via a domain name and HTTPS using Caddy.
  • Configuring automatic indexing of new photos and videos.
  • Recommendations for choosing the optimal VPS configuration and basic server security.
  • Backup and maintenance strategies for your media library.

What we are setting up and why

Diagram: What we are setting up and why
Diagram: What we are setting up and why

In the era of digital technologies, each of us accumulates gigabytes, and sometimes terabytes, of photos and videos. Cloud services, such as Google Photos or iCloud, offer convenient solutions but often raise questions about privacy, subscription costs, and control over your data. PhotoPrism is an elegant alternative that allows you to fully own and manage your media library on your own server.

PhotoPrism is an open-source application that uses advanced technologies to organize your photo collection. It automatically indexes images, detects faces, recognizes objects and places, and allows you to search by these criteria. You get a convenient web interface for viewing, sorting, and sharing your memories, while all data remains under your full control.

As a result of this guide, you will have a fully functional PhotoPrism running on your VPS. Your media library will be accessible via your own domain name (e.g., photos.yourdomain.com) with a secure HTTPS connection, ensuring data confidentiality and integrity. We will configure Docker Compose for easy deployment and management of PhotoPrism and its database, as well as automatic indexing of new files, so your library is always up-to-date.

Alternatives: Cloud Services vs. Self-Hosted on VPS

When it comes to photo management, there are two main paths:

  • Cloud-managed services: These include solutions like Google Photos, Apple iCloud Photos, Dropbox Photos.
    • Pros: Maximum convenience, no need to worry about infrastructure, automatic backups, often a free tier (with limitations).
    • Cons: Dependence on a third-party provider, data privacy concerns (who has access to your photos?), limited control over features and storage, increasing costs as data volume grows.
  • Self-hosting on a VPS/Dedicated server: Installing PhotoPrism (or alternatives like Nextcloud with the Photos app, Immich) on your own server.
    • Pros: Full control over your data and its privacy, no subscription fees for the service (only for the server), flexibility in configuration, ability to integrate with your other services.
    • Cons: Requires technical knowledge for installation and maintenance, you are responsible for backups and server security, initial time investment for setup.

Choosing self-hosted on a VPS is ideal for those who value privacy, want full control over their digital life, and are willing to invest time in setup. This allows you to create a personal, powerful, and reliable photo storage, independent of corporate policies and the pricing strategies of cloud giants.

What VPS configuration is needed for this task

Diagram: What VPS configuration is needed for this task
Diagram: What VPS configuration is needed for this task

Choosing the right VPS is a key step for stable and fast PhotoPrism operation. Resource requirements depend on the size of your media library, the number of users, and the intensity of indexing.

Minimum Requirements

  • CPU: 2 cores. PhotoPrism actively uses the processor for indexing, face and object recognition, and video transcoding. The more cores, the faster the initial indexing and processing of new files will be.
  • RAM: 4 GB. PhotoPrism, especially during active indexing and when working with a large database (MariaDB), can consume a significant amount of RAM. 4 GB is a comfortable minimum. If you have a very large library (hundreds of thousands of photos) or plan for many simultaneous users, consider 8 GB.
  • Disk:
    • Type: SSD or NVMe. Disk speed is critical for fast indexing and access to media files. NVMe is preferable for large libraries.
    • Volume: From 100 GB. The main volume will be occupied by your media library. In addition, PhotoPrism creates a cache and thumbnails, which also require space. Calculate disk space with a margin, based on the current size of your collection and plans for its expansion. For example, if you have 500 GB of photos, you will need at least 600-700 GB of disk space for the system, database, cache, and the files themselves.
  • Network: 100 Mbps or 1 Gbps. Good network bandwidth is important for fast uploading and downloading of photos, especially if you plan to share them or work with them remotely.

Specific VPS plan for the task (example)

For comfortable work with a media library of up to 1-2 TB and several active users, we recommend considering a VPS plan with the following characteristics:

  • CPU: 4 cores
  • RAM: 8 GB
  • Disk: 1 TB NVMe SSD
  • Network: 1 Gbps

Such a configuration will be sufficient for most home and small team PhotoPrism usage scenarios. For renting a VPS with the specified characteristics, you can consider a VPS with such characteristics from a reliable provider.

When a dedicated server is needed, not a VPS

A dedicated server becomes necessary if:

  • Your media library exceeds 5-10 TB and continues to grow actively.
  • You plan to use PhotoPrism for a large number of users (dozens or more) with intensive load.
  • You need maximum disk subsystem performance (e.g., RAID arrays with high-speed HDDs or NVMe).
  • You want full physical control over the hardware and maximum flexibility in configuration.

For most individual users and small teams, a VPS will be more than sufficient and more cost-effective. However, if you find that resource requirements exceed standard VPS offerings, consider a suitable dedicated server.

Location: What it affects

The choice of VPS server location affects several key factors:

  • Access speed (latency/ping): The closer the server is to you and your main users, the lower the latency and faster the loading of pages and media files. Choose a location that is geographically close to most of your users.
  • Legislation: Different countries have different laws regarding data storage and privacy. Ensure that your chosen location complies with your legal regulatory requirements.
  • Cost: VPS prices may vary slightly depending on the location due to differences in electricity costs, infrastructure, and taxes.

Overall, for PhotoPrism, access speed is a priority, so choose a data center located in your region or the region of your primary users.

Server Preparation

Diagram: Server Preparation
Diagram: Server Preparation

Before installing PhotoPrism, you need to perform basic setup and security for your fresh VPS. We will use Ubuntu Server 24.04 LTS as the base, as it is one of the most popular and well-supported operating systems for servers.

1. SSH Connection and New User Creation

Connect to your server as the root user, using the IP address provided by your provider. Replace YOUR_SERVER_IP with the actual IP address of your VPS.


ssh root@YOUR_SERVER_IP

After connecting, create a new user with sudo privileges. This is a best security practice, as working as root can be dangerous.


adduser yourusername # Create a new user, replace 'yourusername'
usermod -aG sudo yourusername # Add them to the sudo group

Set a password for the new user when prompted by the system.

2. SSH Key Setup (Recommended)

Using SSH keys instead of passwords significantly increases security. If you don't have an SSH key yet, generate one on your local machine:


ssh-keygen -t rsa -b 4096 # Generate a new SSH key

Then copy the public key to the server. Replace yourusername and YOUR_SERVER_IP with your details.


ssh-copy-id yourusername@YOUR_SERVER_IP # Copy the public key to the server

Now exit the root session and log in as the new user:


exit
ssh yourusername@YOUR_SERVER_IP # Log in as the new user

Disable password login for root and, optionally, for all users in the /etc/ssh/sshd_config file to allow only key-based login. Open the file:


sudo nano /etc/ssh/sshd_config

Find and change (or add) the following lines:


PermitRootLogin no
PasswordAuthentication no # Disables password login for all users
ChallengeResponseAuthentication no
UsePAM no

Save the file (Ctrl+O, Enter) and exit (Ctrl+X). Restart the SSH service:


sudo systemctl restart sshd

Important: Before disabling password login, make sure you can log in using an SSH key. Otherwise, you might lose access to the server.

3. System Update

Always start by updating the package database and installed packages to their latest versions.


sudo apt update # Update package list
sudo apt upgrade -y # Upgrade installed packages
sudo apt autoremove -y # Remove unnecessary dependencies

4. Firewall Setup (UFW)

The Uncomplicated Firewall (UFW) is easy to configure and serves as the first line of defense. By default, it blocks all incoming connections.


sudo apt install ufw -y # Install UFW
sudo ufw allow OpenSSH # Allow SSH connection (port 22)
sudo ufw allow http # Allow HTTP (port 80)
sudo ufw allow https # Allow HTTPS (port 443)
sudo ufw enable # Enable firewall
sudo ufw status verbose # Check UFW status

If you are using a different port for SSH, allow it instead of OpenSSH, for example sudo ufw allow 2222/tcp.

5. Install Fail2Ban

Fail2Ban protects your server from brute-force attacks by temporarily blocking IP addresses from which failed login attempts originate.


sudo apt install fail2ban -y # Install Fail2Ban
sudo systemctl enable fail2ban # Enable automatic startup of Fail2Ban
sudo systemctl start fail2ban # Start Fail2Ban

By default, Fail2Ban is already configured to protect SSH. You can create a /etc/fail2ban/jail.local file for custom settings, but the default ones will suffice for a start.

Your server is now ready for Docker and PhotoPrism installation.

Software Installation — Step-by-Step

Diagram: Software Installation — Step-by-Step
Diagram: Software Installation — Step-by-Step

For PhotoPrism installation, we will use Docker and Docker Compose, as this is the most recommended and convenient deployment method. Docker allows isolating the application with all its dependencies into containers, simplifying management and updates.

1. Docker Engine Installation

We will install Docker Engine, current for 2026 (assuming version 26.x+). We will use the official Docker repository.


# Update package list and install necessary dependencies
sudo apt update
sudo apt install -y ca-certificates curl gnupg

# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Add Docker repository to APT
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Update package list with the new Docker repository
sudo apt update

# Install Docker Engine, Docker CLI, and containerd
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Add the current user to the docker group to run commands without sudo
sudo usermod -aG docker yourusername

After adding the user to the docker group, you need to log out and log back into your SSH session for the changes to take effect:


exit
ssh yourusername@YOUR_SERVER_IP

Let's verify that Docker is installed correctly by running a test container:


docker run hello-world # Run a Docker test container

If you see the message "Hello from Docker!", then Docker is installed and working.

2. Docker Compose Installation

Docker Compose is usually installed as a plugin for Docker CLI. We already installed it in the previous step (docker-compose-plugin). Let's check the version:


docker compose version # Check Docker Compose version (should be 2.x.x)

3. Preparing Directory Structure for PhotoPrism

Let's create directories for storing PhotoPrism configuration, the database, and your media files. This is important for data preservation when updating containers.


mkdir -p ~/photoprism/config # Directory for PhotoPrism configuration
mkdir -p ~/photoprism/storage # Directory for PhotoPrism cache and auxiliary files
mkdir -p ~/photoprism/database # Directory for MariaDB database
mkdir -p ~/photoprism/originals # Directory where you will upload original photos and videos
mkdir -p ~/photoprism/import # Directory for automatic import (optional)

If necessary, you can change the paths to these directories. For example, if you have a separate disk for data, you can mount it to /mnt/data and use paths like /mnt/data/photoprism/originals.

4. Creating the Docker Compose File for PhotoPrism

Let's create a docker-compose.yml file that will define the PhotoPrism and MariaDB services.


cd ~/photoprism
nano docker-compose.yml # Create and open the docker-compose.yml file

Paste the following content. Make sure to replace YOUR_PHOTOPRISM_PASSWORD, YOUR_MARIADB_ROOT_PASSWORD, and YOUR_MARIADB_PASSWORD with strong passwords.


version: "3.8"

services:
  photoprism:
    image: photoprism/photoprism:24.x.x # Current PhotoPrism version for 2026
    container_name: photoprism
    restart: unless-stopped
    ports:
      - "2342:2342" # Port for direct access to PhotoPrism (will be proxied by Caddy)
    environment:
      PHOTOPRISM_ADMIN_USER: "admin" # PhotoPrism username
      PHOTOPRISM_ADMIN_PASSWORD: "YOUR_PHOTOPRISM_PASSWORD" # PhotoPrism user password
      PHOTOPRISM_DATABASE_DRIVER: "mariadb"
      PHOTOPRISM_DATABASE_DSN: "mariadb://photoprism:YOUR_MARIADB_PASSWORD@mariadb:3306/photoprism?parseTime=true"
      PHOTOPRISM_ORIGINALS_PATH: "/photoprism/originals"
      PHOTOPRISM_IMPORT_PATH: "/photoprism/import" # Path for automatic import
      PHOTOPRISM_STORAGE_PATH: "/photoprism/storage"
      PHOTOPRISM_CONFIG_PATH: "/photoprism/config"
      PHOTOPRISM_DETECT_NSFW: "false" # Can be set to "true" for detecting inappropriate content
      PHOTOPRISM_SIDECAR_YAML: "true" # Enable YAML file support for metadata
      PHOTOPRISM_LOG_LEVEL: "info"
    volumes:
      - ./originals:/photoprism/originals # Your original photos and videos
      - ./import:/photoprism/import # Directory for import
      - ./storage:/photoprism/storage # Cache, thumbnails, sidecar files
      - ./config:/photoprism/config # PhotoPrism configuration
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:11.x # Current stable MariaDB version for 2026
    container_name: mariadb
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: "YOUR_MARIADB_ROOT_PASSWORD" # Root password for MariaDB
      MARIADB_DATABASE: "photoprism" # Database name for PhotoPrism
      MARIADB_USER: "photoprism" # Database user for PhotoPrism
      MARIADB_PASSWORD: "YOUR_MARIADB_PASSWORD" # Database user password
    volumes:
      - ./database:/var/lib/mysql # Directory for database data
    # If the server has low RAM, memory usage for MariaDB can be limited
    # command: ["--max-connections=200", "--innodb-buffer-pool-size=256M"]

Save the file (Ctrl+O, Enter) and exit (Ctrl+X).

5. Running PhotoPrism with Docker Compose

Now start the containers:


docker compose up -d # Start containers in detached mode

This may take some time while Docker downloads images and starts the services. Check the status of the containers:


docker compose ps # Check the status of running containers

Both containers (photoprism and mariadb) should be in running status.

At this point, PhotoPrism is already running and accessible via your VPS's IP address on port 2342 (e.g., http://YOUR_SERVER_IP:2342). However, we want to configure access via a domain name with HTTPS, which will be done in the next step.

Configuration

Diagram: Configuration
Diagram: Configuration

Now that PhotoPrism is running, you need to configure access to it via a domain name, ensure HTTPS encryption, and, if necessary, automate indexing.

1. Domain Name Configuration

Before configuring HTTPS, ensure that your domain or subdomain points to your VPS's IP address. For example, if you want to access PhotoPrism at photos.yourdomain.com, you need to create an A-record in your domain's DNS settings, pointing to your server's IP address:

  • Type: A
  • Name/Host: photos (or @ if it's the main domain)
  • Value: YOUR_SERVER_IP

Wait a few minutes (up to several hours) for the DNS records to update.

2. Configuring HTTPS with Caddy (Reverse Proxy)

Caddy is a powerful, easy-to-use web server that automatically manages Let's Encrypt HTTPS certificates. It's an ideal choice for self-hosted applications.

Caddy Installation

Let's create a separate directory for Caddy and its configuration.


mkdir -p ~/caddy/Caddyfile # Directory for Caddy configuration
mkdir -p ~/caddy/data # Directory for Caddy data (certificates)
mkdir -p ~/caddy/config # Directory for Caddy configuration
cd ~/caddy

Let's create a docker-compose.yml file for Caddy in the ~/caddy directory. This will allow Caddy to run as a separate service that will proxy requests to PhotoPrism.


nano docker-compose.yml # Create and open the docker-compose.yml file for Caddy

Insert the following content:


version: "3.8"

services:
  caddy:
    image: caddy:2.7.x-alpine # Current stable version of Caddy for 2026
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80" # For Let's Encrypt HTTP-01 challenge
      - "443:443" # For HTTPS traffic
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile # Caddy configuration file
      - ./data:/data # Location for storing Caddy certificates and other data
      - ./config:/config # Location for Caddy configuration
    network_mode: host # Use host network for direct access to ports 80/443
    # Or, if you want to use a separate Docker network
    # networks:
    #   - webproxy

# networks:
#   webproxy:
#     external: true # Use an existing external network, if available
#     name: webproxy_network # Name of the network to create or use

Important: If you use network_mode: host, Caddy will directly use ports 80 and 443 of your VPS. This is the simplest method. If you already have other services using these ports, or you prefer a more isolated approach, you will need to create a shared Docker network and connect both Caddy and PhotoPrism to it.

For simplicity, in this guide, we will use network_mode: host for Caddy and assume that PhotoPrism is accessible on port 2342 on localhost (or the container's IP address if you are using a separate network).

Caddyfile Configuration

Create a Caddyfile in the ~/caddy directory. Replace photos.yourdomain.com with your actual domain.


nano ~/caddy/Caddyfile # Create and open Caddyfile

Insert the following content:


photos.yourdomain.com {
    # Enable data compression
    encode gzip zstd

    # HTTP security settings
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "no-referrer-when-downgrade"
        Content-Security-Policy "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; connect-src 'self' ws: wss:"
    }

    # Proxy requests to PhotoPrism
    reverse_proxy localhost:2342 {
        # Additional headers for PhotoPrism to work correctly through the proxy
        header_up Host {host}
        header_up X-Real-IP {remote_ip}
        header_up X-Forwarded-For {remote_ip}
        header_up X-Forwarded-Proto {scheme}
    }

    # Enable logging (optional)
    log {
        output file /var/log/caddy/access.log
    }
}

Save the file (Ctrl+O, Enter) and exit (Ctrl+X).

Create a directory for Caddy logs:


sudo mkdir -p /var/log/caddy
sudo chown -R yourusername:yourusername /var/log/caddy # Ensure the user has write permissions
Starting Caddy

Start the Caddy container:


cd ~/caddy
docker compose up -d # Start the Caddy container

Caddy will automatically obtain an SSL certificate from Let's Encrypt and configure HTTPS for your domain. You can now access PhotoPrism at https://photos.yourdomain.com.

3. Verifying Functionality

Open https://photos.yourdomain.com in your browser. You should see the PhotoPrism login page. Use the login admin and the password you specified in the docker-compose.yml for PhotoPrism.

You can also check the service's availability using curl from the server:


curl -I https://photos.yourdomain.com # Check HTTP headers

If you see an HTTP/2 200 status and headers indicating Caddy and PhotoPrism, then everything is working correctly.

4. Automatic Indexing

PhotoPrism can automatically index new files placed in the originals or import directory. To automatically scan for new files, you can use PhotoPrism's built-in function or configure a cron job.

Using PhotoPrism's Built-in Function

PhotoPrism has a built-in scheduler that can periodically scan for new files. You can configure this through the web interface in "Settings" -> "Library".

Using a Cron Job (for more precise control)

You can create a cron job on your VPS that will invoke the PhotoPrism indexing command.


sudo crontab -e # Open crontab for the root user (or yourusername if they are in the docker group)

Add the following line to run indexing, for example, every hour:


0 * * * * cd /home/yourusername/photoprism && docker compose exec photoprism photoprism index --cleanup --scan-originals --import

This command changes to the ~/photoprism directory, then executes the photoprism index command inside the PhotoPrism container.

  • --cleanup: Deletes metadata for files that no longer exist.
  • --scan-originals: Scans the originals directory for new files.
  • --import: Moves files from the import directory to originals after processing.

Replace /home/yourusername/photoprism with your actual path to the docker-compose.yml file.

Save and close the file. PhotoPrism will now automatically index new media files.

Backups and Maintenance

Diagram: Backups and Maintenance
Diagram: Backups and Maintenance

Backup is a critically important part of any self-hosted service. Your photos and videos are priceless memories, and their loss can be catastrophic. Server maintenance is also important for its stable and secure operation.

What to Back Up

For PhotoPrism, three main components need to be backed up:

  1. Original media files: These are the most important data. The ~/photoprism/originals directory.
  2. PhotoPrism Database (MariaDB): Contains all indexing information, metadata, faces, objects, albums, etc. The ~/photoprism/database directory.
  3. PhotoPrism Configuration: Configuration files and cache. The ~/photoprism/config and ~/photoprism/storage directories (although storage can be rebuilt, it's better to have a backup of it).
  4. Caddy Configuration: The ~/caddy/Caddyfile file and the ~/caddy/data directory (for certificates).

Simple Auto-Backup Script (cron + restic)

Restic is a modern, fast, and secure backup tool that supports deduplication, encryption, and many backends (S3, SFTP, MinIO, etc.).

1. Installing Restic

sudo apt install restic -y # Install Restic
2. Preparing the Restic Repository

As an example, we will use an SFTP server (e.g., a separate VPS or NAS). Replace sftp:[email protected]:/path/to/repo with your actual path. Also, create a strong password for the repository and store it in a safe place.


# Set the environment variable for the repository password
export RESTIC_PASSWORD="your_restic_repository_password"

# Initialize the Restic repository
restic init --repo sftp:[email protected]:/path/to/repo
3. Creating the Backup Script

Create a script file, for example, ~/backup_photoprism.sh:


nano ~/backup_photoprism.sh

Insert the following content. Replace /home/yourusername/photoprism, sftp:[email protected]:/path/to/repo, and your_restic_repository_password with your values.


#!/bin/bash

# Directory where docker-compose.yml for PhotoPrism is located
PHOTOPRISM_DIR="/home/yourusername/photoprism"
CADDY_DIR="/home/yourusername/caddy"

# Variables for Restic
RESTIC_REPO="sftp:[email protected]:/path/to/repo"
RESTIC_PASSWORD="your_restic_repository_password"

# Path to the log file
LOG_FILE="/var/log/photoprism_backup.log"

# Function for logging
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | sudo tee -a "$LOG_FILE"
}

log "--- Starting PhotoPrism backup ---"

# 1. MariaDB Database Backup
log "Creating MariaDB database dump..."
docker compose -f "$PHOTOPRISM_DIR/docker-compose.yml" exec mariadb mariadb-dump -u photoprism -p"$MARIADB_PASSWORD" photoprism > "$PHOTOPRISM_DIR/database/photoprism_dump.sql"
if [ $? -eq 0 ]; then
    log "Database dump successfully created."
else
    log "Error creating database dump."
    exit 1
fi

# 2. Performing Restic backup
log "Starting Restic backup..."
export RESTIC_PASSWORD="$RESTIC_PASSWORD" # Set password for the current session
restic backup \
    --repo "$RESTIC_REPO" \
    "$PHOTOPRISM_DIR/originals" \
    "$PHOTOPRISM_DIR/database" \
    "$PHOTOPRISM_DIR/config" \
    "$PHOTOPRISM_DIR/storage" \
    "$CADDY_DIR/Caddyfile" \
    "$CADDY_DIR/data" \
    --exclude "$PHOTOPRISM_DIR/database/photoprism_dump.sql" \
    --tag "photoprism-daily" \
    --verbose \
    >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
    log "Restic backup successfully completed."
else
    log "Error performing Restic backup."
    exit 1
fi

# 3. Deleting old snapshots (retention policy)
log "Cleaning up old Restic snapshots..."
restic forget \
    --repo "$RESTIC_REPO" \
    --tag "photoprism-daily" \
    --keep-daily 7 \
    --keep-weekly 4 \
    --keep-monthly 6 \
    --prune \
    >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
    log "Restic snapshot cleanup successfully completed."
else
    log "Error cleaning up Restic snapshots."
    exit 1
fi

# 4. Deleting temporary DB dump
rm "$PHOTOPRISM_DIR/database/photoprism_dump.sql"
log "Temporary DB dump deleted."

log "--- PhotoPrism backup completed ---"

Make the script executable:


chmod +x ~/backup_photoprism.sh

Create a .env file in the ~/photoprism directory to store the MariaDB password, so you don't have to write it directly into the script (better than directly in the script):


nano ~/photoprism/.env

Add:


MARIADB_PASSWORD="YOUR_MARIADB_PASSWORD"

Replace YOUR_MARIADB_PASSWORD with the password you used in docker-compose.yml. Then change the DB dump line in the script to:


docker compose -f "$PHOTOPRISM_DIR/docker-compose.yml" exec mariadb mariadb-dump -u photoprism -p"${MARIADB_PASSWORD}" photoprism > "$PHOTOPRISM_DIR/database/photoprism_dump.sql"

Or use docker compose exec mariadb sh -c "exec mariadb-dump -u photoprism -p\"$MARIADB_PASSWORD\" photoprism" > "$PHOTOPRISM_DIR/database/photoprism_dump.sql".

4. Setting up a Cron Job for Backup

Add the script to Cron for daily execution:


sudo crontab -e

Add the line (for example, at 3:00 AM every day):


0 3 * * * /home/yourusername/backup_photoprism.sh >> /var/log/photoprism_backup.log 2>&1

Ensure that the /var/log/ directory exists and is writable.

Where to Store Backups

  • External S3-compatible object storage: The most reliable and scalable option (AWS S3, Backblaze B2, DigitalOcean Spaces). Restic works great with S3.
  • Separate VPS: A small, inexpensive VPS in another data center for storing backups via SFTP.
  • Network Attached Storage (NAS): If you have a home NAS, you can configure SFTP access to it.

Never store backups on the same server as the original data. The 3-2-1 backup principle (3 copies of data, on 2 different media, 1 of which is off-site) is the golden standard.

Updates: rolling vs maintenance window

Regular updates are important for security and new features.

  • OS and Docker: It is recommended to update within a "maintenance window" when server load is minimal.
    
    sudo apt update && sudo apt upgrade -y
    sudo reboot # Reboot after updating the kernel or critical components
    
  • PhotoPrism and Caddy (Docker containers): To update Docker containers, simply stop them, download new images, and start them again.
    
    # Update PhotoPrism
    cd ~/photoprism
    docker compose pull photoprism mariadb # Download new images
    docker compose up -d # Recreate containers with new images
    
    # Update Caddy
    cd ~/caddy
    docker compose pull caddy # Download new image
    docker compose up -d # Recreate container with new image
    

    This can be done more frequently, as the risks are minimal. Always check PhotoPrism Release Notes before updating to ensure there are no critical changes requiring manual intervention.

Troubleshooting + FAQ

This section collects common problems and answers to frequently asked questions that may arise when installing and using PhotoPrism on a VPS.

Cannot access PhotoPrism via domain (502 Bad Gateway / Connection Refused)

What to check:

  1. DNS Records: Make sure your A-record for the domain (e.g., photos.yourdomain.com) correctly points to your VPS's IP address. Use dig photos.yourdomain.com on your local machine.
  2. Caddy: Check that the Caddy container is running: docker compose -f ~/caddy/docker-compose.yml ps. Make sure the Caddyfile is configured correctly (domain, PhotoPrism port). View Caddy logs: docker compose -f ~/caddy/docker-compose.yml logs -f. Caddy might not have been able to obtain an SSL certificate (check that ports 80 and 443 are open and not occupied by another service).
  3. PhotoPrism: Make sure the PhotoPrism container is running: docker compose -f ~/photoprism/docker-compose.yml ps. Check PhotoPrism logs: docker compose -f ~/photoprism/docker-compose.yml logs -f. Ensure PhotoPrism is listening on port 2342 within the Docker network.
  4. Firewall (UFW): Make sure ports 80, 443, and 22 (SSH) are open: sudo ufw status.

PhotoPrism indexes photos slowly or runs slowly

What to check:

  1. VPS Resources: Check CPU, RAM, and disk I/O usage with commands htop, free -h, iostat -x 1. If the CPU is constantly at 100%, RAM is full, or disk I/O is high, your VPS might not be able to handle the load.
  2. Disk Type: Make sure you are using SSD or NVMe. HDD will significantly slow down indexing.
  3. PhotoPrism Settings: In the PhotoPrism web interface, under "Settings" -> "Library", you can manage indexing settings, for example, disable some resource-intensive features (face, object recognition) if they are not critical.
  4. Database: If MariaDB is responding slowly, check its logs. Make sure it has enough RAM.

Cannot upload files to PhotoPrism

What to check:

  1. Permissions: Make sure the Docker user (or root, if running without sudo) has write permissions to the ~/photoprism/originals and ~/photoprism/import directories on the host system. You can try sudo chmod -R 777 ~/photoprism/originals ~/photoprism/import (although this is not best security practice, it can help diagnose the problem).
  2. Disk Space: Check free disk space: df -h. If the disk is full, uploading will not be possible.
  3. File Size: Check if there are any file size limitations in PhotoPrism or Caddy. By default, PhotoPrism supports large files, but Caddy might have request size limits (usually the default is sufficient).

What is the minimum suitable VPS configuration?

For running PhotoPrism with a small library (up to 100-200 GB) and 1-2 users, a VPS with 2 CPU cores, 4 GB RAM, and 200-300 GB NVMe/SSD disk will be minimally suitable. However, for comfortable operation, especially with larger media libraries and active indexing, it is recommended to increase these parameters, primarily RAM size and disk speed.

What to choose — VPS or dedicated for this task?

For most users, including developers, solo founders, gamers, and crypto enthusiasts, a VPS will be the optimal choice. It offers sufficient performance, flexibility, and cost-effectiveness. A dedicated server only makes sense for very large media libraries (several terabytes or more), many active users, or specific requirements for disk subsystem performance that a VPS cannot meet (e.g., hardware RAID). A VPS provides a good balance between cost and performance for personal or small team use of PhotoPrism.

How to update PhotoPrism or Caddy?

To update PhotoPrism or Caddy containers, simply follow these steps in the respective directories (~/photoprism or ~/caddy):


docker compose pull # Download the latest image version
docker compose up -d # Recreate the container using the new image

This will download the latest image version specified in docker-compose.yml (e.g., photoprism/photoprism:24.x.x) and restart the container with the new image, preserving all your data as it is stored in persistent volumes.

How to restore PhotoPrism from a Restic backup?

The restoration process includes:

  1. Installing a new VPS and configuring Docker/Docker Compose.
  2. Creating empty directories for PhotoPrism and Caddy.
  3. Initializing Restic and restoring data from the Restic repository into these directories:
    
    export RESTIC_PASSWORD="your_restic_repository_password"
    restic restore latest --repo sftp:[email protected]:/path/to/repo --target /home/yourusername/ # Restore to the user's home directory
    
  4. Starting PhotoPrism and Caddy containers with the restored data.
  5. Verification and, possibly, re-indexing in PhotoPrism if the database was severely corrupted or not restored correctly.

Conclusions and Next Steps

Diagram: Conclusions and Next Steps
Diagram: Conclusions and Next Steps

Congratulations! You have successfully installed and configured PhotoPrism on your VPS, ensuring secure access via a domain name with HTTPS and automatic indexing. Now you have a powerful, private, and fully controlled solution for managing your digital media library that does not depend on third-party cloud services.

You have gained full control over your photos and videos by hosting them on your own server. This allows you not only to maintain privacy but also to customize functionality to your needs, while ensuring high performance and reliability.

Next Steps:

  • Storage Scaling: If your media library continues to grow, consider connecting additional disks or network storage (NFS/SMB) to your VPS to expand the originals directory.
  • Performance Optimization: For very large libraries, you might consider optimizing MariaDB settings (e.g., increasing innodb_buffer_pool_size) or using a more powerful database like PostgreSQL, if PhotoPrism supports it as a primary database in the future.
  • Mobile App Integration: Explore options for synchronizing photos from mobile devices directly into the PhotoPrism import directory, using WebDAV or other protocols supported by PhotoPrism or third-party applications.

Was this guide helpful?

Your feedback helps us improve our guides.

Share this post:

Send this guide to someone who may find it useful.

Telegram VKVK WhatsApp Facebook LinkedIn XX

PhotoPrism installation on VPS: Docker, automatic indexing, and domain access
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.