Linux Digital Signage Guide
Linux powers a significant portion of professional digital signage deployments, offering unmatched flexibility, reliability, and cost-effectiveness. From embedded systems to enterprise data centers, Linux provides the foundation for scalable signage networks.
Why Linux for Digital Signage?
Advantages
| Advantage | Description |
|---|---|
| No License Fees | Free OS eliminates per-device costs |
| Long-Term Support | Ubuntu LTS: 10 years, Debian: 5 years |
| Customizable | Tailor to exact signage requirements |
| Security | Strong security model, rapid patch availability |
| Reliability | Proven 24/7/365 server-grade stability |
| Hardware Flexibility | Runs on x86, ARM, embedded, servers |
| Automation | Excellent scripting and remote management |
| Open Source Ecosystem | Vast software and tool availability |
Considerations
| Challenge | Mitigation |
|---|---|
| Technical Complexity | Use purpose-built signage distros or detailed guides |
| Driver Support | Choose hardware with good Linux support |
| Learning Curve | Start with familiar distributions (Ubuntu) |
| Vendor Support | Use commercial Linux or enterprise subscriptions |
| Desktop Environment | Often not needed; increases complexity |
Distribution Selection
Recommended Distributions
┌─────────────────────────────────────────────────────────────────────────────┐
│ Linux Distributions for Signage │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Ubuntu LTS (Recommended for Most) │
│ ├── Versions: 22.04 LTS, 24.04 LTS │
│ ├── Support: 10 years with Ubuntu Pro │
│ ├── Best for: General signage, enterprise deployments │
│ └── Pros: Excellent docs, huge community, good hardware support │
│ │
│ Debian Stable │
│ ├── Versions: Debian 12 (Bookworm) │
│ ├── Support: ~5 years │
│ ├── Best for: Stability-focused deployments │
│ └── Pros: Ultra-stable, minimal bloat, long testing period │
│ │
│ Raspberry Pi OS (for Pi hardware) │
│ ├── Based on: Debian │
│ ├── Best for: Raspberry Pi signage players │
│ └── See: Raspberry Pi Signage Guide │
│ │
│ Fedora IoT / RHEL Edge │
│ ├── Support: 10+ years (RHEL) │
│ ├── Best for: Enterprise with Red Hat standardization │
│ └── Pros: Immutable OS option, strong enterprise support │
│ │
│ Alpine Linux │
│ ├── Size: ~130MB │
│ ├── Best for: Containers, embedded, minimal footprint │
│ └── Pros: Security-focused, tiny size, fast boot │
│ │
│ Yocto/Buildroot (Custom Embedded) │
│ ├── Best for: OEMs, high-volume, specialized hardware │
│ └── Pros: Fully custom, minimal attack surface │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Distribution Comparison
| Feature | Ubuntu LTS | Debian | Alpine | Fedora IoT |
|---|---|---|---|---|
| Ease of Setup | ★★★★★ | ★★★★ | ★★★ | ★★★★ |
| Stability | ★★★★ | ★★★★★ | ★★★★ | ★★★★ |
| Hardware Support | ★★★★★ | ★★★★ | ★★★ | ★★★★ |
| Documentation | ★★★★★ | ★★★★ | ★★★ | ★★★★ |
| Size | ~2GB | ~1GB | ~130MB | ~800MB |
| Boot Time | ~15-25s | ~15-20s | ~5-10s | ~10-15s |
| Package Freshness | ★★★★ | ★★★ | ★★★★★ | ★★★★★ |
Installation & Base Setup
Ubuntu Server Installation (Headless)
# Download Ubuntu Server LTS
# Use Rufus/Etcher to create bootable USB
# During installation:
# - Select "Ubuntu Server (minimized)" for smallest footprint
# - Enable OpenSSH server
# - Skip snaps installation
# Post-installation setup
sudo apt update && sudo apt upgrade -y
# Install minimal display environment
sudo apt install --no-install-recommends \
xorg \
openbox \
lightdm \
pulseaudio
# Configure auto-login
sudo nano /etc/lightdm/lightdm.conf
# Add:
[Seat:*]
autologin-user=signage
autologin-user-timeout=0
user-session=openbox
# Create signage user
sudo useradd -m -s /bin/bash signage
sudo usermod -aG audio,video,input signage
Minimal Debian Installation
# Install Debian with "SSH server" and "standard system utilities" only
# Add non-free firmware repository (for hardware support)
sudo nano /etc/apt/sources.list
# Add: non-free-firmware to each line
# Install minimal X environment
sudo apt install --no-install-recommends \
xserver-xorg \
xinit \
openbox \
x11-xserver-utils \
pulseaudio
# Auto-start X on boot
sudo nano /etc/systemd/system/xinit.service
[Unit]
Description=X Server
After=systemd-user-sessions.service
[Service]
ExecStart=/usr/bin/xinit -- :0 vt1
User=signage
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl enable xinit
Signage Player Software
Browser-Based Kiosk
Chromium Kiosk Mode:
# Install Chromium
sudo apt install chromium-browser
# Create autostart script
mkdir -p ~/.config/openbox
cat > ~/.config/openbox/autostart << 'EOF'
# Disable screen blanking
xset s off
xset -dpms
xset s noblank
# Hide cursor after 5 seconds of inactivity
unclutter -idle 5 &
# Start Chromium in kiosk mode
chromium-browser \
--kiosk \
--noerrdialogs \
--disable-infobars \
--disable-session-crashed-bubble \
--disable-restore-session-state \
--disable-features=TranslateUI \
--check-for-update-interval=31536000 \
--disable-background-networking \
--disable-sync \
--disable-translate \
--disable-extensions \
--disable-default-apps \
--disable-component-update \
--autoplay-policy=no-user-gesture-required \
--start-fullscreen \
--start-maximized \
"https://your-signage-cms.com/display/12345"
EOF
chmod +x ~/.config/openbox/autostart
# Install unclutter for cursor hiding
sudo apt install unclutter
Firefox Kiosk Mode:
# Install Firefox ESR
sudo apt install firefox-esr
# Firefox kiosk mode
firefox-esr --kiosk "https://your-signage-cms.com/display"
# Or with more options via user.js
mkdir -p ~/.mozilla/firefox/signage.default
cat > ~/.mozilla/firefox/signage.default/user.js << 'EOF'
user_pref("browser.cache.disk.enable", true);
user_pref("browser.cache.disk.capacity", 1048576);
user_pref("browser.sessionstore.enabled", false);
user_pref("browser.shell.checkDefaultBrowser", false);
user_pref("browser.tabs.warnOnClose", false);
user_pref("media.autoplay.default", 0);
user_pref("full-screen-api.warning.timeout", 0);
EOF
Native Video Players
VLC for Video Signage:
# Install VLC
sudo apt install vlc
# VLC fullscreen loop playback
cvlc --fullscreen --loop --no-video-title-show \
--video-on-top --no-osd \
--rate 1.0 \
/path/to/playlist.m3u
# VLC with HTTP stream
cvlc --fullscreen --loop \
"http://content-server/stream.m3u8"
# Playlist file (playlist.m3u)
/content/video1.mp4
/content/video2.mp4
/content/video3.mp4
mpv Player (Recommended):
# Install mpv
sudo apt install mpv
# Configuration file ~/.config/mpv/mpv.conf
fullscreen=yes
loop-file=inf
no-osd-bar
no-input-default-bindings
hwdec=auto
vo=gpu
gpu-context=drm # Or x11, wayland depending on setup
# mpv playback command
mpv --fullscreen --loop-file=inf /content/video.mp4
# mpv with playlist
mpv --fullscreen --loop-playlist=inf /content/playlist.m3u
# mpv as systemd service
sudo cat > /etc/systemd/system/signage-player.service << 'EOF'
[Unit]
Description=Signage Video Player
After=graphical.target
[Service]
Environment=DISPLAY=:0
User=signage
ExecStart=/usr/bin/mpv --fullscreen --loop-playlist=inf /content/playlist.m3u
Restart=always
RestartSec=5
[Install]
WantedBy=graphical.target
EOF
Dedicated Signage Software
Xibo for Linux:
# Xibo Player for Linux
# Download from: xibo.org.uk
# Requirements
sudo apt install \
libgtk-3-0 \
libcanberra-gtk3-module \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly
# Run Xibo player
./xibo-player
info-beamer:
# Commercial Linux signage solution
# Download from: info-beamer.com
# Features:
# - Hardware accelerated
# - LUA scripting
# - Package-based content
# - Low resource usage
./info-beamer path/to/package
Kiosk Configuration
System Lockdown
# Disable virtual terminals
sudo systemctl mask getty@tty2.service
sudo systemctl mask getty@tty3.service
sudo systemctl mask getty@tty4.service
sudo systemctl mask getty@tty5.service
sudo systemctl mask getty@tty6.service
# Disable Ctrl+Alt+Del
sudo systemctl mask ctrl-alt-del.target
# Disable magic SysRq keys
echo "kernel.sysrq = 0" | sudo tee /etc/sysctl.d/99-disable-sysrq.conf
# Disable USB storage (optional)
echo "blacklist usb-storage" | sudo tee /etc/modprobe.d/disable-usb-storage.conf
# Remove unnecessary packages
sudo apt purge \
nano vim \
wget curl \
ftp telnet \
compilers gcc g++
Read-Only Filesystem
OverlayFS Setup:
# Create initramfs hook for overlayroot
sudo apt install overlayroot
# Configure overlayroot
sudo nano /etc/overlayroot.conf
overlayroot="tmpfs:swap=1,recurse=0"
# Update initramfs
sudo update-initramfs -u
# After reboot, root filesystem is read-only
# Changes are stored in RAM overlay
# Rebooting restores original state
# To make persistent changes:
sudo overlayroot-chroot
# Make changes
exit
sudo reboot
Simpler Approach - Mount Read-Only:
# Edit /etc/fstab
# Change root entry to include 'ro'
/dev/sda1 / ext4 defaults,ro,noatime 0 1
# Add tmpfs for writable areas
tmpfs /tmp tmpfs defaults,noatime,nosuid,size=100m 0 0
tmpfs /var/log tmpfs defaults,noatime,nosuid,size=100m 0 0
tmpfs /var/tmp tmpfs defaults,noatime,nosuid,size=50m 0 0
# Remount scripts
sudo cat > /usr/local/bin/rw << 'EOF'
#!/bin/bash
sudo mount -o remount,rw /
echo "Filesystem is now read-write"
EOF
sudo cat > /usr/local/bin/ro << 'EOF'
#!/bin/bash
sudo mount -o remount,ro /
echo "Filesystem is now read-only"
EOF
sudo chmod +x /usr/local/bin/{rw,ro}
Watchdog Configuration
# Enable hardware watchdog
sudo apt install watchdog
# Configure watchdog
sudo nano /etc/watchdog.conf
watchdog-device = /dev/watchdog
watchdog-timeout = 15
realtime = yes
priority = 1
max-load-1 = 24
ping = 8.8.8.8
interface = eth0
retry-timeout = 60
# Enable and start
sudo systemctl enable watchdog
sudo systemctl start watchdog
Display Configuration
X11 Display Setup
# Configure X11 display
sudo nano /etc/X11/xorg.conf.d/10-display.conf
Section "Monitor"
Identifier "HDMI-1"
Option "DPMS" "false"
EndSection
Section "Screen"
Identifier "Screen0"
Monitor "HDMI-1"
DefaultDepth 24
SubSection "Display"
Depth 24
Modes "1920x1080"
EndSubSection
EndSection
Section "ServerLayout"
Identifier "Layout0"
Screen "Screen0"
EndSection
Section "ServerFlags"
Option "BlankTime" "0"
Option "StandbyTime" "0"
Option "SuspendTime" "0"
Option "OffTime" "0"
EndSection
Multi-Display Setup
# Configure multiple displays
xrandr --output HDMI-1 --mode 1920x1080 --pos 0x0 --primary
xrandr --output HDMI-2 --mode 1920x1080 --pos 1920x0
# Or create xorg.conf for persistent multi-monitor
sudo nano /etc/X11/xorg.conf.d/20-multimonitor.conf
Section "Monitor"
Identifier "HDMI-1"
EndSection
Section "Monitor"
Identifier "HDMI-2"
Option "RightOf" "HDMI-1"
EndSection
# For video wall spanning multiple outputs
# Use nvidia-settings (NVIDIA) or amdcccle (AMD) for advanced config
Display Rotation
# Rotate display 90 degrees (portrait)
xrandr --output HDMI-1 --rotate right
# Rotate options: normal, left, right, inverted
# Permanent rotation in xorg.conf
Section "Monitor"
Identifier "HDMI-1"
Option "Rotate" "right"
EndSection
# For touch input rotation (if applicable)
xinput set-prop "Touch Device" --type=float "Coordinate Transformation Matrix" 0 1 0 -1 0 1 0 0 1
Remote Management
SSH Configuration
# Secure SSH configuration
sudo nano /etc/ssh/sshd_config
Port 22
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
X11Forwarding no
AllowUsers signage-admin
# Restrict SSH to management network
ListenAddress 10.0.0.0
# Generate SSH key pair (on admin machine)
ssh-keygen -t ed25519 -C "signage-admin"
ssh-copy-id -i ~/.ssh/id_ed25519.pub signage-admin@player
Ansible Management
# inventory.yml
all:
children:
signage_players:
hosts:
player-001:
ansible_host: 192.168.1.101
player-002:
ansible_host: 192.168.1.102
player-003:
ansible_host: 192.168.1.103
vars:
ansible_user: signage-admin
ansible_ssh_private_key_file: ~/.ssh/signage_key
# playbook-update.yml
---
- name: Update signage players
hosts: signage_players
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Upgrade packages
apt:
upgrade: safe
- name: Sync content
synchronize:
src: /content/
dest: /home/signage/content/
delete: yes
- name: Restart signage service
systemd:
name: signage-player
state: restarted
# Run: ansible-playbook -i inventory.yml playbook-update.yml
Monitoring Script
#!/bin/bash
# /usr/local/bin/signage-monitor.sh
HOSTNAME=$(hostname)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
UPTIME=$(uptime -p)
LOAD=$(cat /proc/loadavg | cut -d' ' -f1-3)
MEMORY=$(free -m | awk 'NR==2{printf "%.1f%%", $3*100/$2}')
DISK=$(df -h / | awk 'NR==2{print $5}')
TEMP=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null | awk '{printf "%.1f°C", $1/1000}')
# Check if X is running
if pgrep -x "Xorg" > /dev/null; then
DISPLAY_STATUS="running"
else
DISPLAY_STATUS="stopped"
fi
# Check if signage app is running
if pgrep -f "chromium.*kiosk" > /dev/null; then
APP_STATUS="running"
elif pgrep -f "mpv" > /dev/null; then
APP_STATUS="running"
else
APP_STATUS="stopped"
fi
# Network check
if ping -c 1 8.8.8.8 &> /dev/null; then
NETWORK_STATUS="connected"
else
NETWORK_STATUS="disconnected"
fi
# Output JSON for monitoring system
cat << EOF
{
"hostname": "$HOSTNAME",
"timestamp": "$TIMESTAMP",
"uptime": "$UPTIME",
"load": "$LOAD",
"memory": "$MEMORY",
"disk": "$DISK",
"temperature": "$TEMP",
"display": "$DISPLAY_STATUS",
"app": "$APP_STATUS",
"network": "$NETWORK_STATUS"
}
EOF
# Post to monitoring endpoint
curl -s -X POST \
-H "Content-Type: application/json" \
-d @- \
https://monitoring.yourcompany.com/api/signage/heartbeat << EOF
{
"hostname": "$HOSTNAME",
"status": "$APP_STATUS",
"load": "$LOAD",
"memory": "$MEMORY"
}
EOF
Security Hardening
Firewall Configuration
# Install and configure UFW
sudo apt install ufw
# Default deny incoming
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH from management network only
sudo ufw allow from 10.0.0.0/24 to any port 22
# Allow signage CMS traffic (adjust ports as needed)
sudo ufw allow out 80/tcp
sudo ufw allow out 443/tcp
# Enable firewall
sudo ufw enable
sudo ufw status verbose
AppArmor Profiles
# Install AppArmor
sudo apt install apparmor apparmor-utils
# Create profile for Chromium
sudo aa-genprof chromium-browser
# Run chromium, exercise all features
# Press S to scan for changes
# Press F to finish
# Enable profile
sudo aa-enforce /etc/apparmor.d/usr.bin.chromium-browser
Automatic Updates
# Install unattended-upgrades
sudo apt install unattended-upgrades
# Configure automatic security updates
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
# Enable
sudo dpkg-reconfigure -plow unattended-upgrades
Troubleshooting
Common Issues
No display output:
# Check X log
cat /var/log/Xorg.0.log | grep EE
# Verify display detection
xrandr --query
# Check DRM devices
ls -la /dev/dri/
# Force HDMI output
echo "options drm_kms_helper poll=N" | sudo tee /etc/modprobe.d/drm.conf
Video playback issues:
# Check hardware acceleration
vainfo # VA-API
vdpauinfo # VDPAU
# Install missing codecs
sudo apt install \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
ffmpeg
# Check video card driver
lspci -k | grep -A 3 VGA
Network connectivity:
# Check interface status
ip link show
# Check IP configuration
ip addr show
# Test DNS resolution
nslookup your-cms-server.com
# Check routing
ip route show
# Test connectivity
ping -c 4 your-cms-server.com
curl -I https://your-cms-server.com
Frequently Asked Questions
Linux provides a powerful, flexible foundation for digital signage of any scale. For signage CMS software with Linux player support, explore the SignageStudio platform or contact MediaSignage for enterprise solutions.