From a2b3f9b5b97a4ab2258b8f0b62fe828c74f8c6b1 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Tue, 12 Sep 2023 13:38:35 -0500 Subject: [PATCH] jellyfin: Deploy Jellyfin media server Jellyfin is a multimedia library manager. Clients can browse and stream music, movies, and TV shows from the server and play them locally (including in the browser). --- hosts | 3 + jellyfin.yml | 5 ++ roles/jellyfin/defaults/main.yml | 13 +++ roles/jellyfin/handlers/main.yml | 9 +++ roles/jellyfin/tasks/deploy.yml | 79 +++++++++++++++++++ roles/jellyfin/tasks/httpd-proxy.yml | 19 +++++ roles/jellyfin/tasks/install.yml | 12 +++ roles/jellyfin/tasks/main.yml | 9 +++ .../jellyfin/templates/jellyfin.container.j2 | 39 +++++++++ roles/jellyfin/templates/jellyfin.env.j2 | 1 + .../jellyfin/templates/jellyfin.httpd.conf.j2 | 27 +++++++ 11 files changed, 216 insertions(+) create mode 100644 jellyfin.yml create mode 100644 roles/jellyfin/defaults/main.yml create mode 100644 roles/jellyfin/handlers/main.yml create mode 100644 roles/jellyfin/tasks/deploy.yml create mode 100644 roles/jellyfin/tasks/httpd-proxy.yml create mode 100644 roles/jellyfin/tasks/install.yml create mode 100644 roles/jellyfin/tasks/main.yml create mode 100644 roles/jellyfin/templates/jellyfin.container.j2 create mode 100644 roles/jellyfin/templates/jellyfin.env.j2 create mode 100644 roles/jellyfin/templates/jellyfin.httpd.conf.j2 diff --git a/hosts b/hosts index 0e2104f..2f1afcb 100644 --- a/hosts +++ b/hosts @@ -69,6 +69,9 @@ logs0.pyrocufflink.blue [home-assistant] +[jellyfin] +file0.pyrocufflink.blue + [jenkins-slave] [journal2ntfy:children] diff --git a/jellyfin.yml b/jellyfin.yml new file mode 100644 index 0000000..c8f80d6 --- /dev/null +++ b/jellyfin.yml @@ -0,0 +1,5 @@ +- hosts: jellyfin + roles: + - role: apache + tags: apache + - jellyfin diff --git a/roles/jellyfin/defaults/main.yml b/roles/jellyfin/defaults/main.yml new file mode 100644 index 0000000..737e2ae --- /dev/null +++ b/roles/jellyfin/defaults/main.yml @@ -0,0 +1,13 @@ +jellyfin_version: latest +jellyfin_container_image: docker.io/jellyfin/jellyfin +jellyfin_media_dirs: +- /srv/cifs/Music +- /srv/cifs/Movies +- /srv/cifs/TV Shows +jellyfin_server_name: jellyfin.pyrocufflink.blue +jellyfin_server_url: https://{{ jellyfin_server_name }} + +jellyfin_ssl_certificate: >- + {{ apache_ssl_certificate }} +jellyfin_ssl_certificate_key: >- + {{ apache_ssl_certificate_key }} diff --git a/roles/jellyfin/handlers/main.yml b/roles/jellyfin/handlers/main.yml new file mode 100644 index 0000000..b830b5f --- /dev/null +++ b/roles/jellyfin/handlers/main.yml @@ -0,0 +1,9 @@ +- name: reload systemd + systemd: + daemon_reload: true + +- name: restart jellyfin + systemd: + name: jellyfin + state: restarted + diff --git a/roles/jellyfin/tasks/deploy.yml b/roles/jellyfin/tasks/deploy.yml new file mode 100644 index 0000000..45031a3 --- /dev/null +++ b/roles/jellyfin/tasks/deploy.yml @@ -0,0 +1,79 @@ +- name: ensure jellyfin group exists + group: + name: jellyfin + gid: 201 + system: true + state: present + tags: + - user + - group +- name: ensure jellyfin user exists + user: + name: jellyfin + uid: 201 + group: jellyfin + system: true + home: / + createhome: false + state: present + tags: + - user + +- name: ensure jellyfin cache directory exists + file: + path: /var/cache/jellyfin + owner: jellyfin + group: jellyfin + mode: u=rwx,go= + state: directory + tags: + - datadir +- name: ensure jellyfin data directory exists + file: + path: /var/lib/jellyfin + owner: jellyfin + group: jellyfin + mode: u=rwx,og=rx + state: directory + tags: + - datadir + +- name: ensure jellyfin environment is configured + template: + src: jellyfin.env.j2 + dest: /etc/sysconfig/jellyfin + owner: root + group: root + mode: u=rw,go= + tags: + - config + +- name: ensure jellyfin.container systemd unit exists + template: + src: jellyfin.container.j2 + dest: /etc/containers/systemd/jellyfin.container + owner: root + group: root + mode: u=rw,go=r + notify: + - reload systemd + - restart jellyfin + tags: + - systemd + - container + +- name: flush handlers + meta: flush_handlers + +- name: ensure jellyfin starts at boot + systemd: + name: jellyfin + enabled: true + tags: + - service +- name: ensure jellyfin is running + systemd: + name: jellyfin + state: started + tags: + - service diff --git a/roles/jellyfin/tasks/httpd-proxy.yml b/roles/jellyfin/tasks/httpd-proxy.yml new file mode 100644 index 0000000..8f8a74a --- /dev/null +++ b/roles/jellyfin/tasks/httpd-proxy.yml @@ -0,0 +1,19 @@ +- name: ensure apache is configured to proxy for jellyfin + template: + src: jellyfin.httpd.conf.j2 + dest: /etc/httpd/conf.d/jellyfin.conf + owner: root + group: root + mode: u=rw,go=r + notify: + - reload httpd + tags: + - apache + +- name: ensure selinux is configured for apache reverse proxy + seboolean: + name: httpd_can_network_connect + state: true + persistent: true + tags: + - selinux diff --git a/roles/jellyfin/tasks/install.yml b/roles/jellyfin/tasks/install.yml new file mode 100644 index 0000000..16632c8 --- /dev/null +++ b/roles/jellyfin/tasks/install.yml @@ -0,0 +1,12 @@ +- name: ensure podman is installed + package: + name: + - container-selinux + - podman + state: present + +- name: ensure jellyfin container image is present + podman_image: + name: '{{ jellyfin_container_image }}:{{ jellyfin_version }}' + state: present + diff --git a/roles/jellyfin/tasks/main.yml b/roles/jellyfin/tasks/main.yml new file mode 100644 index 0000000..2d0d063 --- /dev/null +++ b/roles/jellyfin/tasks/main.yml @@ -0,0 +1,9 @@ +- block: + - import_tasks: install.yml + tags: + - install + - import_tasks: deploy.yml + - import_tasks: httpd-proxy.yml + tags: + - jellyfin + diff --git a/roles/jellyfin/templates/jellyfin.container.j2 b/roles/jellyfin/templates/jellyfin.container.j2 new file mode 100644 index 0000000..5cd45aa --- /dev/null +++ b/roles/jellyfin/templates/jellyfin.container.j2 @@ -0,0 +1,39 @@ +[Unit] +Description=Jellyfin Media Server +Wants=network.target +After=network.target + +[Container] +Image={{ jellyfin_container_image }}:{{ jellyfin_version }} +#UserNS=keep-id +User=201 +Group=201 +EnvironmentFile=/etc/sysconfig/jellyfin +Volume=/var/lib/jellyfin:/config:rw,z +Volume=/var/cache/jellyfin:/cache:rw,z +{% for path in jellyfin_media_dirs %} +Volume={{ path }}:/media/{{ path | basename }}:ro +{% endfor %} +Network=host +NoNewPrivileges=yes + +[Service] +#MemoryDenyWriteExecute=yes +PrivateTmp=yes +ProtectClock=yes +ProtectHome=yes +ProtectKernelLogs=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectProc=invisible +ProtectSystem=strict +ReadWritePaths=/var/lib/jellyfin +ReadWritePaths=/var/lib/containers/storage +ReadWritePaths=/var/cache/jellyfin +RestrictRealtime=yes +RestrictSUIDSGID=yes +SuccessExitStatus=0 143 +UMask=0077 + +[Install] +WantedBy=multi-user.target diff --git a/roles/jellyfin/templates/jellyfin.env.j2 b/roles/jellyfin/templates/jellyfin.env.j2 new file mode 100644 index 0000000..5b19a4e --- /dev/null +++ b/roles/jellyfin/templates/jellyfin.env.j2 @@ -0,0 +1 @@ +JELLYFIN_PublishedServerUrl={{ jellyfin_server_url }} diff --git a/roles/jellyfin/templates/jellyfin.httpd.conf.j2 b/roles/jellyfin/templates/jellyfin.httpd.conf.j2 new file mode 100644 index 0000000..af6cb97 --- /dev/null +++ b/roles/jellyfin/templates/jellyfin.httpd.conf.j2 @@ -0,0 +1,27 @@ + + ServerName {{ jellyfin_server_name }} + + RewriteEngine On + RewriteCond %{HTTPS} !on + RewriteRule /.* https://%{SERVER_NAME}$0 [R=301,L] + + + + ServerName {{ jellyfin_server_name }} + + SSLCertificateFile {{ jellyfin_ssl_certificate }} + SSLCertificateKeyFile {{ jellyfin_ssl_certificate_key }} + SSLCertificateChainFile {{ jellyfin_ssl_certificate }} + + ProxyPreserveHost On + ProxyRequests Off + + RewriteEngine On + RewriteCond %{HTTP:Upgrade} =websocket [NC] + RewriteRule /(.*) ws://localhost:8096/$1 [P,L] + RewriteRule /(.*) http://localhost:8096/$1 [P,L] + ProxyPassReverse / http://localhost:8096/ + + Header always set \ + Strict-Transport-Security "max-age=63072000; includeSubDomains" +