<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Updates – Serverküche</title><link>https://serverkueche.de/en/tags/updates/</link><description>Updates – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>en-US</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Sat, 18 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/en/tags/updates/index.xml" rel="self" type="application/rss+xml"/><item><title>unattended-upgrades: automatic security updates for Debian</title><link>https://serverkueche.de/en/tutorials/unattended-upgrades-automatic-updates/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/en/tutorials/unattended-upgrades-automatic-updates/</guid><description>Debian installs security updates automatically: set up unattended-upgrades, control the reboot, and verify it really runs.</description><content:encoded><![CDATA[<p>&ldquo;Remember to install updates weekly&rdquo; – this sentence from the maintenance sections of
the other tutorials is the first one people forget. That&rsquo;s exactly why the server now
takes it over itself: <strong>unattended-upgrades</strong> installs security updates automatically.
That closes the most dangerous gap in self-hosting – the server that runs unpatched for
months.</p>
<h2 id="what-are-we-building">What are we building?</h2>
<p>By the end, your <strong>Debian 13</strong> automatically pulls <strong>security updates</strong> daily and
installs them without your involvement. You decide whether and when the server reboots
for necessary kernel updates, and you know how to verify that the automation really
kicks in. What gets automated are security updates and the conservative stable point
releases; larger upgrades of your other software stay deliberately in your hands.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>A <a href="/en/tutorials/harden-ssh/">hardened server</a> with an
<a href="/en/tutorials/firewall-ufw-setup/">active firewall</a></li>
</ul>
<h2 id="step-by-step">Step by step</h2>
<h3 id="step-1-install-the-package">Step 1: Install the package</h3>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">sudo apt install -y unattended-upgrades apt-listchanges</span></span></code></pre></div>
</div>
<p><code>apt-listchanges</code> shows the changelogs on updates – useful if you later do check
manually what changed.</p>
<h3 id="step-2-enable-the-automation">Step 2: Enable the automation</h3>
<p>The simplest way to switch on the daily run:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo dpkg-reconfigure -plow unattended-upgrades</span></span></code></pre></div>
</div>
<p>Choose <strong>Yes</strong> in the dialog. That creates the file
<code>/etc/apt/apt.conf.d/20auto-upgrades</code> with this content:</p>
<div class="sk-code">
  <span class="sk-code-head">INI</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">APT::Periodic::Update-Package-Lists &#34;1&#34;;</span>
</span></span><span class="line"><span class="cl"><span class="na">APT::Periodic::Unattended-Upgrade &#34;1&#34;;</span></span></span></code></pre></div>
</div>
<p>The <code>1</code> means &ldquo;daily&rdquo;: update package lists <strong>and</strong> run unattended upgrades. It&rsquo;s
triggered via the systemd timers <code>apt-daily.timer</code> (package lists) and
<code>apt-daily-upgrade.timer</code> (upgrade run) – no separate cron job needed.</p>
<h3 id="step-3-define-what-gets-updated">Step 3: Define what gets updated</h3>
<p>Take a look at <code>/etc/apt/apt.conf.d/50unattended-upgrades</code>:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo nano /etc/apt/apt.conf.d/50unattended-upgrades</span></span></code></pre></div>
</div>
<p>On Debian 13, <strong>three</strong> sources are active in the <code>Origins-Pattern</code> block by default:</p>
<div class="sk-code">
  <span class="sk-code-head">INI</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">Unattended-Upgrade::Origins-Pattern {</span>
</span></span><span class="line"><span class="cl">  <span class="na">&#34;origin</span><span class="o">=</span><span class="s">Debian,codename=${distro_codename},label=Debian&#34;;
</span></span></span><span class="line"><span class="cl"><span class="s">  &#34;origin=Debian,codename=${distro_codename},label=Debian-Security&#34;;
</span></span></span><span class="line"><span class="cl"><span class="s">  &#34;origin=Debian,codename=${distro_codename}-security,label=Debian-Security&#34;;</span>
</span></span><span class="line"><span class="cl"><span class="na">};</span></span></span></code></pre></div>
</div>
<p>The two <code>Debian-Security</code> lines ensure <strong>timely security updates</strong> – the actual
purpose. The first line (<code>label=Debian</code>) covers the <strong>conservative stable updates</strong>
that only arrive with Debian point releases; so it&rsquo;s not a risky rolling update, but
well-seasoned. If you really want <strong>only</strong> security updates, comment out the first line
with <code>//</code>.</p>
<p>Two options are worth setting explicitly here. <strong>Clean up old kernels/packages
automatically</strong>, otherwise <code>/boot</code> eventually fills up (<code>Remove-Unused-Kernel-Packages</code>
is already the default in code, but only appears commented out in the file – set
explicitly, the decision is documented):</p>
<div class="sk-code">
  <span class="sk-code-head">INI</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">Unattended-Upgrade::Remove-Unused-Kernel-Packages &#34;true&#34;;</span>
</span></span><span class="line"><span class="cl"><span class="na">Unattended-Upgrade::Remove-Unused-Dependencies &#34;true&#34;;</span></span></span></code></pre></div>
</div>
<p>And the most important point – the <strong>automatic reboot</strong>:</p>
<div class="sk-code">
  <span class="sk-code-head">INI</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">Unattended-Upgrade::Automatic-Reboot &#34;true&#34;;</span>
</span></span><span class="line"><span class="cl"><span class="na">Unattended-Upgrade::Automatic-Reboot-Time &#34;04:00&#34;;</span></span></span></code></pre></div>
</div>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>Automatic reboot – decide deliberately
  </p>
  <div class="prose-kitchen text-sm">Some security updates (especially kernel) only take effect after a reboot. With
<code>Automatic-Reboot &quot;true&quot;</code> the server then reboots on its own – <strong>always set an
<code>Automatic-Reboot-Time</code></strong> when you do: without it, the server reboots <strong>immediately</strong>
after the upgrade run (the code default is <code>&quot;now&quot;</code>; the <code>02:00</code> in the example file is
only a commented-out suggestion). Choose a time with low usage. If you want <strong>no</strong>
automatic reboots, leave the option at <code>&quot;false&quot;</code> and reboot yourself when
<code>/var/run/reboot-required</code> exists. Both are defensible – it just has to be a deliberate
decision.</div>
</div>
<p>For the automatic reboot to be able to trigger on Debian at all, one building block is
still missing: unattended-upgrades only reboots if the marker file
<code>/var/run/reboot-required</code> exists – and Debian 13 does <strong>not</strong> create it on kernel
updates by default (the responsible hook comes from an Ubuntu helper package that
doesn&rsquo;t exist in Debian; only individual packages like <code>dbus</code> set the file themselves).
A two-liner closes the gap:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo tee /etc/kernel/postinst.d/zz-reboot-required &gt; /dev/null <span class="s">&lt;&lt;&#39;EOF&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">#!/bin/sh
</span></span></span><span class="line"><span class="cl"><span class="s">touch /var/run/reboot-required
</span></span></span><span class="line"><span class="cl"><span class="s">EOF</span>
</span></span><span class="line"><span class="cl">sudo chmod +x /etc/kernel/postinst.d/zz-reboot-required</span></span></code></pre></div>
</div>
<p>The hook runs after every kernel installation and sets the marker file. From now on,
both <code>Automatic-Reboot</code> and the manual check of <code>/var/run/reboot-required</code> work
reliably – without the hook, the automatic reboot would simply never trigger on kernel
updates.</p>
<h3 id="step-4-do-a-dry-run">Step 4: Do a dry run</h3>
<p>Test what unattended-upgrades would do, without a real installation:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo unattended-upgrade --dry-run --debug</span></span></code></pre></div>
</div>
<p>In the debug output, this line is decisive (on a fresh Debian 13, shortened):</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Allowed origins are: origin=Debian,codename=trixie,label=Debian, origin=Debian,codename=trixie,label=Debian-Security, origin=Debian,codename=trixie-security,label=Debian-Security
</span></span><span class="line"><span class="cl">[...]
</span></span><span class="line"><span class="cl">No packages found that can be upgraded unattended and no pending auto-removals</span></span></code></pre></div>
</div>
<p>The Debian-Security sources must appear there. If something is listed, the
configuration applies; if the run finds nothing to do (as above), there&rsquo;s simply no
security update pending right now.</p>
<h2 id="when-things-go-wrong">When things go wrong</h2>
<div class="troubleshoot not-prose">
<p><strong>The dry run reports <code>No packages found that can be upgraded unattended</code>.</strong> Usually
perfectly normal – no security update is currently pending. Check the configuration
anyway via the <code>Allowed origins are:</code> line in the <code>--debug</code> run. If no security origins
appear there, the <code>Origins-Pattern</code> from step 3 isn&rsquo;t right.</p>
<p><strong>Updates come, but the server never reboots despite a kernel update.</strong> Either
<code>Automatic-Reboot</code> is set to <code>&quot;false&quot;</code> (default) – then set it to <code>&quot;true&quot;</code> (step 3) –
or the marker file is never set because the kernel hook
<code>/etc/kernel/postinst.d/zz-reboot-required</code> from step 3 is missing. Without it, Debian
doesn&rsquo;t create <code>/var/run/reboot-required</code> on kernel updates, and the automatic reboot
never triggers.</p>
<p><strong><code>/boot</code> fills up, updates fail.</strong> Old kernels pile up. Set
<code>Remove-Unused-Kernel-Packages &quot;true&quot;</code> (step 3); clean up once with <code>sudo apt autoremove --purge</code>.</p>
<p><strong>A package is stubbornly held back (<code>kept back</code>).</strong> unattended-upgrades doesn&rsquo;t
install updates that would remove other packages. You resolve such cases deliberately
by hand with <code>sudo apt upgrade</code> and check what happens.</p>

</div>

<h2 id="maintenance--backups">Maintenance &amp; backups</h2>
<ul>
<li><strong>Still check anyway:</strong> automation doesn&rsquo;t replace attention. Take a monthly look at
the log <code>/var/log/unattended-upgrades/unattended-upgrades.log</code> and occasionally run
<code>sudo apt update &amp;&amp; sudo apt upgrade</code> for the <strong>non</strong>-security-critical updates.</li>
<li><strong>Plan for reboots:</strong> if you use automatic reboots, make sure your services survive a
reboot cleanly (<code>restart: unless-stopped</code> in <a href="/en/tutorials/docker-compose-basics/">Docker
Compose</a> if you run containers).</li>
<li><strong>No dedicated backup needed</strong>, but note whether you enabled automatic reboots – it
later explains why the server was briefly gone at night.</li>
</ul>
]]></content:encoded></item></channel></rss>