Skip to content

Librephotos add #722

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions nas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@
tags:
- krusader

- role: librephotos
tags:
- librephotos

- role: lidarr
tags:
- lidarr
Expand Down
47 changes: 47 additions & 0 deletions roles/librephotos/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---

librephotos_enabled: false
librephotos_available_externally: false

# directories
librephotos_scan_directory: "{{ photos_root }}"
librephotos_data_directory: "{{ docker_home }}/librephotos/data"

# network
librephotos_port: "3003"
librephotos_hostname: "librephotos"

# specs
librephotos_memory: 4g

# docker
librephotos_container_name: librephotos
librephotos_image_version: latest
librephotos_image_name: reallibrephotos/librephotos
librephotos_proxy_image_name: nginx
librephotos_proxy_image_version: latest
librephotos_network_name: librephotos

# Number of workers, which take care of the request to the api. This setting can dramatically affect the ram usage.
# A positive integer generally in the 2-4 x $(NUM_CORES) range.
# You’ll want to vary this a bit to find the best for your particular workload.
# Each worker needs 800MB of RAM. Change at your own will. Default is 2.
librephotos_gunniWorkers: "2"

# You can set the database name. Did you know Libre Photos was forked from OwnPhotos?
librephotos_dbName: librephotos

# Here you can change the user name for the database.
librephotos_dbUser: docker

# The password used by the database.
librephotos_dbPass: AaAa1234

librephotos_shhhhKey: "abc123"
librephotos_adminEmail: "{{ ansible_nas_email }}"
librephotos_userName: "{{ ansible_nas_user }}"
librephotos_userPass: "librephotos_password"
librephotos_mapApiKey: ""
librephotos_skipPatterns: ""
librephotos_allowUpload : "false"
librephotos_heavyweight_process: "1"
11 changes: 11 additions & 0 deletions roles/librephotos/docs/librephotos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# LibrePhotos

Homepage: [https://docs.librephotos.com/](https://docs.librephotos.com/)

## Usage

Set `librephotos_enabled: true` in your `inventories/<your_inventory>/nas.yml` file.

The default user is `{{ ansible_nas_user }}` and its password is `librephotos_password`.

librephotos creates a database in `librephotos_config_directory`.
6 changes: 6 additions & 0 deletions roles/librephotos/molecule/default/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
provisioner:
inventory:
group_vars:
all:
hello_world_enabled: true
10 changes: 10 additions & 0 deletions roles/librephotos/molecule/default/side_effect.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
- name: Stop
hosts: all
become: true
tasks:
- name: "Include {{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }} role"
include_role:
name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}"
vars:
hello_world_enabled: false
20 changes: 20 additions & 0 deletions roles/librephotos/molecule/default/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
# This is an example playbook to execute Ansible tests.

- name: Verify
hosts: all
gather_facts: false
tasks:
- include_vars:
file: ../../defaults/main.yml

- name: Get container state
docker_container_info:
name: "{{ hello_world_container_name }}"
register: result

- name: Check Hello World is running
assert:
that:
- result.container['State']['Status'] == "running"
- result.container['State']['Restarting'] == false
20 changes: 20 additions & 0 deletions roles/librephotos/molecule/default/verify_stopped.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
# This is a Hello World playbook to execute Ansible tests.

- name: Verify
hosts: all
gather_facts: false
tasks:
- include_vars:
file: ../../defaults/main.yml

- name: Try and stop and remove Hello World
docker_container:
name: "{{ hello_world_container_name }}"
state: absent
register: result

- name: Check Hello World is stopped
assert:
that:
- not result.changed
123 changes: 123 additions & 0 deletions roles/librephotos/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
- name: LibrePhotos
block:
- name: Create LibrePhotos Directories
file:
path: "{{ item }}"
state: directory
with_items:
- "{{ librephotos_scan_directory }}"
- "{{ librephotos_data_directory }}"
- "{{ librephotos_data_directory }}/proxy"
when: (librephotos_enabled | default(False))

- name: Create Librephotos network
community.docker.docker_network:
name: "{{ librephotos_network_name }}"

- name: Template Librephotos Proxy Config
ansible.builtin.template:
src: nginx.conf
dest: "{{ librephotos_data_directory }}/proxy/"
register: proxy_config

- name: LibrePhotos Proxy Container
docker_container:
name: "{{ librephotos_container_name }}-proxy"
image: "{{ librephotos_proxy_image_name }}:{{ librephotos_proxy_image_version }}"
networks:
- name: "{{ librephotos_network_name }}"
pull: true
restart: "{{ proxy_config is changed }}"
volumes:
- "{{ librephotos_scan_directory }}:/data:rw"
- "{{ librephotos_data_directory }}/protected_media:/protected_media:rw"
- "{{ librephotos_data_directory }}/proxy/nginx.conf:/etc/nginx/nginx.conf"
ports:
- "{{ librephotos_port }}:80"
restart_policy: unless-stopped
labels:
traefik.enable: "{{ librephotos_available_externally | string }}"
traefik.http.routers.librephotos.rule: "Host(`{{ librephotos_hostname }}.{{ ansible_nas_domain }}`)"
traefik.http.routers.librephotos.tls.certresolver: "letsencrypt"
traefik.http.routers.librephotos.tls.domains[0].main: "{{ ansible_nas_domain }}"
traefik.http.routers.librephotos.tls.domains[0].sans: "*.{{ ansible_nas_domain }}"
traefik.http.services.librephotos.loadbalancer.server.port: "{{ librephotos_port }}"
when: (librephotos_enabled | default(False))

- name: LibrePhotos Database Container
docker_container:
name: "{{ librephotos_container_name }}-db"
image: postgres:13
networks:
- name: "{{ librephotos_network_name }}"
pull: true
volumes:
- "{{ librephotos_data_directory }}/db:/var/lib/postgresql/data"
restart_policy: unless-stopped
env:
POSTGRES_USER: "{{ librephotos_dbUser }}"
POSTGRES_PASSWORD: "{{ librephotos_dbPass }}"
POSTGRES_DB: "{{ librephotos_dbName }}"
command: postgres -c fsync=off -c synchronous_commit=off -c full_page_writes=off -c random_page_cost=1.0
# healthcheck:
# test: psql -U ${dbUser} -d ${dbName} -c "SELECT 1;"
# interval: 5s
# timeout: 5s
# retries: 5
when: (librephotos_enabled | default(False))

- name: LibrePhotos Frontend
docker_container:
name: "{{ librephotos_container_name }}-frontend"
image: "{{ librephotos_image_name }}-frontend:{{ librephotos_image_version }}"
networks:
- name: "{{ librephotos_network_name }}"
restart_policy: unless-stopped
when: (librephotos_enabled | default(False))

- name: LibrePhotos Backend
docker_container:
name: "{{ librephotos_container_name }}-backend"
image: "{{ librephotos_image_name }}:{{ librephotos_image_version }}"
networks:
- name: "{{ librephotos_network_name }}"
restart_policy: unless-stopped
memory: "{{ librephotos_memory }}"
volumes:
- "{{ librephotos_scan_directory }}:/data"
- "{{ librephotos_data_directory }}/protected_media:/protected_media"
- "{{ librephotos_data_directory }}/logs:/logs"
- "{{ librephotos_data_directory }}/cache:/root/.cache"
env:
SECRET_KEY: "{{ librephotos_shhhhKey }}"
BACKEND_HOST: "{{ librephotos_container_name }}-backend"
ADMIN_EMAIL: "{{ librephotos_adminEmail }}"
ADMIN_USERNAME: "{{ librephotos_userName }}"
ADMIN_PASSWORD: "{{ librephotos_userPass }}"
DB_BACKEND: postgresql
DB_NAME: "{{ librephotos_dbName }}"
DB_USER: "{{ librephotos_dbUser }}"
DB_PASS: "{{ librephotos_dbPass }}"
DB_HOST: "{{ librephotos_container_name }}-db"
DB_PORT: "5432"
MAPBOX_API_KEY: "{{ librephotos_mapApiKey }}"
WEB_CONCURRENCY: "{{ librephotos_gunniWorkers }}"
SKIP_PATTERNS: "{{ librephotos_skipPatterns }}"
ALLOW_UPLOAD: "{{ librephotos_allowUpload }}"
DEBUG: "0"
HEAVYWEIGHT_PROCESS: "{{ librephotos_heavyweight_process }}"
when: (librephotos_enabled | default(False))

- name: Stop LibrePhotos
block:
- name: Stop LibrePhotos Containers
docker_container:
name: "{{ librephotos_container_name }}-{{ item }}"
state: absent
with_items:
- proxy
- db
- frontend
- backend
when: (not librephotos_enabled)
70 changes: 70 additions & 0 deletions roles/librephotos/templates/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
user nginx;
worker_processes 1;

error_log /var/log/nginx/error.log debug;

events {
worker_connections 1024;
}

http {
server {
listen 80;

location / {
# React routes are entirely on the App side in the web browser
# Always proxy to root with the same page request when nginx 404s
error_page 404 /;
proxy_intercept_errors on;
proxy_set_header Host $host;
proxy_pass http://{{ librephotos_container_name }}-frontend:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Allow to download zip files directly. This has to go before the following rule
location ~ ^/api/downloads/(.*)$ {
root /;
try_files /protected_media/zip/$1.zip =404;
}
location ~ ^/(api|media)/ {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host {{ librephotos_container_name }}-backend;
include uwsgi_params;
proxy_pass http://{{ librephotos_container_name }}-backend:8001;
}
# needed for webpack-dev-server
location /ws {
proxy_pass http://{{ librephotos_container_name }}-frontend:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Django media
location /protected_media {
internal;
alias /protected_media/;
}

location /static/drf-yasg {
proxy_pass http://{{ librephotos_container_name }}-backend:8001;
}

location /data {
internal;
alias /data/;
}

# Original Photos
location /original {
internal;
alias /data/;
}
# Nextcloud Original Photos
location /nextcloud_original {
internal;
alias /data/nextcloud_media/;
}
}
}