El tema central será Jellyfin, pero se necesita tocar varios puntos primero.
La idea de usar miniDLNA se queda muy muy corta
|
Resulta que freeBSD
tiene algo muy potente, siendo nativo de el llamado jails (prisiones, cárcel) para contenerizar nuestras aplicaciones, muy parecido a docker
, pero más maduro, dando un método de contenerización lijera, a veces llamado virtualización a nivel de OS(Sistema operativo), un jail normalmente contiene un sistema operativo completo en una zona de usuario que corre sobre el Sistema FreeBSD.
Los jails, no tienen su propio kernel, sino, que corren en una porción del kernel del host, el host puede controlar el jail, por medio de ciertos comandos sin entrar en el jail, o correr procesos dentro del jail si se prefiere.
La cuenta root del jail puede controlar todo dentro del jail, pero no fuera de el, cada uno de ellos posee una dirección ip dedicada.
Procesos del Jail o JID
xigmanas: ~# jls (1)
JID IP Address Hostname Path
1 adguardhome /mnt/pool/extensions/bastille/jails/adguardhome/root
2 192.168.1.248 jdownloader /mnt/pool/extensions/bastille/jails/jdownloader/root
4 nextcloud /mnt/pool/extensions/bastille/jails/nextcloud/root
5 reverse-proxy /mnt/pool/extensions/bastille/jails/reverse-proxy/root
6 jellyfin /mnt/pool/extensions/bastille/jails/jellyfin/root
1 | Con el comando jls visualizamos nuestros jails, el JID es como un process ID, cada JID cambia una vez que el jail inicie. |
Usando Bastille
Bastille para administrar nuestros jails con simples comandos, este lo instale desde la interface del xigmanas, no me toco probar desde la consola, pero si fue necesario tener primero a OBI(one button installer). para instalarlo desde ese plugin.
Subcommands
La lista de comandos de bastille es un poco variada subcommands. |
Podemos instalar todo nuestros jails via web o por consola
Jails.conf, fstab
Cada Jail tiene 2 ficheros importantes, por ejemplo:
-
jail.conf
-
fstab
Más info al respecto jail-config |
Las rutas de ambos ficheros, estan el dataset donde esta bastille, en mi caso llamado pool
/mnt/pool/extensions/bastille/jails/jdownloader/jail.conf
/mnt/pool/extensions/bastille/jails/jdownloader/fstab
Si queremos entrar dentro de un jail usariamos el siguiente comando.
bastille console Jdownloader (1)
1 | comando que permite entrar al jail llamado Jdownloader |
Dirección ip del jail
Si queremos asignar una dirección ip a nuestro jail bien sea estatica o dinámica, nos vamos al etc/rc.conf
Donde tenemos la ruta siguiente de dicho fichero
/mnt/pool/extensions/bastille/jails/jellyfin-clone/root/etc/rc.conf
Una de las dos líneas se usara, estática o dinámica. |
syslogd_flags="-ss"
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
cron_flags="-J 60"
ifconfig_e0b_bastille4_name="vnet0"
ifconfig_vnet0="inet 192.168.1.247/24" (1)
#ifconfig_vnet0="SYNCDHCP" (2)
defaultrouter="192.168.1.1"
jellyfinserver_enable="TRUE"
jellyfinserver_user="jellyfin"
jellyfinserver_group="jellyfin"
1 | Se asigna a este jail una dirección ip estática dentro del pool DHCP de mi red local, con subnet /24 |
2 | Se usa SYNCDHCP y esto asignará una dirección ip dinámica, justo como lo comenta aquí el código fuente |
El código del enlace anterior.
# If 0.0.0.0 set DHCP, else set static IP address
if [ "${IP}" == "0.0.0.0" ]; then
sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP"
else
sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="inet ${IP}"
fi
Bug al clonar jail con bastille
El bug no es nada complejo de resolver, solo que se debe fixear la vnet correctamente, solo cambiar y ya, porque cuando clona, copia la interface del jail original sin escribir la nueva interface del jail clonado entonces:
En nuestro jails.conf
jellyfin-clone {
devfs_ruleset = 13;
enforce_statfs = 2;
exec.clean;
exec.consolelog = /mnt/pool/extensions/bastille/logs/jellyfin-clone_console.log;
exec.start = '/bin/sh /etc/rc';
exec.stop = '/bin/sh /etc/rc.shutdown';
host.hostname = jellyfin-clone;
mount.devfs;
mount.fstab = /mnt/pool/extensions/bastille/jails/jellyfin-clone/fstab;
path = /mnt/pool/extensions/bastille/jails/jellyfin-clone/root;
securelevel = 2;
vnet;
vnet.interface = e0b_bastille5; (1)
exec.prestart += "jib addm bastille5 igb0"; (2)
exec.prestart += "ifconfig e0a_bastille5 description \"vnet host interface for Bastille jail jellyfin-clone\""; (3)
exec.poststop += "jib destroy bastille5"; (4)
allow.mlock;
allow.raw_sockets;
}
1 | Nuestra inteface es e0b_bastille5, y debe estar también en las siguentes líneas. |
2 | Esta línea la cambie porque antes estaba la interface bastille1 del jail original |
3 | Se usa bastille5 |
4 | Se usa bastille5 también. |
Jail no arranca?
Al clonar, por lo visto el fstab toca actualizar los nombres correctos al nuevo nombre del jail. |
xigmanas: ~# bastille start jellyfin-clone (1)
[jellyfin-clone]:
(2)
mount_nullfs: /mnt/pool/extensions/bastille/jails/jellyfin/root/mnt/series: Resource deadlock avoided
jail: jellyfin-clone: /sbin/mount -t nullfs -o rw /mnt/pool_2/series /mnt/pool/extensions/bastille/jails/jellyfin/root/mnt/series: failed
xigmanas: ~# bastille start jellyfin-clone (3)
[jellyfin-clone]:
e0a_bastille5
e0b_bastille5
jellyfin-clone: created
xigmanas: ~# bastille console jellyfin-clone
[jellyfin-clone]:
root@jellyfin-clone:~ # ping google.com
PING google.com (142.250.201.78): 56 data bytes
64 bytes from 142.250.201.78: icmp_seq=0 ttl=116 time=5.877 ms
64 bytes from 142.250.201.78: icmp_seq=1 ttl=116 time=8.838 ms
64 bytes from 142.250.201.78: icmp_seq=2 ttl=116 time=8.711 ms
^C
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 5.877/7.809/8.838/1.367 ms
1 | Iniciamos nuestro jail y vemos que en la consola arroja un error justo en el fstab. |
2 | El jail clonado tiene un nombre incorrecto apuntando al original jellyfin, entonces lo cambiamos al nuevo nombre que es jellyfin-clone y listo |
3 | Luego de correjir el fstab todo bien. |
Problemas al borrar/eliminar un Jail 🔨
Muchas veces por alguna razón y los permisos del root
impiden borrar el directorio donde el jail se ha instalado, bien sea por un directorio/fichero con la flag schg
haciendolo inmutable (anti borrable), para eso hay un comando útil por ejemplo:
chflags -R 0 borrarDirectorio (1)
rm -rf borrarDirectorio (2)
1 | Esto remueve la flag schg y con -R de manera recursiva dentro del dir. |
2 | Luego podemos borrar el dir con facilidad. |
Con los pasos anteriores bastaría para borrar el directorio y solucionar el problema.
Pero tenemos otro escenario, como estamos trabajando en un sistema de ficheros zfs, se incluyo en el código fuente de bastille el parametro -f
para usarlo junto con destroy
servernas: jails# rm -rf mongodb
rm: mongodb/root: Device busy (1)
rm: mongodb: Device busy
1 | No se puede borrar, según esta ocupada la unidad |
servernas: /# cd /mnt/pool/extensions/bastille/jails
servernas: jails# ls
adguardhome apps-java jdownloader jellyfin mongodb reverse-proxy
servernas: jails# bastille destroy -f mongodb (1)
Deleting Jail: mongodb.
servernas: jails# ls (2)
adguardhome apps-java jdownloader jellyfin reverse-proxy
1 | Esto nos permite también poder borrar el jail anti-borrable 🤣. |
2 | Ya no existe el jail dentro del dataset que era mongodb, porque lo borramos. |
Información al respecto. |
Instalando Jdownloader
Desde hace muchos años, uso Jdownloader y de verdad que siempre me vino bien para reconexión automática, reanudar/continuar las descargas, descompresión automatica, conectarme a otros servidores como mega etc…
Instalar jdk
Viene bien la openjdk11
xigmanas: ~# bastille console jdownloader (1)
root@jdownloader:~ # pkg install openjdk11 (2)
1 | Entramos al jail jdownloader |
2 | Instalamos la open jdk. |
root@jdownloader:~ # java -version (1)
openjdk version "11.0.12" 2021-07-20
OpenJDK Runtime Environment (build 11.0.12+7-1)
OpenJDK 64-Bit Server VM (build 11.0.12+7-1, mixed mode)
1 | Mostramos la versión de java actual. |
Descargar megatools e iniciar Jdownloader
Megatools y url del .jar de Jdownloader
|
root@jdownloader:~ # pkg install megatools (1)
root@jdownloader:~/java # megadl https://mega.nz/file/2EkgUSga#Pjau9db2bBDES-ih4iWYlHfwC0t-444eFfm0SQegqRA (2)
Downloaded JDownloader.jar
root@jdownloader:~/java # ls -la
total 4134
drwxr-xr-x 2 root wheel 3 Jul 4 16:32 .
drwxr-x--- 19 root wheel 37 Jul 4 16:32 ..
-rw-r--r-- 1 root wheel 4411735 Jul 4 16:32 JDownloader.jar
1 | Instalamos megatools |
2 | Comando megadl para descargar desde mega |
java -jar JDownloader.jar -norestart (1)
1 | Este comando permite iniciar Jdownloader pero sin interface grafica, es decir modo consola, y muchas veces, requiere ejecutarlo nuevamente si nos sale la imagen de abajo. |
Al final para conectarnos a el, lo haríamos mediante MyJDownloader este existe en versión app para Android, IOs no lo se, y un plugin para Google Chrome MyJDownloader Browser Extension
Jdownloader con autoboot
Este proceso de autoboot, podemos hacerlo con otra aplicación, asi como hace git automaticamente que también crea su propio daemon, con adguardhome aplique el mismo procedimiento. |
El paso anterior con el parametro -norestart
, no merece la pena por, dado que a veces, el jdownloader con alguna actualización pendiente requiere que se ejecute de nuevo.
Además si nuestro NAS lo apagamos, nuestro jail no iniciara al Jdownloader por lo comentado anteriormente, entonces, en nuestro jail de Jdownloader nos creamos un pequeño fichero de configuración.
Creando fichero en etc/rc.d
El contenido del fichero que permitirá que nuestro Jdownloader arranque en cada inicio es este:
root@jdownloader:/etc/rc.d # touch jdownloader (1)
root@jdownloader:/etc/rc.d # chmod +x jdownloader (2)
root@jdownloader:/etc/rc.d # nano jdownloader (3)
1 | Creamos un fichero llamado jdownloader en esa ruta |
2 | Establecemos permisos de ejecución |
3 | Editamos con nano o el que sea 😆 |
#!/bin/sh
. /etc/rc.subr
name=jd2
rcvar=jd2_enable (1)
start_cmd="${name}_start"
stop_cmd="${name}_stop"
load_rc_config $name
jd2_start()
{
#!/bin/bash
echo "starting JDownloader2..."
umask 000
cd /jdownloader/
/usr/local/bin/java -Djava.awt.headless=true -jar /root/jdownloader/JDownloader.jar >/dev/null 2>/dev/null & (2)
}
jd2_stop()
{
#!/bin/bash
echo "killing java (and JDownloader2)..."
pgrep java | xargs kill
}
jd2_restart()
{
#!/bin/bash
echo "killing java (and JDownloader2)..."
pgrep java | xargs kill
umask 000
cd /jdownloader/
echo "starting JDownloader2..."
/usr/local/bin/java -Djava.awt.headless=true -jar /root/jdownloader/JDownloader.jar >/dev/null 2>/dev/null &
}
run_rc_command "$1"
1 | Es el nombre de nuestro daemon j2d podemos llamarle como queramos |
2 | Esto inicia nuestro .jar y crea un PID del proceso/daemon |
Ruta /etc/rc.conf
Necesitamos ahora ir al /etc/rc.conf de nuestro jail y añadir la siguiente líneas, para habilitar nuestro daemon de JDownloader en cada inicio del jail.
syslogd_flags="-ss"
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
cron_flags="-J 60"
ifconfig_e0b_bastille4_name="vnet0"
ifconfig_vnet0="inet 192.168.1.248/24"
defaultrouter="192.168.1.1"
jd2_enable="YES" (1)
1 | Habilitando el daemon en el boot del jail |
Es importante ejecutar nuevamente el .jar para añadir nuestra autenticación con email y password como en la imagen de abajo. |
En caso de reiniciar el jail por nuestra parte bastaría con un ejecutar jexec o bastille cmd que es una utilidad para ejecutar comandos dentro de un jail, sin estár dentro de el.
xigmanas: /# bastille restart jdownloader (1)
[jdownloader]:
jdownloader: removed
[jdownloader]:
e0a_bastille4
e0b_bastille4
jdownloader: created
xigmanas: /# jexec -l jdownloader top (2)
last pid: 16487; load averages: 0.16, 0.10, 0.04
4 processes: 1 running, 3 sleeping
CPU: 0.3% user, 0.0% nice, 0.0% system, 0.0% interrupt, 99.7% idle
Mem: 295M Active, 962M Inact, 8604M Wired, 21G Free
ARC: 5636M Total, 566M MFU, 5007M MRU, 96K Anon, 17M Header, 47M Other
4611M Compressed, 5333M Uncompressed, 1.16:1 Ratio
Swap: 2048M Total, 2048M Free
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
16135 root 50 52 0 10G 316M uwait 21 0:24 2.40% java (3)
16487 root 1 20 0 14M 3580K CPU4 4 0:00 0.05% top
16411 root 1 20 0 13M 2772K select 15 0:00 0.00% syslogd
16459 root 1 20 0 13M 2604K nanslp 10 0:00 0.00% cron
1 | reiniciando el jail y todo bien |
2 | Mirando que el proceso java dentro del jail este activo |
3 | daemon de jdownloader activo 🔥 |
xigmanas: ~# bastille cmd jdownloader top
[jdownloader]:
last pid: 56994; load averages: 0.00, 0.00, 0.00 up 26+10:35:47 19:30:08
6 processes: 1 running, 5 sleeping
CPU: 0.0% user, 0.0% nice, 0.1% system, 0.0% interrupt, 99.9% idle
Mem: 143M Active, 12G Inact, 8208K Laundry, 18G Wired, 1243M Free
ARC: 16G Total, 1615M MFU, 14G MRU, 96K Anon, 120M Header, 299M Other
14G Compressed, 16G Uncompressed, 1.13:1 Ratio
Swap: 2048M Total, 2048M Free
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
5670 root 53 52 0 11G 745M uwait 11 54:58 0.15% java (1)
56974 root 1 20 0 14M 3700K CPU7 7 0:00 0.01% top
5996 root 1 20 0 13M 2580K nanslp 20 0:07 0.00% cron
5951 root 1 20 0 13M 2772K select 17 0:05 0.00% syslogd
56975 root 1 20 0 13M 2584K piperd 7 0:00 0.00% cron
56976 root 1 20 0 13M 2584K nanslp 23 0:00 0.00% cron
1 | proceso java activo. |
Template de jdownloader
Con el parametro template usamos bajo fondo un bastillefile que nos permitira automatizar procesos luego de crear un jail, muy util tal cual como hace un dockerfile.
El fichero bastillefile debe ir dentro del directorio de bastille/template
bastille template jdownloader test/bastille-jdownloader (1)
1 | Aplicamos el template al jail corriendo, llamado jdownloader. |
Tenemos también 2 parametros opcionales, para cambiar la versión de la jdk y la de jdownloader que casi siempre actualizan el enlace de mega.
-
OPEN_JDK_VERSION
-
J2_URL
bastille template jdownloader test/bastille-jdownloader --arg OPEN_JDK_VERSION=17
ARG OPEN_JDK_VERSION=11
ARG J2_URL=https://mega.nz/file/fRNwxBza#oTUD5FEuWccnIvHzPdMwdE_ju4HndEDXbaf-VtoBnao
PKG openjdk${OPEN_JDK_VERSION} megatools
CMD mkdir jdownloader
CMD chmod -R 775 jdownloader
CMD cd jdownloader && megadl ${J2_URL}
CMD chmod +x jdownloader/JDownloader.jar
#Copy the etc file from the template to the jdownloader jail etc file
CP etc /
RENDER /etc/rc.d/jdownloader
CMD chmod +x /etc/rc.d/jdownloader
SYSRC jd2_enable="YES"
CONFIG set allow.mlock;
CONFIG set allow.raw_sockets;
CMD java -jar jdownloader/JDownloader.jar
CMD pkill java
CMD java -jar jdownloader/JDownloader.jar -norestart (1)
1 | El último comando en la cual lanzara un login a Jdownloader, e introduciremos nuestro user y password. |
Actualizar desde MyJDownloader
En la interface web, en settings podemos actualizarle, pero como tenemos autoboot él se reiniciará automáticamente.
Esta actualización la realize por gusto, en realidad es opcional, sin hacerla me permitía usar jdownloader tranquilamente. |
Ruta de descarga
Aquí en settings también podemos cambiar la ruta de descarga, el directorio debe existir en nuestro jail
Instalando Jellyfin
Esto no es
, nosotros nos corresponde hacer todo el trabajo de guardar las películas en nuestro NAS, y desde el Jellyfin, acceder a ese directorio, pool/dataset donde las tengamos, para poder verlas 😁
Jellyfin es un fork de emby, como plex, pero opensource, como muchas opciones para tener nuestras películas en nuestro NAS organizadas, editar subtítulos, control de usuarios hasta control parental, añadir musica, tiene un Api para aplicaciones externas, extensiones, la versión que usare es 10.7.7
es un poco vieja, pero viene bastante bien, muy superior al miniDLNA 😅.
Pasos básicos de instalación más repositorio de inspiración
|
Configuración del jails.conf
Para jellyfin es importante añadir las últimas 2 líneas:
jellyfin {
devfs_ruleset = 13;
enforce_statfs = 2;
exec.clean;
exec.consolelog = /mnt/pool/extensions/bastille/logs/jellyfin_console.log;
exec.start = '/bin/sh /etc/rc';
exec.stop = '/bin/sh /etc/rc.shutdown';
host.hostname = jellyfin;
mount.devfs;
mount.fstab = /mnt/pool/extensions/bastille/jails/jellyfin/fstab;
path = /mnt/pool/extensions/bastille/jails/jellyfin/root;
securelevel = 2;
vnet;
vnet.interface = e0b_bastille0;
exec.prestart += "jib addm bastille0 igb0";
exec.prestart += "ifconfig e0a_bastille0 description \"vnet host interface for Bastille jail jellyfin\"";
exec.poststop += "jib destroy bastille0";
allow.mlock; (1)
allow.raw_sockets; (2)
}
1 | Relacionado con la memoria del jail. |
2 | Habilita utilidades como ping y traceroute dentro del jail. |
La dirección ip a usar es la que le asignamos al jail y puerto por defecto 8096 |
Error al reinstalar Jellyfin
Me paso muchas veces que al querer reinstalar jellyfin, no podía hacerlo por tener un UID repetido, en realidad por usuarios/grupos.
|
The service file uses daemon to restart jellyfinserver if it crashes.
The service file will also change the permissions so that the updater works.
If this behavior is unwanted you will need to edit the RC file manually and
remove the daemon and/or the permissions changes.
If you are running this in a jail please set "allow_mlock=1" or similar
for this jail otherwise the program will fail to start.
dotNET does not work well inside jails that are missing either a) VNET or
one of b) ip6=inherit c) ip6=new. The service file will try workaround any
user misconfiguration but is not perfect.
root@jailvnet2:~ # pw user add jellyfin -c jellyfin -u 710 -d /nonexistent -s /usr/bin/nologin
pw: uid `710' has already been allocated (1)
root@jailvnet2:~ # ln -s /usr/local/lib/libsqlite3.so /usr/local/lib/libe_sqlite3
root@jailvnet2:~ # sysrc jellyfinserver_enable=TRUE
jellyfinserver_enable: -> TRUE
root@jailvnet2:~ # sysrc jellyfinserver_user=jellyfin
jellyfinserver_user: -> jellyfin
root@jailvnet2:~ # sysrc jellyfinserver_group=jellyfin
jellyfinserver_group: -> jellyfin
root@jailvnet2:~ # service jellyfinserver start
install: unknown group jellyfin
install: unknown group jellyfin
Starting jellyfinserver.
su: unknown login: jellyfin
/usr/local/etc/rc.d/jellyfinserver: WARNING: failed to start jellyfinserver (2)
root@jailvnet2:~ #
1 | El UID 710 estaba repetido, pareciendo que otro usuario lo tiene, entonces lo que hariamos es colocar otro. |
2 | Al intentar iniciar el servidor jellyfin tenemos este error. |
Lo fixeamos con lo siguiente
pw user add jellyfin -c jellyfin -u 715 -d /nonexistent -s /usr/bin/nologin (1)
1 | Usamos ahora UID 715, para fixear el error. |
root@jailvnet2:~ # service jellyfinserver start
Starting jellyfinserver. (1)
1 | Con este solo mensaje, indica que todo esta bien, ahora podemos acceder con la dirección ip del jail mas el puerto 8096 |
Actualizando Jellyfin
Es buena idea tener un backup o clonar el jail en casos como estos, bastille lo permite, vía consola o web. |
root@jellyfin:~ # service jellyfinserver stop (1)
Stopping jellyfinserver.
root@jellyfin:~ # fetch https://github.com/Thefrank/jellyfin-server-freebsd/releases/download/v10.8.1/jellyfinserver-10.8.1.pkg (2)
jellyfinserver-10.8.1.pkg 58 MB 7305 kBps 08s
root@jellyfin:~ # ls
.cshrc .k5login .shrc
.history .login jellyfinserver-10.7.7.pkg
.hushlogin .profile jellyfinserver-10.8.1.pkg
root@jellyfin:~ # pkg install jellyfinserver-10.8.1.pkg (3)
Updating FreeBSD repository catalogue...
[jellyfin] Fetching packagesite.pkg: 100% 6 MiB 3.3MB/s 00:02
Processing entries: 100%
FreeBSD repository update completed. 31614 packages processed.
All repositories are up to date.
New version of pkg detected; it needs to be installed first.
The following 1 package(s) will be affected (of 0 checked):
Installed packages to be UPGRADED:
pkg: 1.17.5 -> 1.18.3 (4)
Number of packages to be upgraded: 1
8 MiB to be downloaded.
Proceed with this action? [y/N]: y (5)
[jellyfin] [1/1] Fetching pkg-1.18.3.pkg: 100% 8 MiB 2.2MB/s 00:04
Checking integrity... done (0 conflicting)
[jellyfin] [1/1] Upgrading pkg from 1.17.5 to 1.18.3...
[jellyfin] [1/1] Extracting pkg-1.18.3: 100%
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 2 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
jellyfinserver: 10.8.1
krb5-120: 1.20
Number of packages to be installed: 2
The process will require 135 MiB more space.
1 MiB to be downloaded.
Proceed with this action? [y/N]: y (6)
[jellyfin] [1/2] Fetching krb5-120-1.20.pkg: 100% 1 MiB 1.2MB/s 00:01
Checking integrity... done (0 conflicting)
[jellyfin] [2/2] Installing jellyfinserver-10.8.1...
===> Creating groups.
Using existing group 'jellyfinserver'.
===> Creating users
Using existing user 'jellyfinserver'.
[jellyfin] Extracting jellyfinserver-10.8.1: 100%
[jellyfin] [1/2] Installing krb5-120-1.20...
[jellyfin] [1/2] Extracting krb5-120-1.20: 100%
=====
Message from jellyfinserver-10.8.1:
--
jellyfinserver relies on Microsoft dotNET5+ SDK to be built
Microsoft does not have an official version of dotNET for FreeBSD
This package was built with an UNOFFICIAL UNSUPPORTED version of dotNET
If this is something that you do not want, remove this package with
"pkg remove jellyfinserver"
This package installs a service file.
Enable it with "sysrc jellyfinserver_enable=TRUE"
Start it with "service jellyfinserver start".
The service file uses daemon to restart jellyfinserver if it crashes.
The service file will also change the permissions so that the updater works.
If this behavior is unwanted you will need to edit the RC file manually and
remove the daemon and/or the permissions changes.
If you are running this in a jail please set "allow_mlock=1" or similar
for this jail otherwise the program will fail to start.
dotNET does not work well inside jails that are missing either a) VNET or
b) ip6=inherit. The service file will try workaround any user misconfiguration
but is not perfect.
root@jellyfin:~ # service jellyfinserver start (7)
Starting jellyfinserver.
1 | Paramos el servidor jellyfin |
2 | fetch a la nueva versión de jellyfin |
3 | Se instala el .pkg versión 10.8.1 de jellyfin |
4 | Se muestra la versión que se actualizara. |
5 | Yes |
6 | Yes |
7 | Iniciamos el servidor jellyfin |
Tenemos la actualización lista
Registros / Logs
Esta parte nos permite visualizar nuestros logs, muy util.
Puede suceder, que las imagenes de las películas no sean las correctas, pero tampoco puedan cambiarse correctamente desde la interface web, pero puede ser falta de permisos de escritura en el NAS gracias a los logs se puede verificar eso. |
[2022-05-08 15:57:59.602 +00:00] [ERR] [18] MediaBrowser.Providers.Manager.ProviderManager: UnauthorizedAccessException - Access to path "/mnt/movies_1/Spiderman un nuevo universo (2018)/folder.jpg" is denied. Will retry saving to "/var/db/jellyfinserver/metadata/library/a4/a45b8287c09ccc439897b6158d8d88bd/poster.jpg"
[2022-05-08 15:57:59.828 +00:00] [ERR] [18] MediaBrowser.Providers.Manager.ProviderManager: UnauthorizedAccessException - Access to path "/mnt/movies_1/Spiderman un nuevo universo (2018)/backdrop.jpg" is denied. Will retry saving to "/var/db/jellyfinserver/metadata/library/a4/a45b8287c09ccc439897b6158d8d88bd/backdrop.jpg"
[2022-05-08 15:58:02.249 +00:00] [ERR] [24] MediaBrowser.Providers.Manager.ProviderManager: Error in metadata saver
(1)
System.UnauthorizedAccessException: Access to the path '/mnt/movies_1/Spiderman un nuevo universo (2018)/Spider-Man Un nuevo universo (2018).nfo' is denied.
---> System.IO.IOException: Permission denied
--- End of inner exception stack trace ---
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at MediaBrowser.XbmcMetadata.Savers.BaseNfoSaver.SaveToFile(Stream stream, String path)
at MediaBrowser.XbmcMetadata.Savers.BaseNfoSaver.Save(BaseItem item, CancellationToken cancellationToken)
at MediaBrowser.Providers.Manager.ProviderManager.SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable`1 savers)
1 | Error a la hora de escribir en el directorio, entonces, no se podrian editar las portadas y demás. |
Generalmente se cambian esas imagenes de aquí, pero el dataset debe tener los permisos correctos.
OpenSubtitles
Este es un plugin para subtítulos muy útil, en caso de tener una película con caracteres raros en las traducciones.
Necesitamos crearnos un usuario para tener acceso al api, dicho usuario lo introduciremos en nuestro server jellyfin
Estatus del api OpenSubtitles
Esta url permite ver el estado del api de OpenSubtitles
con pequeñas metricas.
Buscando subtítulos
En caso de un película vieja, y queramos subtítulos, en la esquina derecha, tenemos 3 puntos verticales, luego en "Editar subtítulos", que nos mostrara la modal siguente:
Por defecto tenemos
-
Subtitulos Latino - Es
-
Pero queremos Inglés por ejemplo
Metadatos con MKVToolNix
Muchos archivos por ahí (.mp4 .mkv etc), tendran metadatos, e incluso llegan a ser un poco molestos.
En el caso de archivos .mkv viene muy bien el MKVToolNix vía GUI, es muy rápido, importamos nuestra película y editamos el metadato que queramos…
Lo mejor es editar el fichero en local, si editamos el video directamente en el directorio del NAS, tardaria muchisimo (aún en LAN), podemos descargar la película desde el mismo jellyfin a nuestra pc editar y luego subirla.
En el menu donde "multiplexador" tenemos varias cosas:
-
Codec
-
Cada item corresponde a una parte que podemos editar.
-
-
Propiedades
-
Podemos cambiar por ejemplo "Nombre de pista".
-
-
Pestaña/tab Salida
-
General → Título del archivo: escribimos el nombre del video(o simplemente borrar el texto original que no queramos), en ciertos reproductores, este nombre se mostrara en el inicio de la película.
-
-
Archivo de salida:
-
Este será el nombre del fichero en realidad puede ser cualquiera, no es un metadato, se puede editar como cualquier archivo.
-
-
Iniciar multiplexado
-
Luego de tener todo listo, clickeamos ese botón.
-
Amazon fire stick 4k
El Amazon fire stick Nos permite instalar aplicaciones en el, basado en Android tv, nos quitamos esa molestia que nos pasa con ciertos smart-tv a la hora de instalar una app, evitando usar el protocolo DLNA que es más inestable de lo que parece.
En el tendremos tranquilamente nuestro cliente
jellyfin para acceder a nuestro servidor jellyfin con una configuración previa pero sencilla.
Con conexión HDMI, si lo llevamos a un lugar remoto, lo conectamos y accedemos a nuestro NAS tanto local, o remotamente con ciertos cambios, como tener un dns dinámico.
Dimensiones | 99 x 30 x 14 mm (solo el dispositivo) 108 x 30 x 14 mm (incluyendo el conector) |
---|---|
Peso |
53,6 |
Procesador |
Quad-Core de 1,7 GHz |
GPU |
IMG GE8300 |
Almacenamiento |
8 GB |
Wifi |
Wifi de doble banda y doble antena (MIMO) que permite una transferencia de datos más rápida y pérdida de conexión menor que con el wifi estándar. Compatible con redes wifi 802.11a/b/g/n/ac. |
Bluetooth |
Bluetooth 5.0 y LE. Se puede vincular con altavoces, auriculares, mandos de videojuegos y otros dispositivos Bluetooth compatibles. |
Reverse proxy para acceso remoto
Ian me trajo recuerdos con una cosa interesante, para mejor administración de los certificados SSL con un server nginx.
Nuevamente nos creamos un Jail para instalar nuestro servidor nginx y redireccionar las peticiones http que queramos que pasen por aquí.
/usr/local/etc/nginx/nginx.conf (1)
1 | Ruta de configuración del proxy nginx |
En caso de editar el fichero nginx.conf
service nginx reload (1)
1 | Para reiniciar el servidor nginx |
Redirección a Https
Por lo visto si accedemos con http a nuestros servidores con nginx por defecto es posible entrar normal, y eso no lo queremos, podemos hacer una redirección a https, pero debemos ajustar nuestro nginx.conf
Fue necesario para esto, abrir el puerto 80 en el router con la ip del reverse-proxy, porque sin eso no funciona. |
server {
listen 443 ssl; (1)
server_name localhost nuestroDominio.duckdns.org;
ssl_certificate /usr/local/etc/letsencrypt/live/dominio/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/dominio/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://192.168.1.130:8096; (2)
}
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000 includeSubDomains; preload" always;
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
set $https_redirect 0;
#if request came from port 80/http
if ($server_port = 80) {
set $https_redirect 1;
}
# or if the requested host came with www
if ($host ~ '^www\.') {
set $https_redirect 1;
}
#then it will redirects
if ($https_redirect = 1) {
return 301 https://$server_name$request_uri;
}
}
server { (3)
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
1 | Config para el https |
2 | Nuestro server en local de jellyfin |
3 | Confi necesaria de http |
Como renovar el certificado SSL de letsencrypt con certbot?
Podemos usar certbot con instrucciones para freeBSD los certificados que hemos creado con letsencrypt, estos se vencen a los 90 días.
root@reverse-proxy:/usr/local/etc/nginx # certbot renew (1)
root@reverse-proxy:/usr/local/etc/nginx # certbot renew --dry-run (2)
1 | Para renovar los certificados. |
2 | Sirve para testear la renovación automática, sin generar los certificados. |
Pero obtenemos este error
Saving debug log to /var/log/letsencrypt/letsencrypt.log (1)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /usr/local/etc/letsencrypt/renewal/mydomain.bla.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for mydomain.bla
Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:
Domain: mydomain.bla
Type: unauthorized
Detail: ip: Invalid response from http://mydomain.bla/.well-known/acme-challenge/e5P1zpHbQUyQ6R28jew3Z9rRxpMPzUdsLE7Gdlp5ZqI: 404
(2)
Hint: The Certificate Authority failed to download the challenge files from the temporary standalone webserver started by Certbot on port 80. Ensure that the listed domains point to this machine and that it can accept inbound connections from the internet.
Failed to renew certificate mydomain.bla with error: Some challenges have failed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All renewals failed. The following certificates could not be renewed:
/usr/local/etc/letsencrypt/live/mydomain.bla/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
1 | Ruta del log generado, y que debemos inspeccionar en caso de algo raro. |
2 | Por lo visto esta estrechamente relacionado con nuestro error, y el puerto 80 bloqueado |
Si investigamos mas con el comando certbot renew -v
tenemos que se usa el:
http-01 challenge for xxx.xxx.net pero justo este no nos sirve .
|
Necesitamos usar otro challenge
que nos permita hacer esto, nuestro proveedor nos bloquea el puerto 80 😡.
Usando DNS dinámico con DuckDNS
Anteriormente me valia con no-ip para mi ip dinámica, pero con este dns-01-challenge necesito escribir los record TXT
en el, y no me va, porque habría que pagar, prefiero darle ese dinero a los pobres.
Ahora con duckdns me da todo, gratis, y un api-rest para actualizar el record TXT, una vez que introduzca el comando necesario con certbot:
certbot certonly --manual --preferred-challenges dns -d miDominio.duckdns.org (1)
1 | Mi dominio |
root@reverse-proxy:/logs-letsencrypt # certbot certonly --manual --preferred-challenges dns -d foo.duckdns.org
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Certificate not yet due for renewal
You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /usr/local/etc/letsencrypt/renewal/foo.duckdns.org.conf)
What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now (1)
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
1 | La opción (1) me tocará ya que tengo el certificado vigente. |
En caso de tener que renovar el certificado los pasos para actualizar el record TXT es aquí.
root@reverse-proxy:/logs-letsencrypt # certbot certonly --manual --preferred-challenges dns -d mySubName (1)
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for bar.duckdns.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:
_acme-challenge.bar.duckdns.org.
with the following value:
L9-------------------------------------(2)
Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.bar.duckdns.org.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 | mySubName ejemplo bar.duckdns.org |
2 | Token generado de 43 caracteres para nuestro record TXT, para usar en los query-parameters del endpoint ofrecido por duck dns, es el paso siguiente. |
Invocando al endpoint para actualizar certificado
Desde la consola usando curl o desde el navegador, o sea, enviar un GET para consumir la URL.
https://www.duckdns.org/update?domains=mySubName&token=myTokenDeDuckDns&txt=tokenGenerado&verbose=true (1)
1 | Insertamos nuestro token de duckdns (el que nos genera la web) en el parametro token, también nuestro token generado en el paso anterior para usarle en el parametro txt |
Cuando el certificado se ha actualizado correctamente
Successfully received certificate.
Certificate is saved at: /usr/local/etc/letsencrypt/live/boo.duckdns.org/fullchain.pem
Key is saved at: /usr/local/etc/letsencrypt/live/foo.duckdns.org/privkey.pem
This certificate expires on 2023-12-06.
These files will be updated when the certificate renews.
NEXT STEPS:
This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Una vez que setemos la nueva ruta de nuestros certificados fullchain.pem
y privkey.pem
nos bastaría con reiniciar nuestro server nginx
root@reverse-proxy:/servernginx # service nginx reload (1)
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
1 | reiniciando el nginx server. |