Skip to content

Advanced NGINX Proxy Setup

While we believe this contributed content may be helpful to advanced users, we have not yet thoroughly reviewed it. If you have suggestions for improvement, please let us know by clicking to submit a change request.

Getting Support

Since NGINX is notoriously difficult to configure, we are unable to provide technical support for NGINX-related issues such as failed uploads, connection errors, broken thumbnails, and video playback problems. If you cannot resolve these on your own, we recommend that you ask their community for advice or use Traefik instead, which is easier to configure and more convenient to handle overall.

Using a reverse proxy in front of PhotoPrism has various benefits:

  • Make use of HTTP/2
  • Add encryption
  • Perform traffic optimization
  • Enhance security (NGINX may block dangerous request patterns the embedded Go-based HTTP server does not know about)

If you consider exposing your PhotoPrism instance to the evil internet, you should at least secure it with a proper HTTPS encryption.

This guide aims for a little more advanced setup, with good security in mind.

Trough the entire guide we use photoprism.example.com as domain. You have to change all these occurrences with your own domain / DynDNS.

Also, this was all tested on ubuntu/20.04 - But the commands should work on a lot of other versions as well. If you use CentOS, SuSE, or any other distro, look up the commands for your package manager.

Setup

Domain setup

First, we need to decide what we want to use as domain / address. We will use a proper domain in this guide, but it will technically also work with just a static IP address.

If you're lucky enough to have your own domain, just create a subdomain and use this for PhotoPrism.

If you want to expose your instance hosted at home, just use a DynDNS provider (just duckduckgo it, there a multiple ones that are free).

Tip

if you're new to DynDNS it might be good to know that most routers do support DynDNS. Therefore only minimal setup is required. Just search for your router name + DynDNS ;)

Install NGINX on your machine

If not already done, install the webserver on your machine which you wish to use as proxy. This also can be the same host that is running the docker container.

apt-get update && apt-get install -y nginx apache2-utils

Info

We use apache2-utils later for the password generation of the optional extra security with http basic auth.

Acquire a certificate

Install cerbot

Luckily nowadays there is a free certificate authority called Let's Encrypt. You can just use their certbot tool and acquire a new certificate in seconds.

For Ubuntu / Debian the package is directly in the repository. Therefore, you can easily install it using this command:

apt-get update && apt-get install -y certbot python3-certbot-nginx

Generate the certificate

Now, just request a new certificate by using this command:

certbot -d photoprism.example.com

After that you should have a new certificate in: /etc/letsencrypt/live/photoprism.example.com/

Note

In order for Let's Encrypt to work, the server has to be accessible from the internet on port 443

Tip

Please refer to Let's Encrypts documentation for automated certificate renewal. The certificates are valid for around 90 days.

Setup NGINX

Now that we have our certificate its time to setup the NGINX itself. Since it is best practice to create a configuration file per application / domain, this is exactly what we gonna do.

Create a new file /etc/nginx/sites-available/photoprism.example.com and put the following content in it. Keep in mind to change the domain (there a multiple entries!)

# 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;
    listen [::]:80; # HTTP IPv6
    # enforce https
    return 301 https://$server_name$request_uri;
}
server {

    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://docker.homenet:2342;
    }
}

Have a look at the individual comments in the configuration for a further description.

Tip

Don't forget to change the PhotoPrism IP / DNS on the bottom of the config... ;)

Once you've changed everything you need, let's restart nginx:

sudo nginx -t
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
systemctl reload nginx
Now, you should have access to PhotoPrism.

Warning

Make sure to setup proper firewalling on the machine that is running PhotoPrism. Have a look at ufw for simple firewall rules.