PhotoPrism is a server-based application for browsing, organizing, and sharing your photo collection. Here, I describe how I set it up on a Google Compute Engine virtual machine using docker-compose, an nginx https proxy, and LetsEncrypt.
Disclaimer: I know next to nothing about securing applications exposed to the internet. Use at your own risk.
In this entire post, I assume your domain will be photoprism.example.com
.
You'll need to change all instances of that throughout.
First, I created a new project in Google Compute just for this. It simplifies the firewall rules.
Depending on whether you want automatic Tensorflow image labeling:
As for the other VM settings:
certbot
will try to connect to this machine over HTTP to validate you own the domain.photoprism.example.com
. Change photoprism
to a different subdomain if you like)
photoprism A 1h <static IPv4 address>
This snippet will do it all in one shot. If you don't need the swapfile, you can skip that part at the end. The first part cribs the current docker-ce install instructions for x86_64 debian. Check to make sure they are still current.
(
sudo apt-get update
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose wget htop nginx apache2-utils certbot python3-certbot-nginx
wget https://dl.photoprism.org/docker/docker-compose.yml
sudo docker-compose pull
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab > /dev/null
)
remember to change photoprism.example.com
Run sudo certbot certonly -d photoprism.example.com
Since we installed nginx in the previous step, select the "nginx plugin" option (this is where you need HTTP allowed through the firewall).
After answering the prompts, the successful result was:
Plugins selected: Authenticator nginx, Installer None
Obtaining a new certificate
Performing the following challenges:http-01 challenge for photoprism.example.com
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/photoprism.example.com/fullchain.pem Your key file has been
saved at: /etc/letsencrypt/live/photoprism.example.com/privkey.pem Your cert will
expire on 2021-04-03. To obtain a new or tweaked version of this certificate in
the future, simply run certbot again. To non-interactively renew *all* of your
certificates, run "certbot renew" - If you like Certbot, please consider supporting
our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
I used the photoprism commit af71e5f704461012be028834ab499f9c2b8e0a7e
from Jan 2, 2021.
Photoprism is configured with docker-compose.yml
.
You will need to choose and enter three seprate passwords. I recommend not using special characters, as the wrong combo can cause things to try to look up environment variables with unpredicable results.
PHOTOPRISM_DATABASE_PASSWORD
/MYSQL_PASSWORD
PHOTOPRISM_ADMIN_PASSWORD
MYSQL_ROOT_PASSWORD
Note that PHOTOPRISM_DATABASE_PASSWORD
and MYSQL_PASSWORD
must be the same.
If you are using a smaller instance, also set
PHOTOPRISM_WORKERS: 1
PHOTOPRISM_DISABLE_TENSORFLOW: "true"
To start photoprism, run sudo docker-compose up -d
You can look at logs with sudo docker-compose logs
. you should not see anything like "failed to connect to database"
If you goof this up, you need to do something like (this will delete everything)
sudo docker-compose down
sudo docker volume prune
sudo rm -r storage database
remember to change photoprism.example.com
I had to follow alternate instructions here (the current instructions here did not work for me).
First, create /etc/nginx/sites-enabled/photoprism.example.com
Put the following content in it.
This is taken from the PhotoPrism instructions, except proxy_pass http://localhost:2342;
instead of proxy_pass http://docker.homenet:2342;
# PhotoPrism Nginx config with SSL HTTP/2 and reverse proxy
# This file gives you an example on how to secure you PP instance with SSL
server {
# listen 80; # If you really need HTTP (unsecure) remove the "#" on the beginning. Not recommended!
# listen [::]:80; # HTTP IPv6
listen 443 ssl http2; # Listen on port 443 and enable ssl and HTTP/2
listen [::]:443 ssl http2; # Same for IPv6
# Put your domain name in here.
server_name photoprism.example.com;
# - - - - - - - - - -
# SSL security
# - - - - - - - - - -
ssl_certificate /etc/letsencrypt/live/photoprism.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photoprism.example.com/privkey.pem;
# Since the PP API is also used on Android, we have to keep TLS1.2 in here for a while.
# A lot of the older Android devices do not support TLS1.3 yet :/
ssl_protocols TLSv1.2 TLSv1.3;
# Use good and strong ciphers, disable weak and old ciphers
ssl_ciphers HIGH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
# Enable HSTS (https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security)
add_header Strict-Transport-Security "max-age=172800; includeSubdomains";
# This checks if the certificate has been invalidated by the certificate authority
# You can remove this section if you use self-singed certificates...
# Enable OCSP stapling (http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/photoprism.example.com/fullchain.pem;
# DNS Servers to use for OCSP lookups
resolver 8.8.8.8 1.1.1.1 9.9.9.9 valid=300s;
resolver_timeout 5s;
# - - - - - - - - -
# Reverse Proxy
# - - - - - - - - -
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr; # Let PP know the clients real IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Let PP know that a proxy did forward this request
proxy_set_header Host $http_host; # Set Proxy host info
proxy_http_version 1.1; # Required for WebSocket connection
proxy_set_header Upgrade $http_upgrade; # Allow protocol switch to websocket
proxy_set_header Connection "upgrade"; # Do protocol switch
proxy_set_header X-Forwarded-Proto $scheme; # Let PP know that this connection used HTTP or HTTPS
client_max_body_size 500M; # Bump the max body size, you may want to upload huge stuff via the upload GUI
proxy_buffering off; # Do not hold back the request while the client sends data, give the stream directly to PP
location / {
# Optional; additional protection with Basic Auth.
# Note: This breaks WebDAV without additional configuration
# You also have to create a .htpasswd file using the command:
# "htpasswd -c /etc/nginx/.pp_htpasswd my_secret_user"
# - - -
# auth_basic "PhotoPrism Pre Auth";
# auth_basic_user_file /etc/nginx/.pp_htpasswd;
# pipes the traffic to PhotoPrism
# Change this to your PhotoPrisms IP / DNS
proxy_pass http://localhost:2342;
}
}
Then run sudo systemctl restart nginx
.
You should see no errors
Navigate to https://photoprism.example.com and log in with the PHOTOPRISM_ADMIN_PASSWORD
you chose previously.
Once everything is working, set up automatic image restart. I guess this causes the photoprism image to be restarted unless you explicitly shut it down.
docker-compose stop
docker-compose.yml
docker-compose up -d
docker-compose stop
systemctl stop nginx
sudo certbot certonly -d photoprism.example.com
systemctl start nginx
docker-compose up -d
docker-compose pull photoprism
docker-compose stop photoprism
docker-compose up -d photoprism
Congrats!
unattended-upgrades
seems to be configured by default on the Google Compute debian image.
You almost certainly want this.
I set up a weekly automated snapshot under Compute Engine
> Snapshots
> Snapshot Schedules
.
Attach it to the machine on the Disks
page with Edit
.