A while back, I was inspired by Thealaskalinuxuser's
article about how he set up his photo
sharing server at home. I experimented briefly with piwigo back when I read
that, but ended up stopping that project. When I returned to this topic, I
realized I just didn't want to deal with php. I applaud his stamina and
commitment, but I want something with fewer dependencies. Here is my solution.
So, here is my internal documentation that is my alternative to Google Photos.
Gallery solution for internal network
Overview
As part of my goals to run self-hosted services for myself and my family, I
intend to maintain a web gallery of photos and videos. This solution consists
of several parts.
- Tools that create symlink forests to the original image files, in a specific location
- Static site generator sigal
- Customized theme for sigal
- Customized sigal config for that theme
- Gallery id table
- SELinux rules
- CGI scripts for Apache httpd
Architecture
The solution runs on server1, the main file server for the internal network.
Tools that create symlink forests for the gallery source directories
Generate.sh
is what I used for the proof of concept. This needs to be rewritten in python,
and to handle files without exif data. My python implementation will show up
on this blog at a later date.
Static site generator
The sigal site generator is installed with pip3,
under local service account sigal
on server1. A special script,
/usr/local/bin/sigal.bin will generate the static pages for a site. To use
this script, pass a parameter of the source directory where the sigal.conf.py
exists.
/usr/local/bin/sigal.bin /mnt/public/www/example/images/.gallery
Sigal depends on ffmpeg for video thumbnailing and conversions. On CentOS
8, ffmpeg is in repository powertools. File
sigal.bin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 |
#!/bin/sh
# File: /usr/local/bin/sigal.bin
# Author: bgstack15@gmail.com
# Startdate: 2021-01-24
# Title: Run sigal static site generator
# Purpose: run sigal static site generator for provided path
# History:
# Usage:
# called by regen.cgi, or by hand
# Dependencies:
# 60_regen_gallery_sudo
# gallery.te
# service account "sigal" with `pip3 install --user sigal`
# Reverse dependencies:
# httpd conf
sigal_home=~sigal
test -z "${GALLERY_ID}" && export GALLERY_ID="${1}"
test -z "${GALLERY_ID}" && { echo "Pass to this script the gallery_id or directory path to a sigal.conf.py. Aborted." 1>&2 ; exit 1 ; }
if test -d "${GALLERY_ID}" ;
then
cd "${GALLERY_ID}"
else
if test -e /etc/gallery-cgi.conf ;
then
. /etc/gallery-cgi.conf
else
# no gallery_id listing exists.
echo "No gallery_id table exists. Aborted." 1>&2 ; exit 1
fi
fi
if test "${GALLERY_ID}" = "init" ;
then
sudo su sigal -s /bin/bash -c "${sigal_home}/.local/bin/sigal init"
else
eval cd \"\${"${GALLERY_ID}"}\"
sudo su sigal -s /bin/bash -c "${sigal_home}/.local/bin/sigal build"
fi
|
Customized theme for sigal
Use theme bgstack15-gallery-theme , in any location. You just need to put
its full path as the value of the theme in a sigal.conf.py for a gallery. This
is a fork of the default, included
colorbox
theme. The full theme is available in this project directory, as well as a
diff of it to the original as of sigal version 2.1.1. The main changes are
adding extra metadata handlers and link logic for the custom links related to
editing metadata.
Customized sigal config for that theme
When you run sigal init in a directory, it generates a default config you
can modify. The example theme, and this whole solution, depends on adding a
number of settings. A summary of the specific options is here, but the full
example file is in this project directory.
source = '/var/www/gallery/.my2018'
destination = '/var/www/gallery/my2018'
use_orig = True
edit_cgi_script = "/cgi-bin/gallery/edit.cgi" # web path to edit.cgi
edit_enabled = False
edit_password = "makeupapassword"
edit_string = '[edit]' # text of link to edit metadata
toggle_enable_string = "Enable editing"
toggle_disable_string = "Disable editing"
toggle_link = "/cgi-bin/gallery/toggle-editing.cgi" # web path to toggle-editing.cgi
toggle_editing = [
(False, 'Enable editing'),
(True, 'Disable editing')
]
gallery_id = "example_images"
# A list of links (tuples (title, URL))
# links = [('Example link', 'http://example.org'),
# ('Another link', 'http://example.org')]
links = [
('Regenerate pages', '/cgi-bin/gallery/regen.cgi?id=' + gallery_id)
]
The gallery_id
is very important, because the cgi scripts and theme rely on
it.
Gallery id table
File /etc/gallery-cgi.conf contains a list of gallery_id translations
to directories with sigal.conf.py rules.
example_images=/mnt/public/www/example/images/.gallery
SELinux rules
The reference system, server1, runs SELinux. A custom selinux module is needed
to allow all the operations that are a part of this gallery solution, which
include the following. File gallery.te can be installed as an enabled
selinux module.
sudo checkmodule -M -m -o gallery.mod gallery.te && sudo semodule_package -o gallery.pp -m gallery.mod && sudo semodule -i gallery.pp
File
gallery.te:
# Last modified 2021-01-30
module gallery 1.0;
require {
type faillog_t;
type security_t;
type httpd_config_t;
type init_t;
type sssd_t;
type mnt_t;
type lastlog_t;
type systemd_logind_sessions_t;
type initrc_var_run_t;
type tmpfs_t;
type gconf_home_t;
type chkpwd_t;
type systemd_logind_t;
type unconfined_t;
type shadow_t;
type httpd_sys_script_t;
type sssd_selinux_manager_t;
type sssd_conf_t;
type var_t;
type httpd_t;
class capability { audit_write dac_read_search net_admin setgid setuid sys_resource };
class process { noatsecure rlimitinh setrlimit siginh };
class netlink_audit_socket { create nlmsg_relay read write };
class netlink_selinux_socket { bind create };
class passwd rootok;
class dir { add_name read remove_name search write };
class file { create execute execute_no_trans setattr getattr link lock map open read unlink write ioctl };
class dbus send_msg;
class fifo_file write;
class security compute_av;
class lnk_file read;
class filesystem getattr;
class process setfscreate;
}
#============= httpd_sys_script_t ==============
allow httpd_sys_script_t faillog_t:file { open read };
allow httpd_sys_script_t var_t:file { create ioctl setattr unlink write };
allow httpd_sys_script_t var_t:dir { read add_name remove_name write };
#!!!! This avc can be allowed using the boolean 'domain_can_mmap_files'
allow httpd_sys_script_t gconf_home_t:file map;
allow httpd_sys_script_t gconf_home_t:file { execute execute_no_trans };
allow httpd_sys_script_t httpd_config_t:dir search;
allow httpd_sys_script_t initrc_var_run_t:file { lock open read };
allow httpd_sys_script_t lastlog_t:file { open read write };
allow httpd_sys_script_t mnt_t:lnk_file read;
allow httpd_sys_script_t security_t:dir read;
allow httpd_sys_script_t security_t:file { getattr open read write };
allow httpd_sys_script_t security_t:security compute_av;
allow httpd_sys_script_t self:capability { audit_write dac_read_search net_admin setgid setuid sys_resource };
allow httpd_sys_script_t self:netlink_audit_socket { create nlmsg_relay read write };
allow httpd_sys_script_t self:netlink_selinux_socket { bind create };
allow httpd_sys_script_t self:passwd rootok;
allow httpd_sys_script_t self:process setrlimit;
allow httpd_sys_script_t shadow_t:file { getattr open read };
allow httpd_sys_script_t sssd_conf_t:dir search;
allow httpd_sys_script_t sssd_conf_t:file { getattr open read };
allow httpd_sys_script_t systemd_logind_sessions_t:fifo_file write;
allow httpd_sys_script_t systemd_logind_t:dbus send_msg;
allow httpd_sys_script_t tmpfs_t:dir { add_name remove_name write };
#!!!! This avc can be allowed using the boolean 'domain_can_mmap_files'
allow httpd_sys_script_t tmpfs_t:file map;
allow httpd_sys_script_t tmpfs_t:file { create getattr link open read unlink write };
allow httpd_sys_script_t tmpfs_t:filesystem getattr;
allow httpd_sys_script_t self:process setfscreate;
#============= init_t ==============
allow init_t chkpwd_t:process siginh;
allow init_t unconfined_t:process siginh;
#============= sssd_t ==============
allow sssd_t sssd_selinux_manager_t:process { noatsecure rlimitinh siginh };
#============= systemd_logind_t ==============
allow systemd_logind_t httpd_sys_script_t:dbus send_msg;
#============= httpd_t ==============
allow httpd_t var_t:file { getattr map open read };
Sudo rules
For apache httpd to be able to run the sigal.bin, set up sudoers rules. File
60_regen_gallery_sudo adds the permission necessary.
# file: /etc/sudoers.d/60_regen_gallery_sudo
# Reference: server4:/etc/sudoers.d/60_starbound_sudo
apache ALL=(root) NOPASSWD: /usr/local/bin/sigal.bin *
CGI scripts for Apache httpd
The main focus of the gallery project is the ability to edit metadata from the
web view. While sigal is great for developers, some users might only care
about editing metadata from where they are actually viewing the media.
-
edit.cgi is called from the custom theme's "edit" links, and includes the form for making changes to media metadata.
-
apply.cgi actually makes the changes, and is called from the edit.cgi form.
-
regen.cgi invokes sigal.bin which re-runs sigal.
-
toggle-editing.cgi enables or disables editing. Enabling requires a password.
These can be placed anywhere you have enabled CGI for httpd, but the canonical
location is /var/www/cgi-bin/gallery/.
Operations
I anticipate that more work is needed on an ongoing basis. Here are some
processes that can be used.
Make a new gallery
To establish a new gallery, change directory to the source directory for the
gallery and run command
sigal.bin init
Which generates the basic sigal.conf.py. Add the pertinent variables,
described in section "Customized sigal config for that theme" above.
Run sigal from command line
While the web links for "regen.cgi" are great for when you are viewing the
web, you can also run the sigal.bin from the cli. You need to include a path
to the directory that holds a sigal.conf.py, or else a gallery_id from
/etc/gallery-cgi.conf.
sigal.bin example_images
Make metadata changes directly on filesystem
You can of course, as designed by the author of sigal, go edit any
${IMAGENAME%%.jpg}.md file with the relevant fields. See references 1 and
2 for the available fields. File index.md will be the metadata for the
directory itself.
History
In 2020, I installed piwigo on a dev system. I didn't
want to deal with php, so I dropped it. In January 2021, I started listing
various options for self-hosted galleries. Read heading [Related Files] for
those. Criteria I assembled includes
- Metadata: description, date, comments
Related Files
These files are important to this gallery project. Check them all out at my
gitlab space.
- /usr/local/bin/sigal.bin
- /var/www/cgi-bin/apply.cgi
- /var/www/cgi-bin/edit.cgi
- /var/www/cgi-bin/regen.cgi
- /var/www/cgi-bin/toggle-editing.cgi
- gallery.te
- /etc/sudoers.d/60_regen_gallery_sudo
- /etc/gallery-cgi.conf
- sigal.conf.py
- bgstack15-gallery-theme/
Alternatives
Ones I considered without trying
Ones I listed as tolerable, but not focused on what I need.
References
Weblinks
- http://sigal.saimon.org/en/latest/album_information.html
- http://sigal.saimon.org/en/latest/image_information.html
-
Home photo server, part 2: Apache, phpAlbum, and Piwigo | thealaskalinuxuser Thealaskalinuxuser's guide to a home photo server with piwigo