Complete Guide: Wake-on-LAN, Jellyfin & WireGuard on Debian

Secure Remote Media Server Setup

Table of Contents


Introduction

In this guide, I will walk you through setting up a secure remote media server using:

  • Wake-on-LAN (WOL) – remotely power on your Debian machine
  • Jellyfin – free, open-source media streaming
  • WireGuard VPN – secure encrypted access to your server

This setup allows you to:

  • Wake up your server from anywhere
  • Access Jellyfin securely from your phone
  • Stream content exactly as if you were on your home network
  • Avoid exposing sensitive services directly to the internet

Requirements

Before you begin, make sure you have:

  • A Debian-based server
  • A home router with NAT/PAT support
  • An Android smartphone
  • Basic terminal knowledge

Wake-on-LAN (WOL)

Step 1 — Enable WOL in the BIOS

Look for options such as:

  • Wake on LAN
  • Power on by PCI-E
  • Resume by LAN

Enable the appropriate setting.


Step 2 — Enable WOL on Debian

Install ethtool:

sudo apt install ethtool

Enable WOL on your network interface:

sudo ethtool -s eth0 wol g

(Replace eth0 with your actual interface using ip link.)


Step 3 — Make WOL Persistent

Create /etc/systemd/system/wol.service:

[Unit]
Description=Wake-on-LAN configuration
After=network.target

[Service]
Type=oneshot
ExecStart=/sbin/ethtool -s eth0 wol g

[Install]
WantedBy=multi-user.target

Enable the service:

sudo systemctl enable wol

Step 4 — Configure Router & Mobile App

On your router:

  • Assign a static DHCP lease
  • Forward UDP 9 → port 9 of the server

On Android (app: Wake On LAN – by MR-Webb):

  • Name: any label
  • Group: Bookmarked
  • MAC address: server NIC MAC
  • Broadcast/Host: server LAN IP
  • Public IP: router’s WAN IP
  • Port: 9

Installing and Configuring Jellyfin

Step 1 — Install Jellyfin

curl https://repo.jellyfin.org/install-debuntu.sh | sudo bash
sudo systemctl enable jellyfin
sudo systemctl start jellyfin

Step 2 — Access the Web Interface

Navigate to:

http://YOUR_SERVER_IP:8096

Follow the setup steps:

  • Create your account
  • Add media libraries (Movies, Series, Music, etc.)

!!! Warning: Do NOT expose Jellyfin directly to the internet !!!

Always place Jellyfin behind a VPN such as WireGuard.


WireGuard VPN Setup

Step 1 — Install WireGuard

sudo apt install wireguard

Install the official Android app:

WireGuard – WireGuard Development Team


Step 2 — Generate Keys

Server keys:

wg genkey | tee server_private.key | wg pubkey > server_public.key

Phone keys:

wg genkey | tee phone_private.key | wg pubkey > phone_public.key

Display keys:

cat server_private.key
cat server_public.key
cat phone_private.key
cat phone_public.key

Never share private keys.


Step 3 — Configure /etc/wireguard/wg0.conf

Example VPN subnet:

  • VPN network: 10.10.0.0/24
  • Server: 10.10.0.1
  • Phone: 10.10.0.2
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>

PostUp   = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp0s31f6 -j MASQUERADE; ip6tables -A INPUT -p udp --dport 51820 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o enp0s31f6 -j MASQUERADE; ip6tables -D INPUT -p udp --dport 51820 -j ACCEPT

SaveConfig = true

[Peer]
PublicKey = <PHONE_PUBLIC_KEY>
AllowedIPs = 10.10.0.2/32

Replace enp0s31f6 with your interface name.


Step 4 — Enable IP Forwarding

echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system

Step 5 — Configure Router Port Forwarding

Forward:

  • UDP 51820 → server LAN IP

Step 6 — Start WireGuard

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg

Step 7 — Configure WireGuard on Android

[Interface]
PrivateKey = <PHONE_PRIVATE_KEY>
Address = 10.10.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = YOUR_PUBLIC_IP:51820
AllowedIPs = 192.168.1.0/24, 10.10.0.0/24
PersistentKeepalive = 25

Step 8 — Generate QR Code (Optional)

sudo apt install qrencode
qrencode -t ansiutf8 < phone.conf

Scan it directly in the WireGuard app.


Testing the Setup

  1. Send WOL packet from your phone
  2. Wait for the Debian server to boot
  3. Activate WireGuard tunnel on your phone
  4. Open Jellyfin via LAN IP:
http://192.168.1.50:8096

(Replace with your own server IP)


Troubleshooting

Common issues:

  • Incorrect router port forwarding
  • Wrong key pasted in configs
  • Firewall blocking VPN traffic

UFW Firewall Configuration (if applicable)

Allow WireGuard:

sudo ufw allow 51820/udp

Allow VPN subnet:

sudo ufw allow from 10.10.0.0/24

Add NAT rules in /etc/ufw/before.rules before *filter:

# WireGuard NAT masquerading
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.10.0.0/24 -o enp0s31f6 -j MASQUERADE
COMMIT

Ensure forwarding rules are present:

-A ufw-before-forward -i wg0 -j ACCEPT
-A ufw-before-forward -o wg0 -j ACCEPT

Restart UFW:

sudo ufw disable
sudo ufw enable

#jellyfin #wireguard #debian #wol #media #setup

Trick grep / egrep to always display filename

If you use grep / egrep on a single file, it will display the matched patterns, but not the filename nor the line number.

This can be boring in case you encapsulate a grep / egrep call inside i.e a find:

find ./mydir -type f -name '*.msg' -exec grep 'mysearch' {} \;

In that case it will only print the match and you will not know in which file.

The trick is to add a dummy filename as a second file to search. Doing so will trick grep / egrep into thinking you are searching in multiples files, thus displaying the filename on each match.
/dev/null is the perfect target for the second dummy file as it will never match anything.

Example:

find ./mydir -type f -name ‘*.msg’ -exec grep ‘mysearch’ {} /dev/null \;

Bonus / reminder:

In grep / egrep use the -n option to also display the match line number

Example:

find ./mydir -type f -name ‘*.msg’ -exec grep -n ‘mysearch’ {} /dev/null \;

#sysadmin #tips #tricks #grep #egrep

KAFKA

KAFKA is in all mouths these days. So I share here, also as a reminder for me, a couple of #KAFKA ressources that looked helpful to me.

TLDR:

Do not use KAFKA for:

-“Little” Data flows (overkill)

-Streaming ETL (handling transformation is a hassle)

-Store and process large files (images, videos, proprietary files, etc.)

https://www.kai-waehner.de/blog/2020/08/07/apache-kafka-handling-large-messages-and-files-for-image-video-audio-processing/

https://www.upsolver.com/blog/apache-kafka-use-cases-when-to-use-not

https://kafka.apache.org/intro

https://docs.confluent.io/kafka-clients/librdkafka/current/overview.html

https://docs.confluent.io/platform/current/clients/librdkafka/html/md_INTRODUCTION.html

Compare two json in shell

I did it using the JQ command line tool from https://stedolan.github.io/jq/

Exemple: list all json files from current directory and print the difference with updated jsons from updated/ directory

for user in  `ls updated-users`
do
    # print file name
    echo $user
    # simple 
    diff <(jq -S . users/$user) <(jq -S . updated-users/$user)
    # or full on one side and the diff on the other side
    # diff -y --left-column <(jq -S . users/$user) <(jq -S . updated-users/$user)
    # or full on one side and the diff on the other side, colored
    # diff -y --left-column --color  <(jq -S . users/$user) <(jq -S . updated-users/$user)
done

#shell #diff #json #script

Adding proxy to MSYS2

If you ever need to use a proxy when updating / installing packages in msys2 you’ll have to set the following environnement variables, and put them i.e in your .bash_profile :

# .bash_profile example
# Note: username and password have to be url encoded in case they contain special chars
export http_proxy=http://USERNAME:PASSWORD@proxy:port
# or like this if not user/password required
# export http_proxy=http://proxy:port
export https_proxy=$http_proxy
export ftp_proxy=$http_proxy
export rsync_proxy=$http_proxy
# if you need a proxy ignore list
export no_proxy="localhost,127.0.0.1,localaddr,.yourlocaldomain.ext,.local"

CYGWIN: list all process arguments

A few days ago I had to list the arguments for specific process.
While finding it using “ps -aef | grep ‘processname'” and getting the information is trivial under linux, it is not the case using cygwin, which is only reporting process name and pid when calling “ps”.

A lot of solutions involve installing cygwin packet, like pstree.

Another solution is to search the /proc/pid/cmdline files, like here:

grep -a /proc/*/cmdline | xargs -0
/proc/1990/cmdline:/bin/sh /usr/bin/startxwin
/proc/2016/cmdline:xinit /etc/X11/xinit/startxwinrc — /usr/bin/XWin :0 -multiwindow -auth /home/user/.serverauth.1990
/proc/2017/cmdline:/usr/bin/XWin :0 -multiwindow -auth /home/user/.serverauth.1990
/proc/2023/cmdline:/usr/bin/xwin-xdg-menu
/proc/2035/cmdline:dbus-launch –sh-syntax –exit-with-session
/proc/2036/cmdline:/usr/bin/dbus-daemon –fork –print-pid 5 –print-address 7 –session
/proc/2046/cmdline:/usr/libexec/gam_server
/proc/2512/cmdline:mintty
/proc/2513/cmdline:bash
/proc/3441/cmdline:grep –color -a /proc/1990/cmdline /proc/2016/cmdline /proc/2017/cmdline /proc/2023/cmdline /proc/2035/cmdline /proc/2036/cmdline /proc/2046/cmdline /proc/2512/cmdline /proc/2513/cmdline /proc/3441/cmdline /proc/self/cmdline
/proc/self/cmdline:grep –color -a /proc/1990/cmdline /proc/2016/cmdline /proc/2017/cmdline /proc/2023/cmdline /proc/2035/cmdline /proc/2036/cmdline /proc/2046/cmdline /proc/2512/cmdline /proc/2513/cmdline /proc/3441/cmdline /proc/self/cmdline

To restrain it to a particular process i.e XWin, excluding grep command:

grep -a “XWin” /proc/*/cmdline |xargs -0 |grep -v grep
/proc/2016/cmdline:xinit /etc/X11/xinit/startxwinrc — /usr/bin/XWin :0 -multiwindow -auth /home/user/.serverauth.1990
/proc/2017/cmdline:/usr/bin/XWin :0 -multiwindow -auth /home/user/.serverauth.1990

Cargo Cult Sytem Administrator

And some other types too.

Fun article to read here: https://blog.lastinfirstout.net/2009/11/cargo-cult-system-administration.html

One particularly right: “Asserting that [Technology O] or [Platform L] or [Methodology A] is inherently superior to all others and blindly applying it to all problems. When you make such claims, are you applying science or religion?”

“It’s easy to fall into cargo cult mode.
Just re-boot it, it’ll be fine.” – Michael Janke