mirror of
https://github.com/screentinker/screentinker.git
synced 2026-05-15 07:32:23 -06:00
Old invite replaced with current permanent invite across README, landing page, and anywhere else it appeared. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
197 lines
11 KiB
HTML
197 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Self-Hosted Digital Signage Software - Complete Guide (2026) | ScreenTinker</title>
|
|
<meta name="description" content="Why and how to self-host your digital signage CMS. Data privacy, cost control, and no recurring fees. Complete deployment guide using ScreenTinker - open source, MIT licensed.">
|
|
<meta name="keywords" content="self hosted digital signage, on premise digital signage, self hosted signage cms, open source signage server, deploy signage on premise, private digital signage">
|
|
<meta name="robots" content="index, follow">
|
|
<link rel="canonical" href="https://screentinker.com/guides/self-hosted-digital-signage.html">
|
|
|
|
<meta property="og:type" content="article">
|
|
<meta property="og:url" content="https://screentinker.com/guides/self-hosted-digital-signage.html">
|
|
<meta property="og:title" content="Self-Hosted Digital Signage Software - Complete Guide (2026)">
|
|
<meta property="og:description" content="Why and how to self-host your digital signage CMS. Data privacy, cost control, no recurring fees.">
|
|
<meta property="og:image" content="https://screentinker.com/assets/dashboard-preview.png">
|
|
<meta property="og:site_name" content="ScreenTinker">
|
|
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:title" content="Self-Hosted Digital Signage Software - Complete Guide (2026)">
|
|
<meta name="twitter:description" content="Why and how to self-host your digital signage CMS. Data privacy, cost control, no recurring fees.">
|
|
<meta name="twitter:image" content="https://screentinker.com/assets/dashboard-preview.png">
|
|
|
|
<meta name="theme-color" content="#111827">
|
|
<link rel="icon" href="/assets/icon-192.png">
|
|
<link rel="apple-touch-icon" href="/assets/icon-192.png">
|
|
<link rel="stylesheet" href="/css/seo-page.css">
|
|
</head>
|
|
<body>
|
|
<nav>
|
|
<div class="nav-inner">
|
|
<div class="nav-logo">
|
|
<a href="/" style="display:flex;align-items:center;gap:10px">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
|
<span class="nav-logo-text">ScreenTinker</span>
|
|
</a>
|
|
</div>
|
|
<div class="nav-links">
|
|
<a href="/#features">Features</a>
|
|
<a href="/#pricing">Pricing</a>
|
|
<a href="/#compare">Compare</a>
|
|
<a href="/app#/login" class="btn btn-outline" style="margin-left:16px">Sign In</a>
|
|
<a href="/app#/login" class="btn btn-primary" style="margin-left:8px">Try Free</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="article">
|
|
<nav class="breadcrumb" aria-label="Breadcrumb">
|
|
<a href="/">Home</a>
|
|
<span>/</span>
|
|
<a href="/#features">Guides</a>
|
|
<span>/</span>
|
|
<span>Self-Hosted Digital Signage</span>
|
|
</nav>
|
|
|
|
<h1>Self-Hosted Digital Signage Software: Complete Guide (2026)</h1>
|
|
<p class="lead">Why you might want to self-host your digital signage CMS, what you need to do it well, and how to deploy ScreenTinker on your own server.</p>
|
|
|
|
<h2>Why self-host digital signage?</h2>
|
|
<p>Most digital signage products are cloud-only. That works for many businesses, but there are real reasons to keep the server in-house:</p>
|
|
<ul>
|
|
<li><strong>Data sovereignty.</strong> Healthcare, finance, government, and education often cannot put internal information into a third-party cloud. Self-hosting keeps content, schedules, and access logs on your network.</li>
|
|
<li><strong>Cost control.</strong> Per-screen monthly fees stack up fast. Self-hosting trades that for a fixed server cost - typically $5 to $50 per month for a small VPS that can run hundreds of screens.</li>
|
|
<li><strong>Network isolation.</strong> Some deployments live on private LANs with no internet access at all. Self-hosting is the only way to manage signage in those environments.</li>
|
|
<li><strong>No vendor lock-in.</strong> If the cloud vendor disappears, raises prices 3x, or pivots away from your use case, your deployment goes with them. Self-hosters control their own roadmap.</li>
|
|
<li><strong>Customization.</strong> Open source self-hosted means you can fork the code, add a custom widget, or wire it into your existing systems.</li>
|
|
</ul>
|
|
|
|
<h2>What you need</h2>
|
|
<h3>Hardware / VPS</h3>
|
|
<p>A modest Linux server is enough for most deployments:</p>
|
|
<ul>
|
|
<li><strong>Up to 25 displays:</strong> 1 vCPU, 1 GB RAM, 20 GB disk. ~$5/month on Hetzner, DigitalOcean, or Vultr.</li>
|
|
<li><strong>25-100 displays:</strong> 2 vCPU, 2 GB RAM, 40 GB disk. ~$12-20/month.</li>
|
|
<li><strong>100+ displays:</strong> 4+ vCPU, 4+ GB RAM, faster disk. Plan for content storage at ~50-200 MB per screen depending on media volume.</li>
|
|
</ul>
|
|
<p>An on-prem VM works just as well as a cloud VPS - in fact, on-prem is often the whole point.</p>
|
|
|
|
<h3>Software prerequisites</h3>
|
|
<ul>
|
|
<li>Ubuntu 22.04 or 24.04 LTS (Debian 12 also works)</li>
|
|
<li>Node.js 18 or newer</li>
|
|
<li>A domain name pointed at your server (or just an internal hostname / IP for LAN deployments)</li>
|
|
<li>SSL certificate (Let's Encrypt is free; or self-signed for LAN)</li>
|
|
</ul>
|
|
|
|
<h2>Deploying ScreenTinker</h2>
|
|
<p>Detailed setup is in the <a href="https://github.com/screentinker/screentinker" target="_blank" rel="noopener">GitHub README</a>. Quick version:</p>
|
|
<pre><code>git clone https://github.com/screentinker/screentinker.git
|
|
cd screentinker/server
|
|
npm install
|
|
cp .env.example .env
|
|
# edit .env with your domain, JWT_SECRET, and SELF_HOSTED=true
|
|
node server.js</code></pre>
|
|
<p>Set <code>SELF_HOSTED=true</code> in the env. This unlocks the enterprise plan for your account, disables subscription expiry checks, and skips Stripe entirely. It is meant for the operator-controlled deployment case.</p>
|
|
|
|
<h2>Reverse proxy and TLS</h2>
|
|
<p>ScreenTinker listens on HTTP/HTTPS directly, but in production you typically front it with nginx or Caddy for TLS termination, gzip, and rate limiting. A minimal Caddyfile:</p>
|
|
<pre><code>signage.example.com {
|
|
reverse_proxy localhost:3001
|
|
}</code></pre>
|
|
<p>Caddy handles Let's Encrypt automatically. nginx works too if your team prefers it.</p>
|
|
|
|
<h2>Running as a service</h2>
|
|
<p>Use systemd to keep the process alive across reboots. A unit file at <code>/etc/systemd/system/screentinker.service</code>:</p>
|
|
<pre><code>[Unit]
|
|
Description=ScreenTinker Digital Signage Server
|
|
After=network.target
|
|
|
|
[Service]
|
|
WorkingDirectory=/opt/screentinker/server
|
|
ExecStart=/usr/bin/node server.js
|
|
EnvironmentFile=/opt/screentinker/.env
|
|
Restart=always
|
|
User=screentinker
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target</code></pre>
|
|
<p>Enable with <code>systemctl enable --now screentinker</code>.</p>
|
|
|
|
<h2>Backups</h2>
|
|
<p>The state lives in two places:</p>
|
|
<ul>
|
|
<li><code>server/db/remote_display.db</code> - SQLite database of users, devices, playlists, schedules</li>
|
|
<li><code>server/uploads/</code> - uploaded media (images, videos, thumbnails)</li>
|
|
</ul>
|
|
<p>A nightly tarball of those two paths gives you a full restore point. Pair with offsite sync (rclone, restic) for disaster recovery.</p>
|
|
|
|
<h2>Self-hosted vs cloud-hosted comparison</h2>
|
|
<div class="compare-table-wrap">
|
|
<table class="compare-table">
|
|
<thead>
|
|
<tr><th>Concern</th><th>ScreenTinker self-hosted</th><th>Cloud-only signage products</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>Data location</td><td>Your server</td><td>Vendor's cloud</td></tr>
|
|
<tr><td>Recurring per-screen cost</td><td>None</td><td>$5-15/screen/month</td></tr>
|
|
<tr><td>Server cost</td><td>$5-50/month flat</td><td>None (included)</td></tr>
|
|
<tr><td>Internet required for management</td><td>No (LAN works)</td><td>Yes</td></tr>
|
|
<tr><td>Source code access</td><td>Yes (MIT)</td><td>Closed</td></tr>
|
|
<tr><td>Air-gapped deployment</td><td>Possible</td><td>Not possible</td></tr>
|
|
<tr><td>Vendor lock-in risk</td><td>None (you own it)</td><td>High</td></tr>
|
|
<tr><td>Update / patch responsibility</td><td>Yours</td><td>Vendor</td></tr>
|
|
<tr><td>Initial setup time</td><td>~1 hour</td><td>~5 minutes</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h2>When the cloud is the right answer</h2>
|
|
<p>Self-hosting is not free of cost - it requires someone who can run a Linux server, monitor it, and apply security updates. If your screen count is small (under ~10) and you do not have IT capacity, the managed cloud version is probably the right choice. ScreenTinker's hosted plans start at $39/mo for 5 devices.</p>
|
|
|
|
<div class="related">
|
|
<h2>Related guides</h2>
|
|
<ul>
|
|
<li><a href="/guides/raspberry-pi-digital-signage.html">How to set up digital signage on a Raspberry Pi</a></li>
|
|
<li><a href="/guides/digital-signage-android-tv.html">Free digital signage for Android TV and Fire TV</a></li>
|
|
<li><a href="/compare/yodeck-alternative.html">Compare: ScreenTinker vs Yodeck</a></li>
|
|
<li><a href="/compare/screencloud-alternative.html">Compare: ScreenTinker vs ScreenCloud</a></li>
|
|
<li><a href="/compare/optisigns-alternative.html">Compare: ScreenTinker vs OptiSigns</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="cta">
|
|
<h2>Try the cloud version first</h2>
|
|
<p>Use the hosted version to get familiar, then deploy on your own server when you are ready.</p>
|
|
<a href="/app#/login" class="btn btn-primary" style="padding:14px 28px;font-size:16px">Start Free</a>
|
|
<a href="https://github.com/screentinker/screentinker" target="_blank" rel="noopener" class="btn btn-outline" style="padding:14px 28px;font-size:16px;margin-left:12px">View on GitHub</a>
|
|
</div>
|
|
</main>
|
|
|
|
<footer>
|
|
<div style="color:var(--dim);font-size:13px">© 2026 ScreenTinker. All rights reserved.</div>
|
|
<div class="links">
|
|
<a href="https://github.com/screentinker/screentinker" target="_blank" rel="noopener">GitHub</a>
|
|
<a href="https://discord.gg/utTdsrqq4Z" target="_blank" rel="noopener">Discord</a>
|
|
<a href="/legal/terms.html">Terms</a>
|
|
<a href="/legal/privacy.html">Privacy</a>
|
|
<a href="/legal/third-party.html">Licenses</a>
|
|
<a href="/app#/login">Sign In</a>
|
|
</div>
|
|
</footer>
|
|
|
|
<script type="application/ld+json">
|
|
{
|
|
"@context": "https://schema.org",
|
|
"@type": "BreadcrumbList",
|
|
"itemListElement": [
|
|
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://screentinker.com/" },
|
|
{ "@type": "ListItem", "position": 2, "name": "Guides", "item": "https://screentinker.com/#features" },
|
|
{ "@type": "ListItem", "position": 3, "name": "Self-Hosted Digital Signage", "item": "https://screentinker.com/guides/self-hosted-digital-signage.html" }
|
|
]
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|