Skip to content
Photo Server

Your Old PC Might Be the Best Photo Server You’ll Ever Own

Turn that aging desktop into a sleek, self-hosted photo server — organize, back up, and access your entire photo library from anywhere.


For many of us, the search for alternatives to Google and Apple Photos is driven by a desire for more privacy or a need for a shared, family-oriented setup. Their products, while powerful, are often too individualized and cloud-dependent. Sometimes, all we need is a simple, secure photo server that stays within the home.

Thankfully, several open-source solutions offer robust features and active community support that put big tech’s products to the test. Here are some of the best self-hosted options for creating a private, family-friendly photo library right at home.

Skills involved

Linux Administration, Docker, Computer Networking, Raid Arrays, Network File Sharing

What are the Options

Before we procede, we need to know what our options are. In this section we look at open-source alternatives, as well as some ready-made, proprietary, but still self-hosted solutions.

Open Source Options

  1. Lychee A sleek and user-friendly photo management system that you can run on your server to manage and share photos. Lychee emphasizes simplicity and ease of use.

    GitHub / 6.3k stars, 224 watching, 675 forks

  2. Immich A high-performance, self-hosted photo and video management solution designed for rapid access and efficient organization of media files. Immich offers features like automatic backups and multi-user support.

    GitHub / 50.3k stars, 226 watching, 2.7k forks

  3. Piwigo A mature and versatile photo gallery software for the web, Piwigo comes with powerful features to publish and manage your collection of pictures. It supports numerous plugins and themes for customization.

    GitHub / 3.2k stars, 74 watching, 442 forks

  4. Photoview A simple and user-friendly photo gallery tailored for photographers, Photoview provides an easy and fast way to navigate directories with thousands of high-resolution photos. It supports RAW files and offers face recognition capabilities.

    GitHub / 5.3k stars, 39 watching, 397 forks

  5. PhotoPrism A privately hosted app for browsing, organizing, and sharing your photo collection. PhotoPrism uses the latest technologies to automatically tag and find pictures without getting in your way.

    GitHub / 35.3k stars, 335 watching, 2k forks

  6. Photonix A photo management application that uses machine learning to help you organize and find your photos effortlessly. Photonix offers features like facial recognition and object detection to enhance your photo browsing experience.

    GitHub / 0.9k stars, 34 watching, 125 forks

  7. LibrePhotos A self-hosted open-source photo management service that supports all types of photos, including RAW formats. LibrePhotos offers features like face recognition, object detection, and a timeline view to organize your photos effectively.

    GitHub / 7k stars, 55 watching, 303 forks

  8. PiGallery2 A lightweight, fast photo gallery designed for personal photo collections. PiGallery2 provides a clean interface, supports large photo libraries, and is easy to set up on most devices.

    GitHub / 1.8k stars, 23 watching, 206 forks

  9. Chevereto A self-hosted image hosting solution that offers a versatile, customizable gallery for personal or public use. Chevereto includes features like image hosting, URL shortening, and robust sharing options.

    GitHub / 517 stars, 4 watching, 44 forks

  10. Ente Ente is a service that provides a fully open source, end-to-end encrypted platform for you to store your data in the cloud without needing to trust the service provider. The platform includes 2 apps: Ente Photos and Ente Auth a 2FA alternative to the deprecated Authy.

    GitHub / 15.8k stars, 42 watching, 814 forks

  11. Damselfly Damselfly is a photo management tool that provides advanced search and tagging features, making it ideal for large collections. With a focus on easy organization and powerful search capabilities, Damselfly is suited for users with extensive photo libraries.

    GitHub / 1.5k stars, 25 watching, 76 forks

Each of these platforms provides unique features to cater to different needs, allowing you to choose the one that best fits your family’s photo-sharing preferences.

The star, watcher, and fork counts listed below are meant to give you a general sense of each project’s popularity and community involvement. These numbers aren’t live and may have changed since publishing. For the latest counts, check each project’s GitHub page.

Intermediate Option: Nextcloud Memories

Nextcloud is a versatile, self-hosted platform offering much more than just photo storage—it includes file sharing, calendar, contacts, and a range of productivity tools. For photo management, the Nextcloud Memories add-on provides you with feature-rich photo management. If you’re already using Nextcloud for other purposes, Memories is your best option. Nextcloud can be self-hosted, but you can find free, hosted Nextcloud by various providers. You just sign up with your email. Extra-storage options are sometimes offered at a cost.

Learn more on GitHub about Nextcloud Memories and the self-hosted Nextcloud Server.

Preconfigured NAS Options

If you’re looking for a solution that comes preconfigured and works out of the box, both Synology and QNAP offer photo management software bundled with their NAS servers. These options require purchasing a NAS server along with compatible hard drives, but they offer a streamlined setup process for easy use.

  1. Synology Photos Synology Photos is an all-in-one photo management app included with Synology NAS servers. It combines robust organization, sharing features, and a simple interface, making it easy to manage large photo collections. Learn more about Synology Photos

  2. QNAP Photo Station QNAP Photo Station offers a powerful, intuitive solution for managing and sharing photos on a QNAP NAS. With features like user permissions, slideshows, and albums, it provides a straightforward experience for personal and family photo storage. Learn more about QNAP Photo Station

These 2 options however do not present you with a learning opportunity nor do they make use of old hardware you may have lying around. While they do offer interesting features, and definite ease of use, one main critique I have is that a regular PC, even old, is usually more powerful.

The Overview

We need a running PC and that includes an operating system. The one thing that every option has in common is Docker. They all run on Docker. So if your operating system run Docker, then your good! That’s means MacOS, Windows and Linux, they all do. But of course, over here, we do Linux. For MacOS and Windows, there should be enough information here to get things running. But what are you waiting for, switch to Linux!

The issue now is to decide which once we’re going to use.

Our PC can be running an Ubuntu server with our docker services, hidden in a closet and connected by WiFi.

A small improvement could be to have an ethernet connection to you home router. Additionally the router could be running a good operating system like OpenWRT or similar. It could provide a few useful options, but your current router may do. You could always check if OpenWRT is compatible with the router you have.

in essence we are creating a NAS (network sharing + storage), a web server for our web interface in the browser, and all the backend utilities for photo manipulation.

we need to set up the network sharing, and I’ll give you some storage options, and docker will do the rest

the setup could look like this, everything works from the browser, so you could visit for example http://photoserver for photo management.

Additionally, you could have direct access to the photos in your file explorer.

That would give you direct access in your file explorer. It would be like having a local folder with all your images and more.

The Server and the Operating System

As mentioned, any operating system that can run Docker can do what we want it to do. But this guide will run through Linux commands. While MacOS is sometimes similar, there are differences. For Windows, you can install WSL (Windows Subsystem for Linux) which should allow you to follow along. But WSL runs in a virtualized environment. You may need to rely on Windows’ utilities in addition.

I’ll provide some Windows and MacOS guidance as we go forward, but we will assume principally that we have a running Linux server, optionally running a desktop environment. The desktop environment is not necessary, but it can provide you with some flexibility. The command line advantage is simplicity, believe it or not, because there is just one way to do things. Step by step, command after command.

Linux Server

If you’re setting up a Linux server for the first time, I highly recommend starting with Ubuntu. It’s user-friendly, has extensive documentation, and boasts a large, supportive community.

However, Fedora is also a strong choice, with excellent installation guides, comprehensive documentation, and an active community.

For those seeking a more hands-on experience, I personally use Arch Linux, though it may not be suited for everyone. I recommend it for advanced users who are comfortable reading and following detailed documentation.

  • Arch Linux doesn’t have separate server and desktop versions, nor a graphical installer. Installation is entirely command-line based, and you decide what to install.
  • While Arch is minimal by design, it has some of the best documentation available. If you’re eager to learn, check out the Arch Linux Wiki.
  • The Arch Installation Guide is the default starting point and requires a hands-on approach.
  • Arch-based distributions with graphical installers, like Manjaro and EndeavourOS, offer a more user-friendly Arch experience.

Now be sure to install the specific tools we need for this setup.

apt update && apt install docker docker-compose nfs-utils git samba wget mdadm # Ubuntu
pacman -Syu docker docker-compose nfs-utils git samba wget mdadm # Arch
dnf update && dnf install docker docker-compose nfs-utils git samba wget mdadm # Fedora
  • docker
  • docker-compose
  • nfs-utils
  • git
  • mdadm (optional)
  • samba (optional)
  • wget

The rest of this post supposes that you have a running Linux server, that has working networking either WiFi or ethernet, receives an IP from a router, and has all the aforementioned software packages installed.

Docker Setup

Here are 3 scenarios of our setup. If it’s your first time working with docker you might understand this section after everything is working. But it’s important for us to pause so we can understand the plan and understand that there is overlap in the tools we are using.

Scenario 1: Docker Restart Policies and Health Checks

  • Setup: systemd will run Docker in detached mode and will not monitor the status of the Docker command or the running containers. The systemd service will always be ‘active’ (unless manually stopped) oblivious of the Docker command. You will rely on Docker for service status and handling failed containers.
  • Health Checks: Add Docker health checks to monitor the services running within the containers. The software inside the containers may fail even if the container itself stays running. Health checks only mark the container as unhealthy.
  • When Docker restart policies fail to solve the problem: You will detect any service failure when you try to access the software through your browser, prompting you to check the server. The systemd service will be ‘active’ and you will troubleshoot with Docker. You may see that a container is ‘unhealthy’ and ‘Up’ or ‘Exited’.

Scenario 2: Monitor Docker Health Checks with systemd

  • Setup: Same as scenario 1 where Docker runs detached, will restart failed containers, and tag unhealthy containers.
  • Additional Monitoring and Restarting:
    • Add a systemd-executed script to monitor Docker health events.
    • This enables Docker health events to be logged in the system and automatic restarts of unhealthy containers.
  • When Docker restart policies and health checks fail to solve the problem: You will detect the service failure in the browser, prompting you to check the server. This time, you will find health check events logged in the system.

Scenario 3: Use systemd Restart Policies

  • Setup: Run Docker in non-detached mode and use systemd restart policies instead of Docker’s.
  • Monitoring: same as scenario 2.
  • When systemd restart policies fail: same as scenario 2.

The best practice is to rely on Docker restart policies since they are built-in for this purpose. In my opinion, systemd restart policies are better suited for services that lack built-in restart capabilities.

Additionally, this setup is not mission-critical, and in my experience, the service is highly stable. You can rely on the provided mechanisms and proceed. However, we will implement Scenario 2 for the learning experience.

File System

If you have a dedicated drive set it up so that it’s ready and always available.

mkfs.ext4 /dev/sda
blkid /dev/sda # copy its uuid
echo "UUID=uuid-from-above-here /srv/share ext4 defaults 0 2" >> /etc/fstab
mkdir -p /srv/share
mount /dev/sda /srv/share

If you have 4 spare drives (they would have to be identical) you can set them up in a raid. We can be as good as Synology and Qnap.

mdadm --create --verbose /dev/md0 --level=5 --raid-devices=4 /dev/sda /dev/sdb /dev/sdc /dev/sdd
mkfs.ext4 /dev/md0
mkdir -p /srv/share
blkid /dev/md0 # copy its uuid
echo "UUID=uuid-from-above-here /srv/share ext4 defaults 0 2" >> /etc/fstab
mdadm --detail --scan >> /etc/mdadm.conf

If you do not have dedicated drive or drives just mkdir -p /srv/share.

File System Network Share

Now we share that drive, that raid array, or that folder with the network.

# /etc/exports.d/my.exports
/srv/share 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
# /etc/samba/smb.conf
[photoserver] # This is the name of the share and it's visible on the network
   path = /srv/share
   browseable = yes
   writable = yes
   valid users = yourusername
   read only = no
smbpasswd -a yourusername
smbpasswd -e yourusername
systemctl enable --now smb.service # Manages file sharing.
systemctl enable --now nmb.service # Manages network browsing and name resolution.
systemctl enable --now nfs-server.service

LibrePhotos

git clone https://github.com/LibrePhotos/librephotos-docker.git /opt/librephotos/librephotos-docker
mkdir -P /opt/librephotos/scripts
mkdir -P /srv/librephotos
mkdir -P /srv/share
touch /etc/systemd/system/librephotos.service
touch /etc/systemd/system/librephotos-healthcheck.service
touch /opt/librephotos/scripts/monitor-docker-healthchecks.sh
chmod +x /opt/librephotos/scripts/monitor-docker-healthchecks.sh
mv /opt/librephotos/librephotos-docker/librephotos.env /opt/librephotos/librephotos-docker/.env

Edit the .env file and change to values to what we have above: scanDirectory=/srv/share and data=/srv/librephotos. You can leave the other values the same. I changed the container names to have a librephotos prefix like librephotos_db.

Create the following file with its contents:

# /etc/systemd/system/librephotos.service
[Unit]
Description=Librephotos
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
# Docker runs detached with the `-d` option
# This services stays active regardless of the exit status of the containers
ExecStart=/usr/bin/docker compose -f /opt/librephotos/librephotos-docker/docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f /opt/librephotos/librephotos-docker/docker-compose.yml down
# But we add monitoring so we can try a restart when unhealthy
ExecStartPost=/opt/librephotos/scripts/monitor-docker-healthchecks.sh

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/librephotos-healthcheck.service
[Unit]
Description=LibrePhotos Docker Health Monitor
After=librephotos.service
Requires=librephotos.service

[Service]
ExecStart=/opt/librephotos/scripts/monitor-docker-healthchecks.sh
Restart=always

[Install]
WantedBy=multi-user.target

Create this file as well:

#!/bin/bash
# /opt/librephotos/scripts/monitor-docker-healthchecks.sh

# The `docker events` command watches for live Docker events
# Events that pass the 2 filters are piped to the `while` code block
# Events that pass the 2 filters only occur when the status changes from healthy to unhealty and back

docker events \
    --filter label=com.docker.compose.project=librephotos-docker \ # default project name is folder name
    --filter event=health_status \
    --filter health_status=unhealthy | grep unhealthy | while read -r event; do
    # docker event filters do not work like I think they should work, forced to add grep

    # Log it
    echo "Unhealthy Docker event detected: $event" | systemd-cat -t librephotos-health-check

    # Restart if unhealthy requires a `healthcheck` on the container
    # LibrePhotos only has a healthcheck on the db container, open the docker-compose file to see
    docker restart $(docker ps --filter "health=unhealthy" --filter label=com.docker.compose.project=librephotos-docker --quiet)
done
systemctl daemon-reload
systemctl enable --now librephotos.service
systemctl enable --now librephotos-healthcheck.service

If the server, the service and the network is working you should be able to visit your photo management software in the browser of any PC or Mac on the network at http://192.168.1.100:3000 or if name resolution is working http://photoserver:3000, where photoserver is the hostname of the Linux server that you set up during the install process. This requires that your router provide proper name resolution.

Immich

mkdir -p /srv/immich/db
mkdir -p /opt/immich
cd /opt/immich
wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
touch /etc/systemd/system/immich.service
touch /etc/systemd/system/immich-healthcheck.service
touch /opt/immich/monitor-docker-healthchecks.sh
chmod +x /opt/immich/monitor-docker-healthchecks.sh

Create the following file with its contents:

# /etc/systemd/system/immich.service
[Unit]
Description=Immich
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
# Docker runs detached with the `-d` option
# This services stays active regardless of the exit status of the containers
ExecStart=/usr/bin/docker compose -f /opt/immich/docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f /opt/immich/docker-compose.yml down

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/immich-healthcheck.service
[Unit]
Description=Immich Docker Health Monitor
After=immich.service
Requires=immich.service

[Service]
ExecStart=/opt/immich/monitor-docker-healthchecks.sh
Restart=always

[Install]
WantedBy=multi-user.target

Create this file as well:

#!/bin/bash
# /opt/immich/monitor-docker-healthchecks.sh

# The `docker events` command watches for live Docker events
# Events that pass the 2 filters are piped to the `while` code block
# Events that pass the 2 filters only occur when the status changes from healthy to unhealty and back

docker events \
    --filter label=com.docker.compose.project=immich \ # default project name is folder name
    --filter event=health_status \
    --filter health_status=unhealthy | grep unhealthy | while read -r event; do
    # docker event filters do not work like I think they should work, forced to add grep

    # Log it
    echo "Unhealthy Docker event detected: $event" | systemd-cat -t immich-health-check

    # Restart if unhealthy, all immich containers have a healthcheck
    docker restart $(docker ps --filter health=unhealthy --filter label=com.docker.compose.project=immich --quiet)
done
systemctl daemon-reload
systemctl enable --now immich.service
systemctl enable --now immich-healthcheck.service

If the server, the service and the network is working you should be able to visit your photo management software in the browser of any PC or Mac on the network at http://192.168.1.100:2283 or if name resolution is working http://photoserver:2283, where photoserver is the hostname (a command you can type to see the value of) or cat /etc/hostname of the Linux server that you set up during the install process. This requires that your router provide proper name resolution.

Connect to the network share

Then from that other client PC or Mac, if nfs is working you should be able to have network share as if it was local:

mkdir ~/PhotoServer
mount photoserver:/srv/share ~/PhotoServer

Works on Linux and MacOS

For PCs running Windows you connect to the samba share like this:

  1. Enable SMB in Windows (if necessary) Open Control Panel > Programs > Turn Windows features on or off.
  2. Open File Explorer and Map the Network Drive Open File Explorer and go to This PC. Click on Map network drive in the top toolbar. Choose a drive letter from the dropdown (e.g., Z:). In the Folder field, enter the path to your Samba share using this format: \photoserver\multimedia \192.168.1.100\multimedia

You have:

  • Web Access
  • File system access

Windows and MacOS

Here I’ll provide a quick overview of Windows and MacOS equivalencies, if you followed along above these 2 sections should fill in the gap if you choose not to use a Linuxdistro.

Windows

  • Install Docker Desktop
  • Optional:
    • Install Windows Subsystem for Linux
    • After installation, open Docker Desktop
    • Go to Settings > Resources > WSL Integration
    • Enable integration with your Linux distribution by checking the box next to it
    • With this you can follow along below
    • You can use SCM to run scripts in WSL, but WSL is not meant to be a system wide running service
  • Better:
    • Windows uses Service Control Manager (SCM) for background processes
    • It’s best to put our photo management software in c:\ProgramData
    • And scripts for starting our photo management software c:\ProgramData\Scripts
    • And using the sc command prompt (cmd) to create the system-wide autostarting service
      sc create LibrePhotos binPath= "C:\ProgramData\Scripts\StartLibrePhotos.bat" start= auto
      sc start LibrePhotos
  • Use Powershell commands too:
    Get-Service # Lists services and their statuses.
    Set-Service # Configures service properties (e.g., start type).
    Start-Service
    Stop-Service
  • Create Windows shared folders under the properties menu of the folder or drive
  • Create a raid array under Control Panel by creating a storage pool
  • The assigned letter can be shared with the network under the properties menu

MacOS

  • Install Homebrew
  • With Homebrew install Docker: brew install docker
  • MacOS uses Launchd instead of Systemd
    • Launch Agents are user-level services that start when a user logs in, with user permissions, and are located in ~/Library/LaunchAgents
    • Launch Daemons are system-level services that start at boot time, before any user logs in, with root permissions and are located in /Library/LaunchDaemons.
      launchctl load `/Library/LaunchDaemons/com.home.photoserver.plist` # Loads a service (starts it if needed).
      launchctl unload `/Library/LaunchDaemons/com.home.photoserver.plist` # Unloads (stops) a service.
      launchctl list # Lists all currently loaded services
  • Third party software, the photo management software, can be placed in /usr/local/lib and /usr/local/var for metadata and settings
  • Data like photos and software data can be stored in /Users/Shared or a dedicated volume /Volumes/SharedVolumeName (name assigned by you when you format the drive)
  • MacOS network shares are created under System Preferences > Sharing > File Sharing
  • Raid array can be built with Disk Utility or the SoftRAID software package

How am I doing?

I care about making these articles better. If something was unclear, helpful, surprising—or if you just want to say hi—you can leave a comment on the discussion thread below.

This happens on our forum (Discourse), so you may be asked to log in or create an account.