<?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>Journal – Serverküche</title><link>https://serverkueche.de/en/tags/journal/</link><description>Journal – 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>Thu, 03 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/en/tags/journal/index.xml" rel="self" type="application/rss+xml"/><item><title>Understanding systemd: Units, Journal &amp; Timers (instead of Cron)</title><link>https://serverkueche.de/en/tutorials/systemd-basics/</link><pubDate>Thu, 03 Sep 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/en/tutorials/systemd-basics/</guid><description>Start services, read logs, schedule tasks: this foundational guide explains systemd with real commands – including your own service and a timer instead of cron.</description><content:encoded><![CDATA[<p>Every service on your server – SSH, Docker, the firewall – is started, supervised and logged by systemd. Understanding systemd lets you diagnose outages, create your own background jobs and automate scheduled tasks cleanly. This guide gets you comfortable with it.</p>
<h2 id="what-are-we-building">What are we building?</h2>
<p>Not a service, but the tool <em>every</em> service runs on: <strong>systemd</strong> (here v257 on Debian 13). By the end you can start, stop and enable services at boot, read their logs with <code>journalctl</code>, create your <strong>own service</strong> as a unit file and build a <strong>timer</strong> that replaces cron – with the key advantage that it can catch up on missed runs.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>A Linux server with systemd (any modern Debian/Ubuntu – your <a href="/en/tutorials/first-steps-netcup-vps/">netcup VPS</a>)</li>
<li>Root or <code>sudo</code> access (see <a href="/en/tutorials/linux-users-and-permissions/">Users &amp; permissions</a>)</li>
<li>Familiarity with the <a href="/en/tutorials/essential-terminal-commands/">essential terminal commands</a></li>
</ul>
<div class="not-prose my-6 overflow-hidden rounded-xl border border-paprika-200 bg-paprika-50 dark:border-paprika-800 dark:bg-paprika-900/20"
     data-track-content data-content-name="Affiliate-Box · /en/tutorials/systemd-basics/" data-content-piece="VPS 1000 G12">
  <div class="flex items-center justify-between border-b border-paprika-200 bg-paprika-100 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-paprika-700 dark:border-paprika-800 dark:bg-paprika-900/40 dark:text-paprika-300">
    <span>🍳 Recommendation</span>
    <span title="Links marked with * are affiliate links.">Ad</span>
  </div>
  <div class="flex flex-col gap-4 p-4 sm:flex-row sm:items-center sm:justify-between">
    <div>
      <p class="text-lg font-bold text-slate-900 dark:text-white">VPS 1000 G12</p>
      <p class="mt-1 text-sm text-slate-600 dark:text-slate-300">4 vCores · 8 GB RAM · 256 GB NVMe</p>
      <p class="mt-1 text-sm font-semibold text-paprika-700 dark:text-paprika-400">from €10.36/month</p>
      <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">The commands are the same on any systemd Linux – any server will do.</p>
    </div>
    <a href="https://www.netcup.com/en/server/vps/vps-1000-g12-iv-12m?ref=44083" rel="sponsored noopener" target="_blank"
   data-track-event="Affiliate|netcup: Affiliate-Box|VPS 1000 G12 · {page}"
   class="inline-flex shrink-0 items-center justify-center rounded-lg bg-paprika-600 px-5 py-2.5 font-semibold text-white transition-colors hover:bg-paprika-700">
  Go to netcup →
</a>

  </div><div class="px-4 pb-4"><p class="not-prose my-3 flex flex-wrap items-center gap-x-2 gap-y-1 rounded-lg border border-herb-500/40 bg-herb-50 px-3 py-2 text-sm text-slate-700 dark:bg-herb-900/20 dark:text-slate-200">
  <span>💶 <strong>5 € voucher</strong> for new netcup customers:</span><code data-track-voucher="36nc17844976032"
        class="rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 dark:bg-slate-800 dark:text-herb-400">36nc17844976032</code>
  <span class="text-xs text-slate-500 dark:text-slate-400">(new customers only, no domains)</span>
</p></div>
</div>

<h2 id="step-by-step">Step by step</h2>
<h3 id="step-1-units--the-core-concept">Step 1: Units – the core concept</h3>
<p>systemd manages everything as <strong>units</strong>. The most important kind is the <strong>service</strong> (<code>.service</code>) – a background daemon. There are also <strong>timers</strong> (<code>.timer</code>, scheduled execution), <strong>sockets</strong> and <strong>targets</strong> (groups, roughly comparable to runlevels). First check which version is running:</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">systemctl --version</span></span></code></pre></div>
</div>
<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">systemd 257 (257.13-1~deb13u1)</span></span></code></pre></div>
</div>
<p><code>systemctl</code> shows all running services:</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">systemctl list-units --type<span class="o">=</span>service --state<span class="o">=</span>running</span></span></code></pre></div>
</div>
<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">  containerd.service   loaded active running containerd container runtime
</span></span><span class="line"><span class="cl">  cron.service         loaded active running Regular background program processing daemon
</span></span><span class="line"><span class="cl">  docker.service       loaded active running Docker Application Container Engine
</span></span><span class="line"><span class="cl">  fail2ban.service     loaded active running Fail2Ban Service
</span></span><span class="line"><span class="cl">  ssh.service          loaded active running OpenBSD Secure Shell server</span></span></code></pre></div>
</div>
<p>Each line is a unit with load state (<code>loaded</code>), active state (<code>active</code>) and sub-state (<code>running</code>).</p>
<h3 id="step-2-controlling-services">Step 2: Controlling services</h3>
<p>The most important command is <code>systemctl status</code>. It shows you everything about a service – using Docker as an example:</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">systemctl status docker</span></span></code></pre></div>
</div>
<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">● docker.service - Docker Application Container Engine
</span></span><span class="line"><span class="cl">     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
</span></span><span class="line"><span class="cl">     Active: active (running) since Sun 2026-07-19 21:34:42 CEST; 4 days ago
</span></span><span class="line"><span class="cl">   Main PID: 53379 (dockerd)
</span></span><span class="line"><span class="cl">      Tasks: 93
</span></span><span class="line"><span class="cl">     Memory: 282.8M (peak: 334.6M)</span></span></code></pre></div>
</div>
<p>Two lines matter: <code>Active:</code> (is the service running right now?) and, in the <code>Loaded:</code> line, the word <code>enabled</code> (does it start automatically at boot?). These are two <strong>independent</strong> things – a service can run but not start at boot, and vice versa. For scripts you query both concisely:</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">systemctl is-active docker
</span></span><span class="line"><span class="cl">systemctl is-enabled docker</span></span></code></pre></div>
</div>
<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">active
</span></span><span class="line"><span class="cl">enabled</span></span></code></pre></div>
</div>
<p>The four everyday commands: <code>systemctl start SERVICE</code> (start now), <code>stop</code> (stop now), <code>restart</code> (restart, e.g. after a config change) and <code>reload</code> (re-read the config without interrupting the service – if it supports that). <strong>Important:</strong> <code>start</code>/<code>stop</code> only last until the next reboot. For a service to <em>permanently</em> start at boot, you need <code>enable</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">systemctl <span class="nb">enable</span> --now SERVICE</span></span></code></pre></div>
</div>
<p><code>enable</code> turns on autostart, <code>--now</code> additionally starts the service right away – saving you the separate <code>start</code>.</p>
<h3 id="step-3-reading-logs-with-journalctl">Step 3: Reading logs with journalctl</h3>
<p>systemd collects the output of all services centrally in the <strong>journal</strong>. Instead of hunting through scattered log files, you query a specific service:</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">journalctl -u docker -n <span class="m">20</span></span></span></code></pre></div>
</div>
<p><code>-u</code> selects the unit, <code>-n 20</code> shows the last 20 lines. The most useful variants:</p>
<ul>
<li><code>journalctl -u SERVICE -f</code> – follow live (like <code>tail -f</code>), ideal for debugging.</li>
<li><code>journalctl -u SERVICE --since &quot;1 hour ago&quot;</code> – narrow by time.</li>
<li><code>journalctl -p err -b</code> – only errors since the last boot (<code>-b</code> = current boot).</li>
</ul>
<p>This is exactly the first move when a service won&rsquo;t start: <code>systemctl status SERVICE</code> for the overview, then <code>journalctl -u SERVICE</code> for the details.</p>
<h3 id="step-4-creating-your-own-service">Step 4: Creating your own service</h3>
<p>Now you build a unit yourself. Example: a backup script for systemd to run. Unit files for your own services live in <code>/etc/systemd/system/</code>. Create <code>backup-demo.service</code>:</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="k">[Unit]</span>
</span></span><span class="line"><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">Demo backup job</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Service]</span>
</span></span><span class="line"><span class="cl"><span class="na">Type</span><span class="o">=</span><span class="s">oneshot</span>
</span></span><span class="line"><span class="cl"><span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/bin/bash -c &#39;echo &#34;Backup ran at $(date)&#34; &gt;&gt; /var/log/backup-demo.log&#39;</span></span></span></code></pre></div>
</div>
<p>The <code>[Unit]</code> section describes the unit, <code>[Service]</code> says <em>what</em> should run. <code>Type=oneshot</code> is the type for one-off tasks that start, do their work and exit (unlike long-running daemons like <code>docker</code>). After creating a new unit, systemd has to read it in:</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">systemctl daemon-reload
</span></span><span class="line"><span class="cl">systemctl start backup-demo.service</span></span></code></pre></div>
</div>
<p>Check the result – <code>oneshot</code> services correctly show <code>inactive (dead)</code> after doing their work:</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">systemctl status backup-demo.service</span></span></code></pre></div>
</div>
<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">○ backup-demo.service - Demo backup job
</span></span><span class="line"><span class="cl">     Loaded: loaded (/etc/systemd/system/backup-demo.service; static)
</span></span><span class="line"><span class="cl">     Active: inactive (dead)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">systemd[1]: Starting backup-demo.service - Demo backup job...
</span></span><span class="line"><span class="cl">systemd[1]: backup-demo.service: Deactivated successfully.
</span></span><span class="line"><span class="cl">systemd[1]: Finished backup-demo.service - Demo backup job.</span></span></code></pre></div>
</div>
<h3 id="step-5-timers-instead-of-cron">Step 5: Timers instead of cron</h3>
<p>To make the job run regularly, you couple it to a <strong>timer</strong> – the systemd alternative to cron. Create <code>backup-demo.timer</code> (same name as the service, different extension):</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="k">[Unit]</span>
</span></span><span class="line"><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">Runs the demo backup daily</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Timer]</span>
</span></span><span class="line"><span class="cl"><span class="na">OnCalendar</span><span class="o">=</span><span class="s">*-*-* 03:00:00</span>
</span></span><span class="line"><span class="cl"><span class="na">Persistent</span><span class="o">=</span><span class="s">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Install]</span>
</span></span><span class="line"><span class="cl"><span class="na">WantedBy</span><span class="o">=</span><span class="s">timers.target</span></span></span></code></pre></div>
</div>
<p><code>OnCalendar</code> sets the schedule (here: daily at 03:00). <code>Persistent=true</code> is the key advantage over cron: if the server was off at the scheduled time, systemd catches up on the run at the next start – so a missed backup doesn&rsquo;t simply get skipped. Enable the timer:</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">systemctl daemon-reload
</span></span><span class="line"><span class="cl">systemctl <span class="nb">enable</span> --now backup-demo.timer</span></span></code></pre></div>
</div>
<p>All active timers and their next run are shown by:</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">systemctl list-timers</span></span></code></pre></div>
</div>
<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">NEXT                        LEFT  UNIT                ACTIVATES
</span></span><span class="line"><span class="cl">Sat 2026-07-25 03:00:00 CEST 7h   backup-demo.timer   backup-demo.service</span></span></code></pre></div>
</div>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Test OnCalendar expressions
  </p>
  <div class="prose-kitchen text-sm">Before activating a complicated schedule, check it with <code>systemd-analyze calendar &quot;Mon *-*-* 09:00:00&quot;</code> – this shows the next execution times without starting anything. That way you avoid timers that never fire or fire at the wrong time.</div>
</div>
<p>This exact pattern – a <code>oneshot</code> service plus timer – is what Serverküche&rsquo;s <a href="/en/tutorials/restic-backups/">Restic backups</a> use. You now hold the tool for any recurring maintenance task.</p>
<h2 id="when-things-go-wrong">When things go wrong</h2>
<div class="troubleshoot not-prose">
<p><strong><code>systemctl start</code> fails, the service is immediately <code>dead</code> again.</strong> Read the details with <code>journalctl -u SERVICE -n 30</code>. For your own units the most common cause is a wrong path in <code>ExecStart</code> – the command must use an <strong>absolute path</strong> (<code>/usr/bin/bash</code>, not <code>bash</code>).</p>
<p><strong>&ldquo;Unit changed on disk, run daemon-reload&rdquo;.</strong> You edited a unit file, but systemd doesn&rsquo;t pick up changes automatically. After <em>every</em> change under <code>/etc/systemd/system/</code>: <code>systemctl daemon-reload</code>.</p>
<p><strong>The timer doesn&rsquo;t show up in <code>list-timers</code>.</strong> It wasn&rsquo;t enabled. <code>systemctl enable --now SERVICE.timer</code> – and remember the timer triggers the <em>service</em>, so you need both files (<code>.service</code> <strong>and</strong> <code>.timer</code>).</p>
<p><strong><code>enable</code> says &ldquo;static&rdquo;.</strong> The unit is missing the <code>[Install]</code> section with <code>WantedBy=</code>. Without it systemd doesn&rsquo;t know when to start the unit automatically – for timers it needs <code>WantedBy=timers.target</code>.</p>
<p><strong>The journal is huge / eats disk.</strong> By default it grows in bounds, but you can trim it: <code>journalctl --vacuum-time=14d</code> deletes entries older than 14 days, <code>journalctl --disk-usage</code> shows the consumption.</p>

</div>

<h2 id="maintenance--backups">Maintenance &amp; backups</h2>
<ul>
<li><strong>Your own units belong in the backup.</strong> Everything under <code>/etc/systemd/system/</code> is your own configuration and should be in your <a href="/en/tutorials/restic-backups/">Restic backup</a>. After a server rebuild you restore your services and timers with it instantly (then run <code>daemon-reload</code> once and re-<code>enable</code> the timers).</li>
<li><strong>Timers instead of your own cron jobs.</strong> If you&rsquo;re using systemd anyway, timers are the more consistent choice: they show up in the journal, catch up on missed runs (<code>Persistent=true</code>) and can be monitored with <code>systemctl status SERVICE</code> like any other service.</li>
<li><strong>Keep an eye on failed units.</strong> <code>systemctl --failed</code> lists services that have crashed – a quick health check for the system. For real alerting, <a href="/en/tutorials/uptime-kuma-monitoring/">Uptime Kuma</a> tells you the server is down, while <code>systemctl --failed</code> shows the cause on the host.
</content></li>
</ul>
]]></content:encoded></item></channel></rss>