<?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: brent alexis</title>
    <description>The latest articles on DEV Community by brent alexis (@ba796).</description>
    <link>https://dev.to/ba796</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4166918%2Ff179ab39-fb12-48f3-bad2-90db5716ecfd.png</url>
      <title>DEV Community: brent alexis</title>
      <link>https://dev.to/ba796</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ba796"/>
    <language>en</language>
    <item>
      <title>The Apache SSL line that looks right and still won't start</title>
      <dc:creator>brent alexis</dc:creator>
      <pubDate>Thu, 08 Oct 2026 12:45:00 +0000</pubDate>
      <link>https://dev.to/ba796/the-apache-ssl-line-that-looks-right-and-still-wont-start-58dc</link>
      <guid>https://dev.to/ba796/the-apache-ssl-line-that-looks-right-and-still-wont-start-58dc</guid>
      <description>&lt;p&gt;I built a free config generator for Nginx and Apache. Before shipping the SSL part, I ran every output against a real Nginx 1.27 and Apache 2.4 server. Using AI, I built a test sandbox instead of just reading the configs over.&lt;/p&gt;

&lt;p&gt;That saved me more than once. The Apache version had two errors, both on the same line, and both looked completely fine on screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;The goal was simple enough. Take a Let's Encrypt certificate and produce the Apache config for HTTPS with OCSP stapling turned on. Stapling lets your server send the certificate's "still valid" proof along with the handshake, so the visitor's browser doesn't have to go and ask the certificate authority itself.&lt;/p&gt;

&lt;p&gt;On Apache, stapling needs two directives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SSLUseStapling on&lt;/code&gt; turns stapling on.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SSLStaplingCache&lt;/code&gt; tells Apache where to keep the stapled responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Version 1 put everything inside the site's &lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;&lt;/code&gt; block, the way a lot of snippets online do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="sr"&gt; *:443&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;SSLEngine&lt;/span&gt; &lt;span class="ss"&gt;on&lt;/span&gt;
    &lt;span class="nc"&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
    &lt;span class="nc"&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
    &lt;span class="nc"&gt;SSLUseStapling&lt;/span&gt; &lt;span class="ss"&gt;on&lt;/span&gt;
    &lt;span class="nc"&gt;SSLStaplingCache&lt;/span&gt; "shared:SSL:10m"   &lt;span class="c"&gt;# two errors on this one line&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;VirtualHost&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads fine. But it isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error 1: Wrong place
&lt;/h2&gt;

&lt;p&gt;Apache didn't start. &lt;code&gt;apachectl configtest&lt;/code&gt; stopped with a syntax error on the &lt;code&gt;SSLStaplingCache&lt;/code&gt; line, saying the directive is "not allowed here".&lt;/p&gt;

&lt;p&gt;The reason is scope. In Apache's mod_ssl, &lt;code&gt;SSLUseStapling&lt;/code&gt; is allowed inside a &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt;, but &lt;code&gt;SSLStaplingCache&lt;/code&gt; is server config only. It sets up one cache shared by the whole server, so it must sit in the main config: &lt;code&gt;httpd.conf&lt;/code&gt;, or &lt;code&gt;ssl.conf&lt;/code&gt; / &lt;code&gt;mods-available/ssl.conf&lt;/code&gt; on Debian and Ubuntu. Put it inside any &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt; and Apache refuses the file.&lt;/p&gt;

&lt;p&gt;It's an easy mistake to make, because the two directives belong together, so they naturally end up next to each other in the same block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error 2: Wrong syntax
&lt;/h2&gt;

&lt;p&gt;After moving the line out of the &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt;, Apache still rejected it. This time it was the value.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;shared:SSL:10m&lt;/code&gt; is Nginx syntax, borrowed from Nginx's &lt;code&gt;ssl_session_cache&lt;/code&gt; directive. Apache uses its own cache providers, and the common one is &lt;code&gt;shmcb&lt;/code&gt; (shared memory, cyclic buffer), written as a path plus a size in bytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;SSLStaplingCache&lt;/span&gt; "shmcb:/tmp/ssl_stapling_cache(32768)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you're building something like this, you often write the Nginx and Apache outputs side by side. I was using AI to speed things up, got a bit lazy, and the Nginx habit slipped into the Apache side. A developer who knows Nginx might read &lt;code&gt;shared:SSL:10m&lt;/code&gt; and move on. Apache doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug in my own test setup
&lt;/h2&gt;

&lt;p&gt;One more lesson came from the sandbox itself. For a while, Apache seemed to just exit with no error at all. My test container had &lt;code&gt;ErrorLog&lt;/code&gt; pointing at a file, so when Apache died during startup, the error was written to a log file inside a container that had already stopped.&lt;/p&gt;

&lt;p&gt;Pointing &lt;code&gt;ErrorLog&lt;/code&gt; at &lt;code&gt;/dev/stderr&lt;/code&gt; for testing fixed it immediately, and the real error messages showed up. If you test Apache in Docker, do that first. Save yourself the headache!&lt;/p&gt;

&lt;p&gt;While I was in there, the testing also showed that the Apache output was missing &lt;code&gt;SSLSessionCache&lt;/code&gt;, which the Nginx side already had. It's the same kind of directive (server config only), and it uses &lt;code&gt;shmcb&lt;/code&gt; too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The config that works
&lt;/h2&gt;

&lt;p&gt;The fix was to split the output into two clearly labelled parts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Once, in the main server config (outside any &lt;code&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;SSLSessionCache&lt;/span&gt;  "shmcb:/tmp/ssl_scache(512000)"
&lt;span class="nc"&gt;SSLStaplingCache&lt;/span&gt; "shmcb:/tmp/ssl_stapling_cache(32768)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Inside your &lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;&lt;/code&gt; block:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;SSLEngine&lt;/span&gt; &lt;span class="ss"&gt;on&lt;/span&gt;
&lt;span class="nc"&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
&lt;span class="nc"&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
&lt;span class="nc"&gt;SSLProtocol&lt;/span&gt; -all +TLSv1.2 +TLSv1.3
&lt;span class="nc"&gt;SSLUseStapling&lt;/span&gt; &lt;span class="ss"&gt;on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test before you reload, so a mistake never takes the site down:&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;apachectl configtest &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload apache2   &lt;span class="c"&gt;# httpd on RHEL/Alma/Rocky/Fedora&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; means the reload only happens if the test passes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scope rules are invisible when you read config.&lt;/strong&gt; Nothing about &lt;code&gt;SSLStaplingCache&lt;/code&gt; looks different from &lt;code&gt;SSLUseStapling&lt;/code&gt;. Only the server knows which context each one is allowed in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing two servers side by side invites cross-contamination.&lt;/strong&gt; Nginx and Apache solve the same problems with different syntax, and it's easy to carry one over to the other. If you do it, test both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Looks right" isn't a test.&lt;/strong&gt; Running the actual binary caught two real errors in one line that several careful read-throughs missed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I wrote this post with help from an AI assistant. The testing and results are my own.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather skip the trial and error, my &lt;a href="https://proxyforge.tech/ssl-generator" rel="noopener noreferrer"&gt;ProxyForge SSL generator&lt;/a&gt; gives you the Certbot command plus the matching Nginx or Apache config, with the Apache output already split into the two parts above. It's free, needs no signup and runs in your browser. The &lt;a href="https://proxyforge.tech/docs#ssl-generator" rel="noopener noreferrer"&gt;how-to guide&lt;/a&gt; explains where each piece goes.&lt;/p&gt;

&lt;p&gt;Have you hit other Apache directives that are only allowed in one context? I'd like to hear about them, since they're exactly the kind of thing worth checking, and maybe adding to my tool.&lt;/p&gt;

</description>
      <category>apache</category>
      <category>devops</category>
      <category>ssl</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
