As an avid personal photographer, I'm always looking for good ways to display my photos. I'd prefer not to host my photos on Instagram, Flicker or one of the commercial sites.

The primary reason for this is most of them its almost impossible to get your photos off these sites.

So looking around at the self hosted arena after trying a few options I came out with Chevereto

Chevereto Image Hosting script - Self-hosted image hosting
An image hosting script that allows you to get your own image hosting website. It’s your hosting and your rules, say goodbye to the closures and restrictions.

Chevereto is a modern web app, it scales on devices has a solid upload interface for multiple images. Its quick and its deployable via script.

There is a free version, however i've gone for the personal version which has a cost involved.

What do I have setup?

The setup is pretty basic, the config however was a pain on the nginx side. The usual problems of getting https to https reverse proxy working and having all the css and images flow through as well.

The site is accessed using https://www.photowalktheworld.com which uses external facing DNS (Hover.com) and LetsEncrypt for SSL certificates.

This hits an NGINX reverse proxy (with some firewalls, double nat and other systems not listed here). Which forwards the traffic to my self hosted Chevereto Server which runs on top of Nginx which is listening on port 443 using a locally bound self served certificate. (so internally the server runs on SSL as well.)

The Chevereto server needs a DB to back out to, and I  have a separate MariaDB server which Chevereto uses to store data.

This post I'll show my configs (IP's changed to protect the innocent) and how I set this up.

DISCLAIMER

Sure, pick holes, its what the internet does, I'm putting this up here because it might help someone. I can't spell, my grammar is terrible and I may not have made the perfect setup like you. Just remember. Not everyone is as perfect as you, and as such this is how we learn..

Before you start

You will need a public DNS entry setup pointing to a public IP on the server you're going to set this up on. Mine is www.photowalktheworld.com. I'm not going to cover how to do that here.

External Facing Reverse Proxy

The External facing NginX reverse proxy has the routers, firewalls and DNS setup accordingly,

The configs are held on my system under /etc/nginx/sites-available/ and symlinked to /etc/nginx/sites-enabled

I've used certbot to generate the necessary LetsEncrypt certs

www.photowalktheworld.com.conf looks like this

server {

large_client_header_buffers 4 16k;
server_name www.photowalktheworld.com;
# The internal IP of the VM that hosts your Apache config
set $upstream 192.168.100.20;
 location / {
 proxy_pass_header Authorization;
 proxy_pass https://$upstream;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For
 $proxy_add_x_forwarded_for;
 proxy_http_version 1.1;
 proxy_set_header Connection “”;
 proxy_buffering off;
 client_max_body_size 20000;
 proxy_read_timeout 36000s;
}

listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.photowalktheworld.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.photowalktheworld.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = www.photowalktheworld.com) {
        return 301 https://$host$request_uri;
} # managed by Certbot


server_name www.photowalktheworld.com;
     listen 80;
     return 404; # managed by Certbot
}

This config both passes the html and more importantly the CSS and images from the internal server to the internet.

Internal NginX server

Hosting the Chevereto server on 192.168.100.20 prior to running. There is a good install guide to get PHP and NGINX running on Ubuntu 20.04 here

How To Install Linux, Nginx, MySQL, PHP (LEMP stack) on Ubuntu 20.04 | DigitalOcean
The LEMP software stack is a group of software that can be used to serve dynamic web pages and web applications written in PHP. This is an acronym that describes a Linux operating system, with an Nginx (pronounced like “Engine-X”) web server. The backend data is stored in a MySQL database, and dynam…

The /etc/nginx/nginx.conf looks as follows

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

 events {
    worker_connections 768;
    # multi_accept on;
 }

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;


    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

The recommended setting for me here was

 events {
    worker_connections 768;
    # multi_accept on;
 }

Which fixed some errors  shown in the /var/log/nginx/error.log

The default NGINX Server listens on Port 443

# Default server configuration
#
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    server_name _;

    root /var/www/html;
    index index.php index.html index.htm index.nginx-debian.html;

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;

# Context limits
client_max_body_size 20M;

# CORS header (avoids font rendering issues)
location ~* /.*\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js)$ {
  add_header Access-Control-Allow-Origin "*";
}

# Pretty URLs
 location / {
  index index.php;
  try_files $uri /index.php$is_args$query_string;
}

}

The SSL Config is held in the snippets lines

    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

snippets/self-signed.conf contain the self signed certificates created using SSL

How To Create a Self-Signed SSL Cert for Nginx in Ubuntu 18.04 | DigitalOcean
In this guide, we will show you how to set up a self-signed SSL certificate for use with an Nginx web server on an Ubuntu 18.04 server.
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

The general ss-params are contained in

snippets/ssl-params.conf

ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;ssl_ecdh_curve secp384r1; 
# Requires nginx >= 1.1.0
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;ssl_session_tickets off; 
# Requires nginx >= 1.5.9
ssl_stapling on; 
# Requires nginx >= 1.3.7
ssl_stapling_verify on; 
# Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

This should get NGINX working on the Chevereto server and you're ready to deploy the software.

Installing Chevereto

Upload the installer

  • to your target destination (usually the public_html folder).
  • Open your website at /installer.php and follow the process.

The installer will prompt with steps to install the software, after that it will download the software, extract it and it will post to /install the data previously provided.

Edit the app/settings.php

The settings for the the server are held in the aptly named settings.php

NOTE: When editing there is no trailing /?> at the end of the php file
vi app/settings.php
<?php $settings['db_host'] = '192.168.100.10';
$settings['db_port'] = '3306'; 
$settings['db_name'] = 'chevereto'; 
$settings['db_user'] = 'chevereto'; 
$settings['db_pass'] = 'yourpaswordhere';
$settings['db_table_prefix'] = 'chv_';
$settings['db_driver'] = 'mysql';
$settings['db_pdo_attrs'] = [];
$settings['debug_level'] = 1;
$settings['https'] = TRUE;
// Use X-Forwarded-For HTTP Header to Get Visitor's Real IP Address
if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
    $http_x_headers = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );

    $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}

I added the lines below

$settings['https'] = TRUE;
// Use X-Forwarded-For HTTP Header to Get Visitor's Real IP Address
if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
    $http_x_headers = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );

    $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
}

At this point I was able to login internally and externally