feat(deluge): added role to install deluge and deluge web

This commit is contained in:
NaeiKinDus 2025-03-24 00:00:00 +00:00
parent bef258cfec
commit 1c625d2d84
Signed by: WoodSmellParticle
GPG key ID: 8E52ADFF7CA8AE56
19 changed files with 553 additions and 1 deletions

View file

@ -22,7 +22,7 @@
become: true
changed_when: false
ansible.builtin.reboot:
reboot_timeout: 10
reboot_timeout: 30
tasks:
- include_vars: ../../../../../../inventory/group_vars/all/vars.yml
- include_vars: ../../../../../../inventory/group_vars/all/vault.yml
@ -78,3 +78,7 @@
ansible.builtin.include_role:
name: nullified.infrastructure.gaming
tasks_from: main.yml
- name: Testing deluge role
ansible.builtin.include_role:
name: nullified.infrastructure.deluge
tasks_from: main.yml

View file

@ -1,5 +1,6 @@
custom_base_user_account: 'vagrant'
security_firewall_mangle_drop_privatenets: false
security_firewall_filter_policy_output: accept
security_configure_resolve_conf: true
global_ip_dualstack: false
external_provisioner_source_ips:

View file

@ -0,0 +1,29 @@
Role Name
=========
@todo
Requirements
------------
@todo
Role Variables
--------------
@todo
Dependencies
------------
@todo
Example Playbook
----------------
@todo
License
-------
[MIT](https://opensource.org/license/mit)

View file

@ -0,0 +1,19 @@
---
deluge_git_branch: "develop"
deluge_git_dir: "/srv/git/deluge.git"
deluge_install_dir: "/opt/deluge"
deluge_git_version: "HEAD"
deluge_user: "deluge"
deluge_group: "deluge"
deluge_download_dir: "/opt/deluge/Downloads"
deluge_completed_dir: "/opt/deluge/Completed"
deluge_plugins_dir: "/opt/deluge/.config/deluge/plugins"
deluge_torrentfiles_dir: "/opt/deluge/Torrents"
deluge_web_port: 8112
deluge_web_password: deluge
deluge_web_password_salt:
deluge_daemon_control_port: 58846
deluge_daemon_incoming_port: 6881
deluge_daemon_outgoing_port_lo: 6889
deluge_daemon_outgoing_port_hi: 6899
deluge_web_expose_client: false

View file

@ -0,0 +1,23 @@
---
- name: restart deluged service
become: true
ansible.builtin.systemd:
name: deluged.service
enabled: true
state: restarted
daemon_reload: true
- name: restart deluge-web service
become: true
ansible.builtin.systemd:
name: deluge-web.service
enabled: true
state: restarted
daemon_reload: true
- name: restart firewall
become: true
ansible.builtin.systemd:
name: nftables.service
enabled: true
state: restarted

View file

@ -0,0 +1,13 @@
---
galaxy_info:
author: Florian L.
namespace: nullified
description:
license: MIT
min_ansible_version: 2.15
platforms:
- name: Debian
versions:
- bookworm
galaxy_tags: []
dependencies: []

View file

@ -0,0 +1,28 @@
---
- name: find systemd unit directory
become: true
ansible.builtin.command: pkg-config systemd --variable=systemdsystemunitdir
changed_when: false
register: systemd_unit_directory_cmd
- name: find systemd version
become: true
ansible.builtin.shell: >
systemctl --version | awk '{if($1=="systemd" && $2~"^[0-9]+$"){print $2}}'
changed_when: false
register: systemd_version_cmd
- name: set facts
ansible.builtin.set_fact:
systemd_unit_directory: "{{ systemd_unit_directory_cmd.stdout }}"
systemd_version: "{{ systemd_version_cmd.stdout | int }}"
deluge_web_password_salt: "{{ deluge_web_password_salt | default(lookup('ansible.builtin.password', '/dev/null', chars=['ascii_letters', 'digits'], length=40), true) }}"
- name: compute sha1 digest
ansible.builtin.shell: >
echo -n "${DELUGED_PASSWD_SALT}${DELUGED_PASSWD}" | openssl dgst -sha1 -r | cut -d ' ' -f 1
register: deluge_pwd_sha1
changed_when: false
environment:
DELUGED_PASSWD: '{{ deluge_web_password }}'
DELUGED_PASSWD_SALT: '{{ deluge_web_password_salt }}'
- name: set facts
ansible.builtin.set_fact:
deluge_web_password_hash: "{{ deluge_pwd_sha1.stdout }}"

View file

@ -0,0 +1,160 @@
---
- name: install dependencies
become: true
ansible.builtin.apt:
update_cache: yes
force_apt_get: true
state: present
cache_valid_time: 3600
pkg:
- closure-compiler
- git
- intltool
- openssl
- pkg-config
- python3-dbus
- python3-geoip
- python3-libtorrent
- python3-pip
- python3-virtualenv
- name: gather facts
ansible.builtin.include_tasks: gather_facts.yml
- name: create service group
become: true
ansible.builtin.group:
name: '{{ deluge_group }}'
system: true
state: present
- name: create service user
become: true
ansible.builtin.user:
name: '{{ deluge_user }}'
group: '{{ deluge_group }}'
shell: '/usr/sbin/nologin'
home: '{{ deluge_install_dir }}'
create_home: true
system: true
state: present
- name: mark repository as safe
become: true
ansible.builtin.shell: >
git config --global --get safe.directory {{ deluge_git_dir }} ||
git config --global --add safe.directory {{ deluge_git_dir }}
- name: clone repository
become: true
ansible.builtin.git:
repo: '{{ deluge_git_repository }}'
dest: '{{ deluge_git_dir }}'
single_branch: true
version: '{{ deluge_git_version }}'
- name: setup virtualenv
become: true
ansible.builtin.pip:
requirements: '{{ deluge_git_dir }}/requirements.txt'
virtualenv: '{{ deluge_git_dir }}/.venv'
virtualenv_site_packages: true
- name: build project
become: true
command: >-
.venv/bin/python setup.py bdist_wheel
args:
chdir: '{{ deluge_git_dir }}'
- name: install generated wheel
become: true
ansible.builtin.shell: >-
.venv/bin/pip install dist/*.whl --no-index --find-links=.
args:
chdir: '{{ deluge_git_dir }}'
- name: set ownership
become: true
ansible.builtin.file:
path: '{{ deluge_git_dir }}'
owner: '{{ deluge_user }}'
group: '{{ deluge_group }}'
mode: 'u=rwX,g=rX,o='
recurse: yes
follow: false
- name: install man page
become: true
ansible.builtin.copy:
src: '{{ deluge_git_dir }}/docs/man/deluged.1'
remote_src: true
dest: '/usr/local/share/man/man1/'
owner: root
group: root
mode: 'u=rwX,g=rX,o='
- name: install deluged unit files
become: true
ansible.builtin.template:
src: ../templates/systemd/deluged.service.j2
dest: '{{ systemd_unit_directory }}/deluged.service'
owner: root
group: root
mode: 'u=rwX,g=rX,o='
notify:
- 'deluge : restart deluged service'
- name: install systemd unit files
become: true
ansible.builtin.template:
src: ../templates/systemd/deluge-web.service.j2
dest: '{{ systemd_unit_directory }}/deluge-web.service'
owner: root
group: root
mode: 'u=rwX,g=rX,o='
notify:
- 'deluge : restart deluge-web service'
- name: create directories
become: true
ansible.builtin.file:
path: '{{ item }}'
owner: '{{ deluge_user }}'
group: '{{ deluge_group }}'
mode: 'u=rwX,g=rX,o='
state: directory
loop:
- '{{ deluge_download_dir }}'
- '{{ deluge_install_dir }}/.config/deluge'
- '{{ deluge_completed_dir }}'
- '{{ deluge_plugins_dir }}'
- '{{ deluge_torrentfiles_dir }}'
- name: 'install firewall ruleset'
become: true
ansible.builtin.template:
src: ../templates/nftables.d/deluge.nft.j2
dest: '/etc/nftables.d/deluge.nft'
owner: root
group: root
mode: 'u=rw,g=r,o='
notify:
- 'deluge : restart firewall'
- name: stop services
become: true
ansible.builtin.systemd:
name: '{{ item }}.service'
enabled: true
state: stopped
daemon_reload: true
loop:
- deluged
- deluge-web
- name: create basic configuration
become: true
ansible.builtin.template:
src: '../templates/{{ item }}.j2'
dest: '{{ deluge_install_dir }}/.config/deluge/{{ item }}'
owner: '{{ deluge_user }}'
group: '{{ deluge_group }}'
mode: 'u=rw,g=r,o='
loop:
- core.conf
- web.conf
- name: start services
become: true
ansible.builtin.systemd:
name: '{{ item }}.service'
enabled: true
state: started
daemon_reload: true
loop:
- deluged
- deluge-web

View file

@ -0,0 +1,95 @@
{
"file": 1,
"format": 1
}{
"add_paused": false,
"allow_remote": false,
"auto_manage_prefer_seeds": false,
"auto_managed": true,
"cache_expiry": 60,
"cache_size": 512,
"copy_torrent_file": false,
"daemon_port": {{ deluge_daemon_control_port }},
"del_copy_torrent_file": false,
"dht": false,
"dont_count_slow_torrents": false,
"download_location": "{{ deluge_download_dir }}",
"download_location_paths_list": [],
"enabled_plugins": [],
"enc_in_policy": 1,
"enc_level": 2,
"enc_out_policy": 1,
"geoip_db_location": "/usr/share/GeoIP/GeoIP.dat",
"ignore_limits_on_local_network": true,
"info_sent": 0.0,
"listen_interface": "",
"listen_ports": [
{{ deluge_daemon_incoming_port }},
{{ deluge_daemon_incoming_port }}
],
"listen_random_port": null,
"listen_reuse_port": true,
"listen_use_sys_port": false,
"lsd": false,
"max_active_downloading": 20,
"max_active_limit": 50,
"max_active_seeding": 50,
"max_connections_global": 200,
"max_connections_per_second": 20,
"max_connections_per_torrent": -1,
"max_download_speed": -1.0,
"max_download_speed_per_torrent": -1,
"max_half_open_connections": 50,
"max_upload_slots_global": 20,
"max_upload_slots_per_torrent": -1,
"max_upload_speed": -1.0,
"max_upload_speed_per_torrent": -1,
"move_completed": true,
"move_completed_path": "{{ deluge_completed_dir }}",
"move_completed_paths_list": [],
"natpmp": true,
"new_release_check": true,
"outgoing_interface": "",
"outgoing_ports": [
{{ deluge_daemon_outgoing_port_lo }},
{{ deluge_daemon_outgoing_port_hi }}
],
"path_chooser_accelerator_string": "Tab",
"path_chooser_auto_complete_enabled": true,
"path_chooser_max_popup_rows": 20,
"path_chooser_show_chooser_button_on_localhost": true,
"path_chooser_show_hidden_files": false,
"peer_tos": "0x00",
"plugins_location": "{{ deluge_plugins_dir }}",
"pre_allocate_storage": true,
"prioritize_first_last_pieces": false,
"proxy": {
"anonymous_mode": false,
"force_proxy": false,
"hostname": "",
"password": "",
"port": 8080,
"proxy_hostnames": true,
"proxy_peer_connections": true,
"proxy_tracker_connections": true,
"type": 0,
"username": ""
},
"queue_new_to_top": false,
"random_outgoing_ports": false,
"random_port": false,
"rate_limit_ip_overhead": true,
"remove_seed_at_ratio": false,
"seed_time_limit": -1,
"seed_time_ratio_limit": -1.0,
"send_info": false,
"sequential_download": false,
"share_ratio_limit": -1.0,
"shared": false,
"stop_seed_at_ratio": false,
"stop_seed_ratio": 2.0,
"super_seeding": false,
"torrentfiles_location": "{{ deluge_torrentfiles_dir }}",
"upnp": true,
"utpex": false
}

View file

@ -0,0 +1,24 @@
table inet filter {
chain input {
{% if deluge_web_expose_client %}
meta nfproto { ipv4, ipv6 } tcp dport {{ deluge_web_port }} accept
{% else %}
meta nfproto { ipv4, ipv6 } iifname "lo" tcp dport {{ deluge_web_port }} accept
{% endif %}
iifname "lo" tcp dport {{ deluge_daemon_control_port }} accept
meta l4proto { tcp, udp } th dport {{ deluge_daemon_incoming_port }} accept
meta l4proto { tcp, udp } th dport { {{ deluge_daemon_outgoing_port_lo }}-{{ deluge_daemon_outgoing_port_hi }} } accept
}
chain output {
{% if deluge_web_expose_client %}
meta nfproto { ipv4, ipv6 } tcp sport {{ deluge_web_port }} accept
{% else %}
meta nfproto { ipv4, ipv6 } oifname "lo" tcp sport {{ deluge_web_port }} accept
{% endif %}
meta l4proto { tcp, udp } th sport { {{ deluge_daemon_outgoing_port_lo }}-{{ deluge_daemon_outgoing_port_hi }} } accept
oifname "lo" tcp sport {{ deluge_daemon_control_port }} accept
udp dport { 1900, 5351 } accept
tcp dport 6969 accept
}
}

View file

@ -0,0 +1,53 @@
[Unit]
Description=Deluge Bittorrent Client Web Interface
Documentation=man:deluge-web
After=deluged.service
Wants=deluged.service
[Service]
User=deluge
Group=deluge
Type=simple
UMask=027
ExecStart={{ deluge_git_dir }}/.venv/bin/deluge-web -d
Restart=on-failure
RestartSec=3
# Security Hardening
PrivateTmp=true
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
{% if systemd_version | int >= 187 %}
NoNewPrivileges=true
SystemCallFilter=@system-service
{% endif %}
{%+ if systemd_version | int >= 209 %}SystemCallArchitectures=native{%- endif +%}
{% if systemd_version | int >= 214 %}
ProtectHome=true
ProtectSystem=true
{% endif %}
{% if systemd_version | int >= 231 %}
ReadOnlyPaths=/
ReadWritePaths={{ deluge_git_dir }} {{ deluge_install_dir }}
RestrictRealtime=true
{% endif %}
{% if systemd_version | int >= 232 %}
ProtectControlGroups=true
ProtectKernelModules=true
ProtectKernelTunables=true
RemoveIPC=true
{% endif %}
{% if systemd_version | int >= 233 %}
MountAPIVFS=true
RestrictNamespaces=ipc net mnt pid
{% endif %}
{%+ if systemd_version | int >= 235 %}LockPersonality=true{%- endif +%}
{% if systemd_version | int >= 242 %}
ProtectHostname=true
RestrictSUIDSGID=true
{% endif %}
{%+ if systemd_version | int >= 244 %}ProtectKernelLogs=true{%- endif +%}
{%+ if systemd_version | int >= 245 %}ProtectClock=true{%- endif +%}
{%+ if systemd_version | int >= 247 %}ProtectProc=invisible{%- endif +%}
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,54 @@
[Unit]
Description=Deluge Bittorrent Client Daemon
Documentation=man:deluged
After=network-online.target
[Service]
User=deluge
Group=deluge
Type=simple
UMask=007
ExecStart={{ deluge_git_dir }}/.venv/bin/deluged -d -L warning
Restart=on-failure
RestartSec=3
TimeoutStopSec=300
WorkingDirectory=~
# Security Hardening
PrivateTmp=true
CapabilityBoundingSet=CAP_SYS_RESOURCE
{% if systemd_version | int >= 187 %}
NoNewPrivileges=true
SystemCallFilter=@system-service
{% endif %}
{%+ if systemd_version | int >= 209 %}SystemCallArchitectures=native{%- endif +%}
{% if systemd_version | int >= 214 %}
ProtectHome=true
ProtectSystem=true
{% endif %}
{% if systemd_version | int >= 231 %}
ReadOnlyPaths=/
ReadWritePaths={{ deluge_git_dir }} {{ deluge_install_dir }}
RestrictRealtime=true
{% endif %}
{% if systemd_version | int >= 232 %}
ProtectControlGroups=true
ProtectKernelModules=true
ProtectKernelTunables=true
RemoveIPC=true
{% endif %}
{% if systemd_version | int >= 233 %}
MountAPIVFS=true
RestrictNamespaces=ipc net mnt pid
{% endif %}
{%+ if systemd_version | int >= 235 %}LockPersonality=true{%- endif +%}
{% if systemd_version | int >= 242 %}
ProtectHostname=true
RestrictSUIDSGID=true
{% endif %}
{%+ if systemd_version | int >= 244 %}ProtectKernelLogs=true{%- endif +%}
{%+ if systemd_version | int >= 245 %}ProtectClock=true{%- endif +%}
{%+ if systemd_version | int >= 247 %}ProtectProc=invisible{%- endif +%}
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,26 @@
{
"file": 2,
"format": 1
}{
"base": "/",
"cert": "ssl/daemon.cert",
"default_daemon": "",
"enabled_plugins": [
],
"first_login": false,
"https": false,
"interface": "{{ '0.0.0.0' if deluge_web_expose_client is truthy else '127.0.0.1' }}",
"language": "",
"pkey": "ssl/daemon.pkey",
"port": {{ deluge_web_port }},
"pwd_salt": "{{ deluge_web_password_salt }}",
"pwd_sha1": "{{ deluge_web_password_hash }}",
"session_timeout": 3600,
"sessions": {
},
"show_session_speed": true,
"show_sidebar": true,
"sidebar_multiple_filters": true,
"sidebar_show_zero": false,
"theme": "gray"
}

View file

@ -0,0 +1,2 @@
localhost

View file

@ -0,0 +1,5 @@
---
- hosts: localhost
remote_user: root
roles:
- test

View file

@ -0,0 +1,2 @@
---
deluge_git_repository: 'git://deluge-torrent.org/deluge.git'

View file

@ -4,3 +4,7 @@ ansible_user: "{{ vault_ssh_user }}"
nginx_extra_packages: [nginx-module-geoip, nginx-module-otel]
nginx_sites: "{{ vault_nginx_sites }}"
nginx_streams: "{{ vault_nginx_streams }}"
deluge_web_password: '{{ vault_deluge_web_password }}'
deluge_web_password_salt: '{{ vault_deluge_web_password_salt }}'
global_dns_udp_dns4: "{{ vault_global_dns_udp_dns4 }}"
global_dns_udp_dns6: "{{ vault_global_dns_udp_dns6 }}"

View file

@ -47,3 +47,13 @@
apply:
tags: [webserver]
tags: [webserver, webserver-config, webserver-sites, webserver-streams]
- name: setup deluge instances
hosts: external:&deluge
tasks:
- name: include deluge role
ansible.builtin.include_role:
name: nullified.infrastructure.deluge
apply:
tags: [deluge]
tags: [deluge]