<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MP Singh</title>
    <description>The latest articles on DEV Community by MP Singh (@actools-pl).</description>
    <link>https://dev.to/actools-pl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3873409%2F0437544c-15a5-449f-ad08-8f611566087d.png</url>
      <title>DEV Community: MP Singh</title>
      <link>https://dev.to/actools-pl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/actools-pl"/>
    <language>en</language>
    <item>
      <title>I built a Drupal installer that tells you if your site is safe to ship</title>
      <dc:creator>MP Singh</dc:creator>
      <pubDate>Fri, 17 Apr 2026 18:46:04 +0000</pubDate>
      <link>https://dev.to/actools-pl/i-built-a-drupal-installer-that-tells-you-if-your-site-is-safe-to-ship-2p8e</link>
      <guid>https://dev.to/actools-pl/i-built-a-drupal-installer-that-tells-you-if-your-site-is-safe-to-ship-2p8e</guid>
      <description>&lt;p&gt;Most Drupal installers stop at "it's running."&lt;/p&gt;

&lt;p&gt;Mine doesn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem nobody talks about
&lt;/h2&gt;

&lt;p&gt;You follow the tutorial. You provision a server. You install Drupal. The site loads. You think you're done.&lt;/p&gt;

&lt;p&gt;You're not.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;trusted_host_patterns&lt;/code&gt; might be unconfigured — meaning any Host header gets accepted, opening you to cache poisoning. Your private file path might be unset — meaning files uploaded to &lt;code&gt;private://&lt;/code&gt; are publicly accessible via direct URL. Your Redis might be running but not actually wired as Drupal's cache backend. Your TLS cert might have 12 days left and you have no alert for it.&lt;/p&gt;

&lt;p&gt;The site looks fine. The vulnerabilities are invisible.&lt;/p&gt;

&lt;p&gt;Every Drupal developer I know has shipped something that looked fine and wasn't. Including me.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/actools-pl/actoolsDrupal" rel="noopener noreferrer"&gt;Actools&lt;/a&gt;&lt;/strong&gt; is a Drupal 11 installer for Hetzner VPS. One command, complete stack — Caddy 2, PHP 8.3-FPM, MariaDB 11.4, Redis 7, XeLaTeX PDF worker, automated backups.&lt;/p&gt;

&lt;p&gt;That part exists. There are other installers.&lt;/p&gt;

&lt;p&gt;What's different is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;actools audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;25 checks. Four categories. A score out of 10. Fix commands attached to every finding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=== ACTOOLS DRUPAL AUDIT ===

[DRUPAL]
  PASS  Security advisories: none found
  PASS  trusted_host_patterns: configured
  PASS  Error display: hidden
  PASS  Private file path: configured and writable

[INTEGRATION]
  PASS  Redis: write/read/TTL confirmed
  PASS  Queue worker: enqueue test passed
  PASS  HTTP: Cache-Control header present

[STACK]
  PASS  Containers: all 5/5 running
  PASS  Site response: HTTP 200
  PASS  TLS: valid, 90 days remaining
  PASS  MariaDB: reachable
  PASS  Worker container: healthy

[SECURITY]
  PASS  HTTPS: HTTP redirects to HTTPS
  PASS  HSTS header: present
  PASS  X-Frame-Options header: present
  PASS  Server header: hidden

─────────────────────────────────────────
  PASS: 22   WARN: 5   FAIL: 1
  Audit score: 6/10
  Fix FAIL items before next deploy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not a dashboard. Not a Drupal module. A CLI tool that tells you the truth about your own server.&lt;/p&gt;




&lt;h2&gt;
  
  
  The line that started it
&lt;/h2&gt;

&lt;p&gt;At the top of &lt;code&gt;audit.sh&lt;/code&gt; there's a comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The Drupal community has enough Report modules.&lt;/span&gt;
&lt;span class="c"&gt;# What it lacks is a CLI tool that says:&lt;/span&gt;
&lt;span class="c"&gt;# I found a problem. I won't let you deploy until you run this specific command to fix it.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole product philosophy in three lines. Written before a single check existed.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it checks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Drupal layer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security advisories via &lt;code&gt;drush pm:security&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;trusted_host_patterns&lt;/code&gt; — reads settings.php and verifies it's active&lt;/li&gt;
&lt;li&gt;Config drift — but only if the sync directory has a baseline (fresh installs get INFO, not false WARNING)&lt;/li&gt;
&lt;li&gt;Error display mode&lt;/li&gt;
&lt;li&gt;Session cookie security flags&lt;/li&gt;
&lt;li&gt;Queue backlog&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Integration layer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis behavioral test — not just "is it running" but write/read/TTL cycle&lt;/li&gt;
&lt;li&gt;Redis as actual Drupal cache backend&lt;/li&gt;
&lt;li&gt;HTTP cache headers&lt;/li&gt;
&lt;li&gt;Queue worker — enqueues a test job and verifies processing&lt;/li&gt;
&lt;li&gt;Private file path — verifiable and writable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stack layer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All containers running&lt;/li&gt;
&lt;li&gt;HTTP 200 response&lt;/li&gt;
&lt;li&gt;TLS validity and days remaining&lt;/li&gt;
&lt;li&gt;Disk usage&lt;/li&gt;
&lt;li&gt;Memory available&lt;/li&gt;
&lt;li&gt;Backup existence and age&lt;/li&gt;
&lt;li&gt;MariaDB reachability&lt;/li&gt;
&lt;li&gt;Worker container health&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security layer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS redirect&lt;/li&gt;
&lt;li&gt;HSTS header&lt;/li&gt;
&lt;li&gt;X-Frame-Options&lt;/li&gt;
&lt;li&gt;X-Content-Type-Options&lt;/li&gt;
&lt;li&gt;Server header hidden&lt;/li&gt;
&lt;li&gt;Referrer-Policy&lt;/li&gt;
&lt;li&gt;Docker image pinning&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The honest score
&lt;/h2&gt;

&lt;p&gt;Fresh install scores &lt;strong&gt;6/10&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not 10. Not "everything is perfect." Six. Because on a brand new server there's no backup yet, Redis isn't wired as the cache backend by default, and a few medium-priority items need operator attention.&lt;/p&gt;

&lt;p&gt;That's honest. A tool that gives you 10/10 on a fresh install is lying to you.&lt;/p&gt;

&lt;p&gt;The score goes up as you fix things. Run &lt;code&gt;actools backup&lt;/code&gt;. Wire Redis. Pin your Docker images. Each fix moves the needle.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned building it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shell escaping across Docker layers is genuinely hard.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Injecting &lt;code&gt;$settings['trusted_host_patterns']&lt;/code&gt; into a PHP file through &lt;code&gt;bash → docker exec → bash → heredoc&lt;/code&gt; — every layer eats escape characters differently. I went through printf, echo -e, inline quoting, and eventually landed on the only solution that actually works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$php_svc&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cat &amp;gt; /tmp/php_inject.php &amp;lt;&amp;lt; 'EOF'
&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;settings['trusted_host_patterns'] = array('^&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domain_escaped&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;', '^.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;domain_escaped&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;');
// trusted_host_patterns_active
EOF
cat /tmp/php_inject.php &amp;gt;&amp;gt; /path/to/settings.php
rm -f /tmp/php_inject.php"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quoted heredoc inside the container. Write to temp file. Append. Delete. No escaping war.&lt;/p&gt;

&lt;p&gt;Three AI systems independently converged on this exact pattern when I described the problem. That's usually a sign it's right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idempotency checks need to be precise.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first idempotency check used &lt;code&gt;grep -q file_private_path settings.php&lt;/code&gt;. It matched the commented-out default line &lt;code&gt;# $settings['file_private_path'] = '';&lt;/code&gt; and skipped the injection every time. The installer said "set" — nothing was actually written.&lt;/p&gt;

&lt;p&gt;Fix: &lt;code&gt;grep -q "^$settings\['file_private_path'\]"&lt;/code&gt; — anchor to the start of line, require the actual PHP assignment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache matters more than you think.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Settings written to &lt;code&gt;settings.php&lt;/code&gt; aren't visible to Drupal until the cache is rebuilt. The installer now runs &lt;code&gt;drush cr&lt;/code&gt; immediately after both injections. Obvious in hindsight. Invisible until you're staring at an audit that says CRITICAL on something you just fixed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Drupal 11 + PHP 8.3-FPM&lt;/li&gt;
&lt;li&gt;Caddy 2 (automatic HTTPS, security headers, rate limiting)&lt;/li&gt;
&lt;li&gt;MariaDB 11.4&lt;/li&gt;
&lt;li&gt;Redis 7&lt;/li&gt;
&lt;li&gt;XeLaTeX worker (PDF generation, self-contained)&lt;/li&gt;
&lt;li&gt;GitHub Actions CI (bats + shellcheck + Trivy + CodeQL)&lt;/li&gt;
&lt;li&gt;Hetzner CX22 — €10/month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MIT license. No lock-in. The installer is free. What you install today stays yours. Future modules are optional.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/actools-pl/actoolsDrupal.git
&lt;span class="nb"&gt;cd &lt;/span&gt;actoolsDrupal
&lt;span class="nb"&gt;cp &lt;/span&gt;actools.env.example actools.env &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nano actools.env
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./actools.sh
actools audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need a Hetzner VPS running Ubuntu 24.04 and a domain pointed at it. That's it.&lt;/p&gt;

&lt;p&gt;First tester feedback welcome at &lt;a href="https://github.com/actools-pl/actoolsDrupal/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Claude. For Claude.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>opensource</category>
      <category>development</category>
      <category>security</category>
    </item>
    <item>
      <title>Drupal Developers: I Need You to Break This</title>
      <dc:creator>MP Singh</dc:creator>
      <pubDate>Tue, 14 Apr 2026 11:34:32 +0000</pubDate>
      <link>https://dev.to/actools-pl/drupal-developers-i-need-you-to-break-this-20i</link>
      <guid>https://dev.to/actools-pl/drupal-developers-i-need-you-to-break-this-20i</guid>
      <description>&lt;p&gt;I built something I want to stress-test properly.&lt;/p&gt;

&lt;p&gt;A one-command installer that deploys a full Drupal 11 production stack on a €10 VPS. Not a demo. Not a toy. A real stack with backups, recovery, observability, and preview environments.&lt;/p&gt;

&lt;p&gt;Now I need people who will actually try to break it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it deploys
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/actools-pl/actoolsDrupal.git
&lt;span class="nb"&gt;cd &lt;/span&gt;actoolsDrupal
&lt;span class="nb"&gt;cp &lt;/span&gt;actools.env.example actools.env
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./actools.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In under 30 minutes on a fresh Ubuntu 24.04 server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drupal 11 + PHP 8.3-FPM&lt;/li&gt;
&lt;li&gt;Caddy 2.8 — automatic HTTPS, HTTP/3&lt;/li&gt;
&lt;li&gt;MariaDB 11.4 — binary logging, point-in-time recovery&lt;/li&gt;
&lt;li&gt;Redis 7 — session and page caching&lt;/li&gt;
&lt;li&gt;XeLaTeX worker — containerised PDF generation&lt;/li&gt;
&lt;li&gt;Prometheus + Grafana — full observability&lt;/li&gt;
&lt;li&gt;Automated encrypted backups&lt;/li&gt;
&lt;li&gt;Preview environments per branch&lt;/li&gt;
&lt;li&gt;Self-healing health checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total cost: €10/month on a Hetzner CX22 (2 vCPU, 4GB RAM).&lt;/p&gt;




&lt;h2&gt;
  
  
  What stays free forever
&lt;/h2&gt;

&lt;p&gt;Everything above. MIT licensed. No feature gates. No licence keys. No phone-home. Every line readable at github.com/actools-pl/actoolsDrupal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this exists
&lt;/h2&gt;

&lt;p&gt;If you have worked with Acquia, Pantheon, or felt the pain of BOA's complexity — you already know the gap. This tries to close it. Full control. Predictable behaviour. Low cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I need
&lt;/h2&gt;

&lt;p&gt;I am not looking for cheerleaders.&lt;/p&gt;

&lt;p&gt;I want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install failures&lt;/li&gt;
&lt;li&gt;Confusing steps&lt;/li&gt;
&lt;li&gt;Broken assumptions&lt;/li&gt;
&lt;li&gt;Anything that makes you hesitate to use this on a client project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run it on a fresh server. Try to use it like real work. Then send a short email to &lt;a href="mailto:hello@feesix.com"&gt;hello@feesix.com&lt;/a&gt; answering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Did it install without errors?&lt;/li&gt;
&lt;li&gt;What was confusing or unclear?&lt;/li&gt;
&lt;li&gt;What broke or behaved unexpectedly?&lt;/li&gt;
&lt;li&gt;What would you need before using this on a client site?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No forms. No account. Just an honest email.&lt;/p&gt;

&lt;p&gt;Post it publicly if you prefer — that is even better.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Early access to Phase 4.5 enterprise features when released&lt;/li&gt;
&lt;li&gt;Your feedback shapes the roadmap directly&lt;/li&gt;
&lt;li&gt;Credit in the changelog if you want it&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The honest part
&lt;/h2&gt;

&lt;p&gt;I am a physics teacher building infrastructure tools on pocket money. The installer has been stress-tested, CI is green, security scanning is automated — but real-world testing by real Drupal developers is what it needs now.&lt;/p&gt;

&lt;p&gt;Try it. Break it. Tell me how to fix it.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/actools-pl/actoolsDrupal" rel="noopener noreferrer"&gt;https://github.com/actools-pl/actoolsDrupal&lt;/a&gt;&lt;br&gt;
Site: &lt;a href="https://feesix.com" rel="noopener noreferrer"&gt;https://feesix.com&lt;/a&gt;&lt;br&gt;
Email: &lt;a href="mailto:hello@feesix.com"&gt;hello@feesix.com&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Replaced Acquia (€134/month) with a €10 Hetzner VPS. One bash script. Full enterprise Drupal stack. XeLaTeX, S3, preview environments, Grafana — all included. Here is exactly how.</title>
      <dc:creator>MP Singh</dc:creator>
      <pubDate>Sun, 12 Apr 2026 05:53:20 +0000</pubDate>
      <link>https://dev.to/actools-pl/replaced-acquia-eu134month-with-a-eu10-hetzner-vps-one-bash-script-full-enterprise-drupal-stack-3n5d</link>
      <guid>https://dev.to/actools-pl/replaced-acquia-eu134month-with-a-eu10-hetzner-vps-one-bash-script-full-enterprise-drupal-stack-3n5d</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/actools-pl/-how-i-replaced-acquia-eu134month-with-a-eu10-hetzner-vps-and-beat-it-on-every-feature-3337" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwkaab75ea23k9g6jzcl.jpeg" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/actools-pl/-how-i-replaced-acquia-eu134month-with-a-eu10-hetzner-vps-and-beat-it-on-every-feature-3337" rel="noopener noreferrer" class="c-link"&gt;
            How I Replaced Acquia (€134/month) with a €10 Hetzner VPS — and Beat It on Every Feature - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            I run a Drupal 11 production site. For years, managed Drupal hosting meant one thing: pay Acquia,...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>How I Replaced Acquia (€134/month) with a €10 Hetzner VPS — and Beat It on Every Feature</title>
      <dc:creator>MP Singh</dc:creator>
      <pubDate>Sun, 12 Apr 2026 05:41:52 +0000</pubDate>
      <link>https://dev.to/actools-pl/-how-i-replaced-acquia-eu134month-with-a-eu10-hetzner-vps-and-beat-it-on-every-feature-3337</link>
      <guid>https://dev.to/actools-pl/-how-i-replaced-acquia-eu134month-with-a-eu10-hetzner-vps-and-beat-it-on-every-feature-3337</guid>
      <description>&lt;p&gt;I run a Drupal 11 production site. For years, managed Drupal hosting meant one thing: pay Acquia, Pantheon, or Platform.sh a significant monthly fee and hope nothing breaks.&lt;/p&gt;

&lt;p&gt;Last month I built Actools — a single-command enterprise Drupal installer that runs on a €10/month Hetzner VPS. It now handles everything my managed hosting used to do, plus things it never did.&lt;/p&gt;

&lt;p&gt;Here is the honest comparison.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Managed Hosting Gives You
&lt;/h2&gt;

&lt;p&gt;Acquia Cloud starts at around €134/month for a basic production environment. For that you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managed Drupal hosting&lt;/li&gt;
&lt;li&gt;Automated backups&lt;/li&gt;
&lt;li&gt;A CDN&lt;/li&gt;
&lt;li&gt;SSH access&lt;/li&gt;
&lt;li&gt;A deployment pipeline (basic)&lt;/li&gt;
&lt;li&gt;Support tickets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you do not get: control. You cannot touch the server. You cannot customise the stack. You cannot add a XeLaTeX worker for PDF generation. You cannot run your own Redis configuration. You pay for their infrastructure decisions.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built Instead
&lt;/h2&gt;

&lt;p&gt;One bash script. One config file. One command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./actools.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What it deploys in under 10 minutes on a fresh Hetzner VPS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Drupal 11&lt;/strong&gt; — production-isolated with PHP 8.3-FPM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caddy 2.8&lt;/strong&gt; — automatic HTTPS, custom rate-limiting plugin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MariaDB 11.4&lt;/strong&gt; — with binary logging for point-in-time recovery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis 7&lt;/strong&gt; — session caching, page caching&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XeLaTeX worker&lt;/strong&gt; — PDF generation fully containerised&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 storage&lt;/strong&gt; — works with AWS, Backblaze, Wasabi, Cloudflare R2, MinIO&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preview environments&lt;/strong&gt; — &lt;code&gt;actools branch feature-x&lt;/code&gt; spins up a full isolated environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipeline&lt;/strong&gt; — GitHub Actions integration built in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus + Grafana&lt;/strong&gt; — full observability stack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated backups&lt;/strong&gt; — encrypted, offsite, with restore testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-healing health checks&lt;/strong&gt; — containers restart on failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-downtime migrations&lt;/strong&gt; — database migrations without taking the site down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total cost: &lt;strong&gt;€10/month&lt;/strong&gt; for a Hetzner CX22 (2 vCPU, 4GB RAM).&lt;/p&gt;




&lt;h2&gt;
  
  
  The XeLaTeX Part
&lt;/h2&gt;

&lt;p&gt;This is the detail that matters if you generate PDFs from Drupal content.&lt;/p&gt;

&lt;p&gt;Every managed host I tried either did not support XeLaTeX at all, or required a separate server, or had it as an expensive add-on. With Actools, the XeLaTeX worker lives inside a Docker container. It builds once, caches, and is available to every environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;actools pdf-test          &lt;span class="c"&gt;# Verifies XeLaTeX is working&lt;/span&gt;
actools storage-info      &lt;span class="c"&gt;# Shows S3 config and PDF mode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PDFs generated by Drupal go directly to S3. No local storage. No egress fees with Cloudflare R2.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Preview Environments Part
&lt;/h2&gt;

&lt;p&gt;This one still surprises people when I show them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;actools branch feature-redesign
&lt;span class="c"&gt;# → Creates: dev-feature-redesign.yourdomain.com&lt;/span&gt;
&lt;span class="c"&gt;# → Full database clone&lt;/span&gt;
&lt;span class="c"&gt;# → Full files clone&lt;/span&gt;
&lt;span class="c"&gt;# → Isolated PHP-FPM container&lt;/span&gt;
&lt;span class="c"&gt;# → Own Redis namespace&lt;/span&gt;
&lt;span class="c"&gt;# → Automatic HTTPS&lt;/span&gt;

actools branch &lt;span class="nt"&gt;--list&lt;/span&gt;
actools branch &lt;span class="nt"&gt;--destroy&lt;/span&gt; feature-redesign
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pantheon charges extra for multidev environments. Acquia limits them by plan. With Actools they are unlimited and take about 90 seconds to spin up.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Observability Part
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;actools health
&lt;span class="c"&gt;# → Checks: web, database, cache, worker, storage&lt;/span&gt;
&lt;span class="c"&gt;# → Returns: green/yellow/red per component&lt;/span&gt;
&lt;span class="c"&gt;# → Auto-restarts failed containers&lt;/span&gt;

actools logs &lt;span class="nt"&gt;--tail&lt;/span&gt; 100
actools drush status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grafana dashboards are available at &lt;code&gt;grafana.yourdomain.com&lt;/code&gt; with Drupal-specific metrics out of the box.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Backup Part
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;actools backup
&lt;span class="c"&gt;# → Dumps database&lt;/span&gt;
&lt;span class="c"&gt;# → Archives files&lt;/span&gt;
&lt;span class="c"&gt;# → Encrypts with age&lt;/span&gt;
&lt;span class="c"&gt;# → Uploads to S3&lt;/span&gt;
&lt;span class="c"&gt;# → Tests restore in isolation&lt;/span&gt;
&lt;span class="c"&gt;# → Reports: backup verified&lt;/span&gt;

actools restore-test
&lt;span class="c"&gt;# → Pulls latest backup&lt;/span&gt;
&lt;span class="c"&gt;# → Restores to isolated environment&lt;/span&gt;
&lt;span class="c"&gt;# → Runs smoke tests&lt;/span&gt;
&lt;span class="c"&gt;# → Confirms data integrity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most managed hosts say "we take backups." Actools proves the backup works every time it runs.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Cannot Do (Honest)
&lt;/h2&gt;

&lt;p&gt;Managed hosts have large support teams. If something goes wrong at 3am, you can file a ticket.&lt;/p&gt;

&lt;p&gt;With Actools you are the support team. The health checks, the observability, the self-healing containers — they reduce the 3am events significantly. But they do not eliminate the possibility. If you are not comfortable being the operator of your own infrastructure, managed hosting is still the right answer for you.&lt;/p&gt;

&lt;p&gt;Actools is for teams and individuals who want control, want cost efficiency, and are comfortable running a VPS.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Acquia Basic&lt;/th&gt;
&lt;th&gt;Pantheon Performance&lt;/th&gt;
&lt;th&gt;Actools + Hetzner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monthly cost&lt;/td&gt;
&lt;td&gt;~€134&lt;/td&gt;
&lt;td&gt;~€179&lt;/td&gt;
&lt;td&gt;€10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview environments&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Extra cost&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XeLaTeX / custom workers&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full server access&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability (Grafana)&lt;/td&gt;
&lt;td&gt;Extra&lt;/td&gt;
&lt;td&gt;Extra&lt;/td&gt;
&lt;td&gt;Included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restore testing&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Automated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 provider choice&lt;/td&gt;
&lt;td&gt;Locked&lt;/td&gt;
&lt;td&gt;Locked&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The installer and full documentation are available at &lt;a href="https://feesix.com" rel="noopener noreferrer"&gt;feesix.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Hetzner VPS (CX22 or larger, €10/month)&lt;/li&gt;
&lt;li&gt;Ubuntu 24.04&lt;/li&gt;
&lt;li&gt;A domain pointing at the server
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone into a dedicated directory — important&lt;/span&gt;
&lt;span class="c"&gt;# The installer uses the directory it runs from as the project root&lt;/span&gt;
git clone https://github.com/actools-pl/actoolsDrupal.git
&lt;span class="nb"&gt;cd &lt;/span&gt;actoolsDrupal

&lt;span class="c"&gt;# Configure&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;actools.env.example actools.env
nano actools.env
&lt;span class="c"&gt;# Required: BASE_DOMAIN, DRUPAL_ADMIN_EMAIL&lt;/span&gt;
&lt;span class="c"&gt;# Everything else auto-generates&lt;/span&gt;

&lt;span class="c"&gt;# Install&lt;/span&gt;
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./actools.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. Drupal 11 with the full enterprise stack, running in under 10 minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One important note:&lt;/strong&gt; Always clone into a subdirectory as shown above. The installer creates all project files — &lt;code&gt;docker-compose.yml&lt;/code&gt;, &lt;code&gt;Caddyfile&lt;/code&gt;, &lt;code&gt;docroot/&lt;/code&gt;, &lt;code&gt;logs/&lt;/code&gt;, &lt;code&gt;backups/&lt;/code&gt; — relative to wherever &lt;code&gt;actools.sh&lt;/code&gt; lives. If you run it from your home directory directly, everything lands there. Clone first, then run.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is Coming
&lt;/h2&gt;

&lt;p&gt;Phase 4.5 is in progress: encrypted offsite backups, Cloudflare Tunnel for zero-trust networking, multi-user RBAC with audit trails, and a DNA/resurrection system that rebuilds a complete server from a single JSON snapshot in under 15 minutes.&lt;/p&gt;

&lt;p&gt;The goal is a platform that any serious Drupal team can run confidently without a managed hosting bill.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built on a €10 server. Running in production. Replacing a €134/month bill.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Questions or feedback? Reach me at &lt;a href="mailto:hello@feesix.com"&gt;hello@feesix.com&lt;/a&gt; or leave a comment below.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>drupal</category>
      <category>selfhosted</category>
      <category>devops</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
