feat(linkding): Add linkding stack

Bookmarking software similar to shaarli but a bit more featureful. And
not written in php, thankfully.
This commit is contained in:
Marty Oehme 2025-03-07 21:42:45 +01:00
parent 83613f6d86
commit aa5ada96c8
Signed by: Marty
GPG key ID: 4E535BC19C61886E
8 changed files with 200 additions and 0 deletions

View file

@ -0,0 +1,19 @@
---
linkding_version: latest-plus # plus contains self-archiving possibilities with singlefile
linkding_upstream_file_dir: "{{ docker_stack_files_dir }}/{{ stack_name }}"
linkding_use_https: true
linkding_autoupdate: true
# the subdomain link linkding will be reachable under
subdomain_alias: ld
# initial superuser creation
linkding_username: linkdinger
linkding_password: linkdingerpass123
# should we back up the data?
linkding_backup_enable: true
linkding_backup_cron: 0 45 3 * * *

View file

@ -0,0 +1,52 @@
## Register reverse proxy
- name: Ensure upstream directory exists
ansible.builtin.file:
path: "{{ linkding_upstream_file_dir }}"
state: directory
mode: "0755"
become: true
listen: "update linkding upstream"
- name: Update upstream template
ansible.builtin.template:
src: upstream.json.j2
dest: "{{ linkding_upstream_file_dir }}/upstream.json"
become: true
listen: "update linkding upstream"
# figure out if upstream id exists
- name: check {{ stack_name }} upstream
community.docker.docker_container_exec:
container: "{{ caddy_container_id }}"
command: >
curl localhost:2019/id/{{ stack_name }}_upstream/
changed_when: False
register: result
become: true
listen: "update linkding upstream"
# upstream already exists, patch it
- name: remove old {{ stack_name }} upstream
community.docker.docker_container_exec:
container: "{{ caddy_container_id }}"
command: >
curl -X DELETE localhost:2019/id/{{ stack_name }}_upstream/
become: true
when: (result.stdout | from_json)['error'] is not defined
listen: "update linkding upstream"
# upstream has to be created
- name: add {{ stack_name }} upstream
community.docker.docker_container_exec:
container: "{{ caddy_container_id }}"
command: >
curl -X POST -H "Content-Type: application/json" -d @{{ linkding_upstream_file_dir }}/upstream.json localhost:2019/config/apps/http/servers/{{ (linkding_use_https == True) | ternary(caddy_https_server_name, caddy_http_server_name) }}/routes/0/
become: true
listen: "update linkding upstream"
- name: Ensure upstream directory is gone again
ansible.builtin.file:
path: "{{ linkding_upstream_file_dir }}"
state: absent
become: true
listen: "update linkding upstream"

View file

@ -0,0 +1,11 @@
---
galaxy_info:
author: Marty Oehme
description: Installs linkding as a docker stack service
license: GPL-3.0-only
min_ansible_version: "2.9"
galaxy_tags: []
dependencies:
- docker-swarm
- caddy_id

View file

@ -0,0 +1,23 @@
---
## install linkding container
- name: Check upstream status
community.docker.docker_container_exec:
container: "{{ caddy_container_id }}"
command: >
curl localhost:2019/id/{{ stack_name }}_upstream/
register: result
changed_when: (result.stdout | from_json) != (lookup('template', 'upstream.json.j2') | from_yaml)
become: true
notify: "update linkding upstream"
- name: Deploy linkding to swarm
community.general.docker_stack:
name: "{{ stack_name }}"
state: present
prune: yes
compose:
- "{{ stack_compose }}"
become: true
tags:
- docker-swarm
notify: "update linkding upstream"

View file

@ -0,0 +1,46 @@
services:
app:
image: "{{ stack_image }}:{{ linkding_version }}"
healthcheck:
test: ["CMD", "curl", "--fail", "http://127.0.0.1:9090/health"]
interval: 1m
timeout: 10s
retries: 3
start_period: 1m
networks:
- "{{ docker_swarm_public_network_name }}"
volumes:
- data:/etc/linkding/data
environment:
- "LD_SUPERUSER_NAME={{ linkding_username }}"
- "LD_SUPERUSER_PASSWORD={{ linkding_password }}"
{% if linkding_autoupdate is defined and linkding_autoupdate %}
deploy:
labels:
- shepherd.autoupdate=true
{% endif %}
{% if backup_enable is not undefined and not false and linkding_backup_enable is not undefined and not false %}
backup:
image: mazzolino/restic
environment:
- "TZ={{ restic_timezone }}"
# go-cron starts w seconds
- "BACKUP_CRON={{ linkding_backup_cron }}"
- "RESTIC_REPOSITORY={{ restic_repo }}"
- "AWS_ACCESS_KEY_ID={{ restic_s3_key }}"
- "AWS_SECRET_ACCESS_KEY={{ restic_s3_secret }}"
- "RESTIC_PASSWORD={{ restic_pass }}"
- "RESTIC_BACKUP_TAGS=linkding"
- "RESTIC_BACKUP_SOURCES=/volumes"
volumes:
- data:/volumes/linkding_data:ro
{% endif %}
volumes:
data:
networks:
"{{ docker_swarm_public_network_name }}":
external: true

View file

@ -0,0 +1,38 @@
{
"@id": "{{ stack_name }}_upstream",
{% if server_domain is not undefined and not none %}
"match": [
{
"host": [
{% if subdomain_alias is not undefined and not none %}
"{{ subdomain_alias }}.{{ server_domain }}"
{% else %}
"{{ stack_name }}.{{ server_domain }}"
{% endif %}
]
}
],
{% else %}
"match": [
{
"path": [
{% if subdomain_alias is not undefined and not none %}
"/{{ subdomain_alias }}*"
{% else %}
"/{{ stack_name }}*"
{% endif %}
]
}
],
{% endif %}
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "{{ stack_name }}_app:80"
}
]
}
]
}

View file

@ -0,0 +1,6 @@
---
stack_name: linkding
stack_image: "sissbruecker/linkding"
stack_compose: "{{ lookup('template', 'docker-stack.yml.j2') | from_yaml }}"

View file

@ -76,6 +76,11 @@
role: shaarli
tags: shaarli
- name: Install linkding
import_role:
role: linkding
tags: linkding
- name: Install landingpage
import_role:
role: landingpage