https://shoreless.limited/en en How to re-apply Sieve filters to a Dovecot IMAP inbox https://shoreless.limited/en/knowledge-base/kb20224071315-reapply-dovecot-sieve-filters <span class="field field--name-title field--type-string field--label-hidden">How to re-apply Sieve filters to a Dovecot IMAP inbox</span> <section class="kb-categories"> <div class="container"> <span class="kb-categories-title">Categories</span> <div class="kb-category"><i class="fa fa-tag"></i> <a href="/en/knowledge-base/categories/server-talks/dovecot" hreflang="en">Dovecot</a></div> <div class="kb-category"><i class="fa fa-tag"></i> <a href="/en/knowledge-base/categories/software-tools/sieve-mail-filters" hreflang="en">Sieve Mail Filters</a></div> <div class="kb-category"><i class="fa fa-tag"></i> <a href="/en/knowledge-base/categories/imap" hreflang="en">IMAP</a></div> </div> </section> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/en/user/mario-steinitz" typeof="schema:Person" property="schema:name" datatype="">Mario Steinitz</span></span> <span class="field field--name-created field--type-created field--label-hidden">Sun, 10/09/2022 - 13:15</span> <section id="page-preface" class="page-preface"> <div class="container"> <p>Sieve scripts are a great tool to fil­ter incom­ing email mes­sages before they are stored in your mail­box. The Dove­cot <a title="IMAP" tabindex="0" data-content="&lt;p&gt;Internet Message Access Protocol (IMAP) is a standard email protocol, that allows users to access emails or messages stored on a remote mail server from virtually any local mail client and device that supports the IMAP protocol. &lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/imap&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: IMAP&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">IMAP</a> server sup­ports Sieve scripts via the Pigeon­hole plu­gin. How­ever, those scripts are applied to your incom­ing emails before they are deliv­ered to your inbox.</p> <p>Some­times, you may wish to fil­ter mes­sages that are already stored in your mail­box. For instance, when a <a title="bug" tabindex="0" data-content="&lt;p&gt;In software engineering, a bug is an error in a software application. It may cause the application to behave in an unintended manner or quit unexpectedly. Most often bugs are caused by syntax or logic errors within the source code of the application. &lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/bug&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: bug&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">bug</a> in a Sieve script caused many mes­sages to be deliv­ered incor­rectly. As long as the <a href="https://doc.dovecot.org/configuration_manual/sieve/plugins/imapfilter_sieve/" title="Pigeonhole IMAP FILTER=SIEVE Plugin">Sieve IMAP fil­ter</a> is exper­i­men­tal and its sup­port lim­ited, the `sieve-fil­ter` tool can come to your aid. This arti­cle explains how it is done.</p> </div> </section> <section class="sl-c14 sl-bg-c06 top-ltr clearfix" id="section-193"> <div class="section-content container"> <div class="clearfix text-formatted field field--name-sl-text field--type-text-long field--label-hidden field__item"><div class="highlight">The steps shown in this arti­cle are intended for being con­ducted on the com­mand line inter­face (CLI) of your mail server. If you don't have access to the CLI, please ask your mail servers' sys­tems admin­is­tra­tor, whether he can help you.</div> <p> </p> <h3>Introduction</h3> <p>Our Dove­cot <a title="IMAP" tabindex="0" data-content="&lt;p&gt;Internet Message Access Protocol (IMAP) is a standard email protocol, that allows users to access emails or messages stored on a remote mail server from virtually any local mail client and device that supports the IMAP protocol. &lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/imap&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: IMAP&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">IMAP</a> email ser­vice user defined mail fil­ter rules using the Man­a­ge­sieve pro­to­col. His Sieve rules auto­mat­i­cally clas­sify the hun­dreds of emails flood­ing his inbox every day. They delete unwanted mes­sages, store oth­ers in dis­tinct fold­ers, set flags and pri­or­i­tize them for later read­ing. A typo in his sieve scripts caused the fil­ters to break. Emails were sent directly to his inbox where now thou­sands of unclas­si­fied newslet­ters and spam mails linger, mak­ing him unable to deter­mine the impor­tant com­mu­ni­ca­tion. We were asked to help him refilter the mes­sages using his fixed Sieve fil­ters.</p> <p> </p> <h3>Example environment</h3> <p>For the sake of this arti­cle, we use `<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>` as email inbox. We advice our <a title="IMAP" tabindex="0" data-content="&lt;p&gt;Internet Message Access Protocol (IMAP) is a standard email protocol, that allows users to access emails or messages stored on a remote mail server from virtually any local mail client and device that supports the IMAP protocol. &lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/imap&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: IMAP&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">IMAP</a> user to cre­ate a sub­folder `Refilter` in his email inbox and move all unclas­si­fied emails into this folder.</p> <p>Our exam­ple Dove­cot email server uses `/var/vmail/[domain]/[user]` as stor­age loca­tion. User-defined cus­tom Sieve scripts are located in a `/var/vmail/[domain]/[user]/.sieve` sym­bolic link that tar­gets the enabled Sieve fil­ter rules file. The inbox folder root is `INBOX`.</p> <p> </p> <h3>Proceedings</h3> <p>In order to re-apply Sieve rules on a Dove­cot <a title="IMAP" tabindex="0" data-content="&lt;p&gt;Internet Message Access Protocol (IMAP) is a standard email protocol, that allows users to access emails or messages stored on a remote mail server from virtually any local mail client and device that supports the IMAP protocol. &lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/imap&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: IMAP&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">IMAP</a> server, newer ver­sions of Dove­cot Pigeon­hole come with the `sieve-fil­ter` tool. It takes the tar­get inbox, the sieve rules to apply, and the inbox folder to apply the rules to as argu­ments:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;">sieve-fil­ter <span style="color: #660033;">-u</span> <span style="color: #ff0000;">"<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>"</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>vmail<span style="color: #000000; font-weight: bold;">/</span>exam­ple.com<span style="color: #000000; font-weight: bold;">/</span>user.name<span style="color: #000000; font-weight: bold;">/</span>.sieve INBOX.Refilter</div></div> <p> </p> <p>By default, the `sieve-fil­ter` com­mand runs in sim­u­la­tion mode. To apply any changes, we have to explic­itly enable exe­cu­tion mode by adding the `-e` option, and allow write and delete access to the mail­box by adding the `-W` option. We also want the Sieve scripts to be recom­piled to apply any last changes by the user. So we add the `-C` option to the com­mand (a com­plete ref­er­ence of avail­able options can be found at the <a href="https://pigeonhole.dovecot.org/doc/man1/sieve-filter.1.html" rel=" noopener" target="_blank" title="sieve-filter documentation">Pigeon­hole Dove­cot sieve-fil­ter doc­u­men­ta­tion page</a>):</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;">sieve-fil­ter <span style="color: #660033;">-e</span> <span style="color: #660033;">-W</span> <span style="color: #660033;">-C</span> <span style="color: #660033;">-u</span> <span style="color: #ff0000;">"<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>"</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>vmail<span style="color: #000000; font-weight: bold;">/</span>exam­ple.com<span style="color: #000000; font-weight: bold;">/</span>user.name<span style="color: #000000; font-weight: bold;">/</span>.sieve INBOX.Refilter</div></div> <p> </p> <p>Con­sid­er­ing that inboxes can grow rather large, and pro­cess­ing thou­sands of mes­sages at a time may put a heavy strain on our live mail server, we may want to run the fil­ter­ing with lower pri­or­ity, only when the sys­tem isn't too busy. There­fore, we addi­tion­ally use the `ion­ice` com­mand with `-c2` for best-effort mode and `-n7` for low­est pri­or­ity:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;">ion­ice <span style="color: #660033;">-c2</span> <span style="color: #660033;">-n7</span> sieve-fil­ter <span style="color: #660033;">-e</span> <span style="color: #660033;">-W</span> <span style="color: #660033;">-C</span> <span style="color: #660033;">-u</span> <span style="color: #ff0000;">"<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>"</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>vmail<span style="color: #000000; font-weight: bold;">/</span>exam­ple.com<span style="color: #000000; font-weight: bold;">/</span>user.name<span style="color: #000000; font-weight: bold;">/</span>.sieve INBOX.Refilter</div></div> <h3> </h3> <h3>Wrap it into a Bash script</h3> <p>We don't always want to return to our knowl­edge base when hav­ing to help a mail user to refilter its mes­sages. There­fore, we cre­ated a sim­ple Bash script that just requires the mail user name as argu­ment and does the job for us.</p> <p>It is using the `doveadm` <a href="https://wiki.dovecot.org/Tools/Doveadm#command_authentication_commands" title="Dovecot doveadm user documentation">user lookup</a> com­mand to deter­mine the users' Sieve script loca­tion and mail­box fold­ers:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;">doveadm user <span style="color: #ff0000;">"<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>"</span></div></div> <p>Which, for exist­ing mail­box users, returns an answer like this:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">field   value<br /> uid     *****<br /> gid     *****<br /> home    /var/vmail/exam­ple.com/user.name<br /> mail    maildir:/var/vmail/exam­ple.com/user.name/Maildir<br /> quo­ta_rule      *:stor­age=0B<br /> sieve   /var/vmail/exam­ple.com/user.name/.sieve</div></div> <p>We are using the `maildir` infor­ma­tion to check for exist­ing mes­sages to process, as well as the `sieve` infor­ma­tion to find the user-defined Sieve rules.</p> <p> </p> <p>And here is the script as ref­er­ence for our val­ued read­ers `sieve-refilter.sh`: </p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span><br /> <span style="color: #666666; font-style: italic;">#------------------------------------------------------------------------------</span><br /> <span style="color: #666666; font-style: italic;"># Reap­ply user-defined Sieve fil­ters to a Dove­cot mail­box folder.</span><br /> <span style="color: #666666; font-style: italic;">#------------------------------------------------------------------------------</span><br /> <span style="color: #666666; font-style: italic;"># REQUIRE­MENTS:</span><br /> <span style="color: #666666; font-style: italic;"># awk, cat, doveadm, echo, exit, find, grep, ion­ice, printf, read, shift,</span><br /> <span style="color: #666666; font-style: italic;"># sieve-fil­ter, tr, wc, non-POSIX sup­port for `&lt; &lt;()` syn­tax</span><br /> <span style="color: #666666; font-style: italic;">#------------------------------------------------------------------------------</span><br /> <span style="color: #666666; font-style: italic;"># USAGE:</span><br /> <span style="color: #666666; font-style: italic;"># ./sieve-refilter.sh &lt;user&gt; [&lt;folder&gt;]</span><br /> <span style="color: #666666; font-style: italic;">#</span><br /> <span style="color: #666666; font-style: italic;"># Options:</span><br /> <span style="color: #666666; font-style: italic;">#   &lt;user&gt;             The Dove­cot user to reap­ply Sieve fil­ters for. E.g.,</span><br /> <span style="color: #666666; font-style: italic;">#                      "<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>".</span><br /> <span style="color: #666666; font-style: italic;">#   &lt;folder&gt;           Optional: The mail­box folder to process.</span><br /> <span style="color: #666666; font-style: italic;">#                      Defaults to 'INBOX.Refilter'.</span><br /> <span style="color: #666666; font-style: italic;">#------------------------------------------------------------------------------</span><br /> <span style="color: #666666; font-style: italic;"># Author: SHORELESS Limited &lt;<a href="mailto:contact@shoreless.limited">con­tact@shore­less.lim­ited</a>&gt;</span><br /> <span style="color: #666666; font-style: italic;"># See <a href="https://shoreless.ltd/kb20224071315">https://shore­less.ltd/kb20224071315</a></span><br /> <span style="color: #666666; font-style: italic;">#------------------------------------------------------------------------------</span><br /> <br /> <span style="color: #666666; font-style: italic;"># User option.</span><br /> <span style="color: #007800;">EMAIL_USER</span>=<span style="color: #ff0000;">"$1"</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">"<span style="color: #007800;">${EMAIL_USER}</span>"</span> <span style="color: #7a0874; font-weight: bold;">]</span><span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"<span style="color: #000099; font-weight: bold;">\n</span>\e[1;31mAn argu­ment error occurred.\e[0m<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'Argu­ment error: The user para­me­ter "&lt;user&gt;" is miss­ing.'</span><span style="color: #7a0874; font-weight: bold;">)</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>Usage: ./sieve-refilter.sh &lt;user&gt; [&lt;folder&gt;]<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"Options:<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  &lt;user&gt;             The Dove­cot user to reap­ply Sieve fil­ters for. E.g.,<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"                     <span style="color: #000099; font-weight: bold;">\"</span><a href="mailto:user.name@example.com">user.name@exam­ple.com</a><span style="color: #000099; font-weight: bold;">\"</span>."</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  &lt;folder&gt;           Optional: The mail­box folder to process.<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"                     Defaults to 'INBOX.Refilter'.<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">22</span><br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <br /> <span style="color: #007800;">FOLDER</span>=<span style="color: #ff0000;">"$2"</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">"<span style="color: #007800;">${FOLDER}</span>"</span> <span style="color: #7a0874; font-weight: bold;">]</span><span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #007800;">FOLDER</span>=<span style="color: #ff0000;">"INBOX.Refilter"</span><br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <br /> <span style="color: #666666; font-style: italic;"># Exe­cutes a com­mand while writ­ing STD­OUT and STDERR to vari­ables.</span><br /> <span style="color: #666666; font-style: italic;">#</span><br /> <span style="color: #666666; font-style: italic;"># @param STD­OUT</span><br /> <span style="color: #666666; font-style: italic;">#   The vari­able to write STD­OUT to.</span><br /> <span style="color: #666666; font-style: italic;"># @param STDERR</span><br /> <span style="color: #666666; font-style: italic;">#   The vari­able to write STDERR to.</span><br /> <span style="color: #666666; font-style: italic;"># @param COM­MAND</span><br /> <span style="color: #666666; font-style: italic;">#   The com­mand to run.</span><br /> <span style="color: #666666; font-style: italic;"># @param [ARG1[ ARG2[ ...[ ARGN]]]]</span><br /> <span style="color: #666666; font-style: italic;">#   Any addi­tional argu­ments for the com­mand to run.</span><br /> <span style="color: #666666; font-style: italic;">#</span><br /> <span style="color: #666666; font-style: italic;"># @return</span><br /> <span style="color: #666666; font-style: italic;">#   The com­mand exit code.</span><br /> <span style="color: #666666; font-style: italic;">#</span><br /> <span style="color: #666666; font-style: italic;"># @see <a href="https://stackoverflow.com/questions/11027679/#answer-59592881">https://stack­over­flow.com/ques­tions/11027679/#answer-59592881</a></span><br /> catch<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">{</span><br />   <span style="color: #7a0874; font-weight: bold;">{</span><br />     <span style="color: #007800;">IFS</span>=$<span style="color: #ff0000;">'\n'</span> <span style="color: #7a0874; font-weight: bold;">read</span> <span style="color: #660033;">-r</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">''</span> <span style="color: #ff0000;">"<span style="color: #007800;">${1}</span>"</span>;<br />     <span style="color: #007800;">IFS</span>=$<span style="color: #ff0000;">'\n'</span> <span style="color: #7a0874; font-weight: bold;">read</span> <span style="color: #660033;">-r</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">''</span> <span style="color: #ff0000;">"<span style="color: #007800;">${2}</span>"</span>;<br />     <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #007800;">IFS</span>=$<span style="color: #ff0000;">'\n'</span> <span style="color: #7a0874; font-weight: bold;">read</span> <span style="color: #660033;">-r</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">''</span> _ER­RNO_; <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #800000;">${_ER­RNO_}</span><span style="color: #7a0874; font-weight: bold;">)</span>;<br />   <span style="color: #7a0874; font-weight: bold;">}</span> <span style="color: #000000; font-weight: bold;">&lt;</span> <span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'\0%s\0%d\0'</span> <span style="color: #ff0000;">"<span style="color: #007800;">$(((({ shift 2; ${@}; echo "${?}" 1&gt;&amp;3-; } | tr -d '\0' 1&gt;&amp;4-)</span> 4&gt;&amp;2- 2&gt;&amp;1- | tr -d '\0' 1&gt;&amp;4-) 3&gt;&amp;1- | exit "</span>$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #c20cb9; font-weight: bold;">cat</span><span style="color: #7a0874; font-weight: bold;">)</span><span style="color: #ff0000;">") 4&gt;&amp;1-)"</span> <span style="color: #ff0000;">"<span style="color: #007800;">${?}</span>"</span> <span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">)</span><br /> <span style="color: #7a0874; font-weight: bold;">}</span><br /> <br /> <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">"Dove­cot Sieve refilter"</span><br /> <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">"----------------------"</span><br /> <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">"Check­ing pro­vided options and mail­box:"</span><br /> <br /> <span style="color: #666666; font-style: italic;"># Check, whether the user exists in the local Dove­cot instance.</span><br /> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'\e[0m- Check­ing, whether the user exists... '</span><br /> catch STD­OUT STDERR doveadm user <span style="color: #ff0000;">"<span style="color: #007800;">${EMAIL_USER}</span>"</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #800000;">${?}</span> <span style="color: #660033;">-eq</span> <span style="color: #000000;">0</span> <span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;32m[ok]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br /> <span style="color: #000000; font-weight: bold;">else</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;31m[error]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'%s\n%s\n\n'</span> <span style="color: #ff0000;">"  User lookup failed."</span> <span style="color: #ff0000;">"  <span style="color: #007800;">${STDERR}</span>"</span><span style="color: #7a0874; font-weight: bold;">)</span><br />   <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">22</span>;<br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <br /> <span style="color: #666666; font-style: italic;"># Deter­mine mail folder.</span><br /> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'\e[0m- Deter­mine mail folder... '</span><br /> <span style="color: #007800;">MAIL_­FOLDER</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">"<span style="color: #007800;">${STD­OUT}</span>"</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #ff0000;">'^mail'</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">awk</span> <span style="color: #ff0000;">'{print $2}'</span><span style="color: #7a0874; font-weight: bold;">)</span><br /> <span style="color: #007800;">MAIL_­FOLDER</span>=<span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER#maildir:}</span>"</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>"</span> <span style="color: #7a0874; font-weight: bold;">]</span><span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;31m[error]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'%s\n%s\n\n'</span> <span style="color: #ff0000;">"  Dove­cot Maildir could not be found."</span> <span style="color: #ff0000;">"  <span style="color: #007800;">${MAIL_­FOLDER}</span>"</span><span style="color: #7a0874; font-weight: bold;">)</span><br />   <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">2</span>;<br /> <span style="color: #000000; font-weight: bold;">else</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;32m[ok]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  <span style="color: #007800;">${MAIL_­FOLDER}</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <br /> <span style="color: #666666; font-style: italic;"># Deter­mine sieve script.</span><br /> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'\e[0m- Check for Sieve script... '</span><br /> <span style="color: #007800;">SIEVE</span>=$<span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">"<span style="color: #007800;">${STD­OUT}</span>"</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #ff0000;">'^sieve'</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">awk</span> <span style="color: #ff0000;">'{print $2}'</span><span style="color: #7a0874; font-weight: bold;">)</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">"<span style="color: #007800;">${SIEVE}</span>"</span> <span style="color: #7a0874; font-weight: bold;">]</span><span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-e</span> <span style="color: #ff0000;">"<span style="color: #007800;">${SIEVE}</span>"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">"<span style="color: #007800;">${SIEVE}</span>"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-r</span> <span style="color: #ff0000;">"<span style="color: #007800;">${SIEVE}</span>"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-s</span> <span style="color: #ff0000;">"<span style="color: #007800;">${SIEVE}</span>"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;31m[error]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'%s\n%s\n\n'</span> <span style="color: #ff0000;">"  Sieve script does not exist or is empty."</span> <span style="color: #ff0000;">"  <span style="color: #007800;">${SIEVE}</span>"</span><span style="color: #7a0874; font-weight: bold;">)</span><br />   <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">2</span>;<br /> <span style="color: #000000; font-weight: bold;">else</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;32m[ok]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  <span style="color: #007800;">${SIEVE}</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <br /> <span style="color: #666666; font-style: italic;"># Count the num­ber of unprocessed mes­sages.</span><br /> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">'\e[0m- Check for mes­sages to refilter... '</span><br /> <span style="color: #007800;">MAIL_­FOLDER</span>=<span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>/.<span style="color: #007800;">${FOLDER}</span>"</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>/cur"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #000000; font-weight: bold;">!</span> \<span style="color: #7a0874; font-weight: bold;">(</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>/new"</span> \<span style="color: #7a0874; font-weight: bold;">)</span> <span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;31m[error]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  User inbox doesn't have a '<span style="color: #007800;">${FOLDER}</span>' folder.<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #7a0874; font-weight: bold;">)</span><br />   <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">2</span>;<br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <span style="color: #666666; font-style: italic;"># Count the num­ber of files in the tar­get inbox folder.</span><br /> <span style="color: #007800;">FILES</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>/cur/"</span> <span style="color: #ff0000;">"<span style="color: #007800;">${MAIL_­FOLDER}</span>/new/"</span> <span style="color: #660033;">-type</span> f <span style="color: #660033;">-name</span> <span style="color: #ff0000;">'*'</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">wc</span> -l<span style="color: #000000; font-weight: bold;">`</span><br /> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">[</span> <span style="color: #800000;">${FILES}</span> <span style="color: #660033;">-eq</span> <span style="color: #000000;">0</span> <span style="color: #7a0874; font-weight: bold;">]</span>; <span style="color: #000000; font-weight: bold;">then</span><br />   <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;33m[warn­ing]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />   <span style="color: #7a0874; font-weight: bold;">(</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  No mes­sages to process. Abort­ing.<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #7a0874; font-weight: bold;">)</span><br />   <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">61</span>;<br /> <span style="color: #000000; font-weight: bold;">fi</span><br /> <br /> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"\e[1;32m[ok]\e[0m<span style="color: #000099; font-weight: bold;">\n</span>"</span><br /> <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">"  Found <span style="color: #007800;">${FILES}</span> mes­sages to process.<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span><br /> <br /> <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">"Run­ning <span style="color: #007800;">${FILES}</span> mes­sages in <span style="color: #007800;">${FOLDER}</span> through the Sieve fil­ter."</span><br /> ion­ice <span style="color: #660033;">-c2</span> <span style="color: #660033;">-n7</span> sieve-fil­ter <span style="color: #660033;">-e</span> <span style="color: #660033;">-W</span> <span style="color: #660033;">-C</span> <span style="color: #660033;">-u</span> <span style="color: #ff0000;">"<span style="color: #007800;">${EMAIL_USER}</span>"</span> <span style="color: #ff0000;">"<span style="color: #007800;">${SIEVE}</span>"</span> <span style="color: #ff0000;">"<span style="color: #007800;">${FOLDER}</span>"</span></div></div> <p> </p> <p>Make the script exe­cutable:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">chmod</span> +x sieve-refilter.sh</div></div> <p> </p> <p>Now we can run the script as admin­is­tra­tor or vmail shell user:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> .<span style="color: #000000; font-weight: bold;">/</span>sieve-refilter.sh <span style="color: #ff0000;">"<a href="mailto:user.name@example.com">user.name@exam­ple.com</a>"</span></div></div> <p> </p> <h3>Conclusion</h3> <p>The Pigeon­hole `sieve-fil­ter` tool is great for re-run­ning Sieve fil­ter rules on a Dove­cot <a title="IMAP" tabindex="0" data-content="&lt;p&gt;Internet Message Access Protocol (IMAP) is a standard email protocol, that allows users to access emails or messages stored on a remote mail server from virtually any local mail client and device that supports the IMAP protocol. &lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/imap&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: IMAP&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">IMAP</a> inbox folder. We cre­ated a sim­ple script to per­form this oper­a­tion for a sin­gle user.</p> <p> </p> <p> </p> <p> </p> </div> </div> </section> Sun, 09 Oct 2022 05:15:58 +0000 Mario Steinitz 407 at https://shoreless.limited How to run headless Chrome as systemd service https://shoreless.limited/en/knowledge-base/kb20224030735-headless-chrome-systemd-service <span class="field field--name-title field--type-string field--label-hidden">How to run headless Chrome as systemd service</span> <section class="kb-categories"> <div class="container"> <span class="kb-categories-title">Categories</span> <div class="kb-category"><i class="fa fa-tag"></i> <a href="/en/knowledge-base/categories/operating-systems/linux" hreflang="en">Linux</a></div> <div class="kb-category"><i class="fa fa-tag"></i> <a href="/en/knowledge-base/categories/software-tools/headless-chrome" hreflang="en">Headless Chrome</a></div> <div class="kb-category"><i class="fa fa-tag"></i> <a href="/en/knowledge-base/categories/software-tools/systemd" hreflang="en">systemd</a></div> </div> </section> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/en/user/mario-steinitz" typeof="schema:Person" property="schema:name" datatype="">Mario Steinitz</span></span> <span class="field field--name-created field--type-created field--label-hidden">Wed, 10/05/2022 - 07:35</span> <section id="page-preface" class="page-preface"> <div class="container"> <p><a title="Systemd" tabindex="0" data-content="&lt;p&gt;Systemd is a system and service manager for Linux operating systems. One of the main functions of systemd is to manage the services, devices, mount points, sockets and other entities in a Linux system. Each of these entities that are managed by systemd is called a unit. Systemd has replaced the…&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/systemd&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: Systemd&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">Sys­temd</a> has been the default init sys­tem in RHEL/Cen­tOS, Fedora, Ubuntu, Debian and other Linux dis­tri­b­u­tions for sev­eral years now. This arti­cle shows how to cre­ate a sim­ple <a title="systemd" tabindex="0" data-content="&lt;p&gt;Systemd is a system and service manager for Linux operating systems. One of the main functions of systemd is to manage the services, devices, mount points, sockets and other entities in a Linux system. Each of these entities that are managed by systemd is called a unit. Systemd has replaced the…&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/systemd&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: systemd&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">sys­temd</a> ser­vice to run a head­less Chrome instance for remote debug­ging.</p> </div> </section> <section class="sl-bg-c06 top-ltr pb-5 clearfix" id="section-191"> <header class="section-header container"> <h2 class="sr-only">Article content</h2> </header> <div class="section-content container"> <div class="clearfix text-formatted field field--name-sl-text field--type-text-long field--label-hidden field__item"><h3><span>Introduction</span></h3> <p>We oper­ate an <a title="application" tabindex="0" data-content="&lt;p&gt;An application is a software program running on a computer system or mobile device. It is&amp;nbsp;designed to perform a specific function for the user or other applications and&amp;nbsp;called application because it can be applied&amp;nbsp;for a particular purpose or use.&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/application&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: application&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">appli­ca­tion</a> on a Linux based remote server. This <a title="application" tabindex="0" data-content="&lt;p&gt;An application is a software program running on a computer system or mobile device. It is&amp;nbsp;designed to perform a specific function for the user or other applications and&amp;nbsp;called application because it can be applied&amp;nbsp;for a particular purpose or use.&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/application&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: application&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">appli­ca­tion</a> runs sev­eral tasks which require head­less Chrome for gen­er­at­ing for­mat­ted out­put from HTML pages (PDF doc­u­ments, screen­shots of web pages, ...). Each com­ple­tion of such tasks includes start­ing up a head­less Chrome instance, gen­er­at­ing the out­put, and clos­ing Chrome.</p> <p>Dur­ing high usage times, a lot of sys­tem resources are required for par­al­lel work­ing tasks. We wish to opti­mize the gen­er­a­tion of doc­u­ments via Chrome by using a sin­gle Chrome instance only that runs as sys­tem ser­vice and serves all tasks of our <a title="application" tabindex="0" data-content="&lt;p&gt;An application is a software program running on a computer system or mobile device. It is&amp;nbsp;designed to perform a specific function for the user or other applications and&amp;nbsp;called application because it can be applied&amp;nbsp;for a particular purpose or use.&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/application&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: application&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">appli­ca­tion</a> . In order to ensure this Chrome instance doesn't use up too many resources in the long term, we also want it to be restarted on a reg­u­lar base.</p> <p>To avoid mali­cious JavaScripts on the processed HTML pages to harm our server, we also want to restrict Chrome access to the sys­tem as much as pos­si­ble.</p> <p> </p> <h3><span>Proceedings</span></h3> <p>We cre­ate a ded­i­cated user <span class="geshifilter"><code class="text geshifilter-text">chrome</code></span>, which can't login nor has a home folder. It serves as a non-ele­vated user to run the Chrome instance:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> adduser chrome <span style="color: #660033;">--shell</span>=<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">false</span> <span style="color: #660033;">--no-cre­ate-home</span></div></div> <p> </p> <p>We want to exchange files with the Chrome instance. Chrome will save the gen­er­ated out­put files to an exchange folder, where our <a title="application" tabindex="0" data-content="&lt;p&gt;An application is a software program running on a computer system or mobile device. It is&amp;nbsp;designed to perform a specific function for the user or other applications and&amp;nbsp;called application because it can be applied&amp;nbsp;for a particular purpose or use.&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/application&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: application&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">appli­ca­tion</a> can pick them up. This folder shall be the only writable folder for Chrome:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Cre­ate a file exchange folder.</span><br /> <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>file­ex­change<br /> <span style="color: #666666; font-style: italic;"># Set folder own­er­ship.</span><br /> <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chown</span> chrome:chrome <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>file­ex­change<br /> <span style="color: #666666; font-style: italic;"># Set appro­pri­ate file exchange folder per­mis­sions.</span><br /> <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chmod</span> <span style="color: #000000;">775</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>file­ex­change</div></div> <p> </p> <p>For run­ning our head­less Chrome in the back­ground, we cre­ate a sys­tem-wide <a title="systemd" tabindex="0" data-content="&lt;p&gt;Systemd is a system and service manager for Linux operating systems. One of the main functions of systemd is to manage the services, devices, mount points, sockets and other entities in a Linux system. Each of these entities that are managed by systemd is called a unit. Systemd has replaced the…&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/systemd&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: systemd&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">sys­temd</a> file <span class="geshifilter"><code class="text geshifilter-text">/etc/systemd/system/chrome.service</code></span>:</p> <div class="geshifilter"><div class="text geshifilter-text" style="font-family:monospace;">[Unit]<br /> Descrip­tion=Head­less chrome<br /> <br /> [Ser­vice]<br /> Type=sim­ple<br /> Restart=always<br /> Run­timeMaxSec=1d<br /> Dynam­i­cUser=true<br /> User=chrome<br /> Pro­tect­Sys­tem=strict<br /> Read­WritePaths=/var/file­ex­change<br /> Envi­ron­ment=HOME=/tmp<br /> Envi­ron­ment=DIS­PLAY=:0<br /> Exec­Start=/opt/chrome --head­less --no-first-run --no-default-browser-check --no-sand­box --dis­able-setuid-sand­box --dis­able-gpu --dis­able-dev-shm-usage --remote-debug­ging-port=9222 --win­dow-size="1920,1200" --force-device-scale-fac­tor=0.5<br /> <br /> [Install]<br /> Want­edBy=multi-user.tar­get</div></div> <p> </p> <p>Key aspects of this ser­vice unit:</p> <ul> <li><span class="geshifilter"><code class="text geshifilter-text">Type=simple</code></span>: There's only one main process, which is started with <span class="geshifilter"><code class="text geshifilter-text">ExecStart</code></span>.</li> <li><span class="geshifilter"><code class="text geshifilter-text">Restart=always</code></span>: Restart the ser­vice in case of any fail­ures or inter­rup­tions.</li> <li><span class="geshifilter"><code class="text geshifilter-text">RuntimeMaxSec=1d</code></span>: Limit the ser­vice to a one day run­time. The ser­vice will auto­mat­i­cally be stopped and because of above <span class="geshifilter"><code class="text geshifilter-text">Restart</code></span> direc­tive restarted.</li> <li><span class="geshifilter"><code class="text geshifilter-text">DynamicUser=true</code></span>: Hard­ens file and process access to the sys­tem. It implies pri­vate tem­po­rary fold­ers and strict sys­tem pro­tec­tion.</li> <li><span class="geshifilter"><code class="text geshifilter-text">User=chrome</code></span>: The sys­tem user that will run the Chrome instance. We use our pre­vi­ously cre­ated non-ele­vated user, rather than a ran­dom user which <span class="geshifilter"><code class="text geshifilter-text">DynamicUser=true</code></span> would cre­ate with­out this direc­tive.</li> <li><span class="geshifilter"><code class="text geshifilter-text">ProtectSystem=strict</code></span>: This option is redun­dant. It is implied already by <span class="geshifilter"><code class="text geshifilter-text">DynamicUser=true</code></span>. We kept as reminder of a very strict read-only file sys­tem.</li> <li><span class="geshifilter"><code class="text geshifilter-text">ReadWritePaths=/var/fileexchange</code></span>: Space sep­a­rated whitelist for writable fold­ers. Adding our pre­vi­ously cre­ated file exchange folder here ensures Chrome can write to this folder.</li> <li><span class="geshifilter"><code class="text geshifilter-text">Environment=HOME=/tmp</code></span>: Set the home direc­tory to the pri­vate temp files path.</li> <li><span class="geshifilter"><code class="text geshifilter-text">Environment=DISPLAY=:0</code></span>: Explic­itly use the first dis­play by defin­ing the <span class="geshifilter"><code class="text geshifilter-text">DISPLAY</code></span> envi­ron­ment vari­able.</li> <li><span class="geshifilter"><code class="text geshifilter-text">ExecStart</code></span>: The path to and start options for our head­less Chrome instance. You may want to replace the path with your actual Chrome path and also adjust the Chrome startup flags accord­ing to your require­ments.</li> <li><span class="geshifilter"><code class="text geshifilter-text">WantedBy=multi-user.target</code></span>: Start the ser­vice after all net­work ser­vices are avail­able and when the sys­tem is ready for login.</li> </ul> <p> </p> <p>Set proper file per­mis­sions for the <a title="systemd" tabindex="0" data-content="&lt;p&gt;Systemd is a system and service manager for Linux operating systems. One of the main functions of systemd is to manage the services, devices, mount points, sockets and other entities in a Linux system. Each of these entities that are managed by systemd is called a unit. Systemd has replaced the…&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/systemd&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: systemd&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">sys­temd</a> ser­vice file:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">chmod</span> <span style="color: #000000;">644</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>sys­temd<span style="color: #000000; font-weight: bold;">/</span>sys­tem<span style="color: #000000; font-weight: bold;">/</span>chrome.ser­vice</div></div> <p> </p> <p>Reload the unit files to make <a title="systemd" tabindex="0" data-content="&lt;p&gt;Systemd is a system and service manager for Linux operating systems. One of the main functions of systemd is to manage the services, devices, mount points, sockets and other entities in a Linux system. Each of these entities that are managed by systemd is called a unit. Systemd has replaced the…&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/systemd&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: systemd&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">sys­temd</a> know about the new ser­vice:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> sys­tem­ctl dae­mon-reload</div></div> <p> </p> <p>Start the ser­vice and observe any error mes­sages (e.g., when the path to Chrome isn't cor­rect, the cho­sen remote debug­ging port already used, with a typo in Chrome startup flags, and so on):</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> sys­tem­ctl start chrome.ser­vice</div></div> <p> </p> <p>If no errors occurred and the ser­vice is run­ning fine, enable it for auto­matic start on machine boot:</p> <div class="geshifilter"><div class="bash geshifilter-bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> sys­tem­ctl <span style="color: #7a0874; font-weight: bold;">enable</span> chrome.ser­vice</div></div> <p> </p> <h3><span>Conclusion</span></h3> <p>We suc­cess­fully cre­ated a <a title="systemd" tabindex="0" data-content="&lt;p&gt;Systemd is a system and service manager for Linux operating systems. One of the main functions of systemd is to manage the services, devices, mount points, sockets and other entities in a Linux system. Each of these entities that are managed by systemd is called a unit. Systemd has replaced the…&lt;/p&gt;&lt;div class=&quot;sl-glossary-tip-brand&quot;&gt;SHORELESS Glossary&lt;/div&gt;&lt;a href=&quot;/en/glossary/systemd&quot; class=&quot;sl-glossary-link&quot; title=&quot;Glossary Term: systemd&quot;&gt;more&lt;/a&gt;" role="button" data-toggle="popover" data-trigger="click" data-placement="top" data-html="true" class="sl-glossary-term">sys­temd</a> ser­vice for head­less Chrome that</p> <ul> <li>restarts daily,</li> <li>starts with a non-ele­vated user,</li> <li>is mostly iso­lated from the remain­ing sys­tem, but</li> <li>can cre­ate files for processed out­put in a specif­i­cally defined loca­tion.</li> </ul> <p> </p> <p> </p> <p> </p> </div> </div> </section> Tue, 04 Oct 2022 23:35:04 +0000 Mario Steinitz 405 at https://shoreless.limited