<?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: Daniel, Petrica Andrei-Daniel</title>
    <description>The latest articles on DEV Community by Daniel, Petrica Andrei-Daniel (@danielpetrica).</description>
    <link>https://dev.to/danielpetrica</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%2F254697%2F1f469a97-6b0b-46a6-a452-6e24c617843d.jpg</url>
      <title>DEV Community: Daniel, Petrica Andrei-Daniel</title>
      <link>https://dev.to/danielpetrica</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danielpetrica"/>
    <language>en</language>
    <item>
      <title>How to Replace Raw S3 URLs with a Laravel Image Proxy (and Keep Your CDN Cache)</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Mon, 15 Jun 2026 15:52:36 +0000</pubDate>
      <link>https://dev.to/danielpetrica/how-to-replace-raw-s3-urls-with-a-laravel-image-proxy-and-keep-your-cdn-cache-113n</link>
      <guid>https://dev.to/danielpetrica/how-to-replace-raw-s3-urls-with-a-laravel-image-proxy-and-keep-your-cdn-cache-113n</guid>
      <description>&lt;p&gt;&lt;a href="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%2Fa7caky1lflj9owxohkez.jpg" class="article-body-image-wrapper"&gt;&lt;img 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%2Fa7caky1lflj9owxohkez.jpg" alt="How to Replace Raw S3 URLs with a Laravel Image Proxy (and Keep Your CDN Cache)" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're serving images and media files directly from an S3-compatible object storage (like Hetzner Object Storage, AWS S3, or DigitalOcean Spaces), you're probably used to URLs that look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://storage.example.com/my-bucket/project/files/posts/hello-world/cover.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's ugly. It exposes your storage provider and bucket name. And if your bucket is private, you can't even serve those URLs directly. You'd need signed URLs or a proxy.&lt;/p&gt;

&lt;p&gt;Here's how I replaced all raw S3 media URLs on my Laravel blog with clean proxied paths through the application, while keeping 24-hour CDN caching for performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;We run a typical Laravel + Octane stack behind Traefik with Cloudflare. All media is stored on an S3-compatible object storage in two buckets: a private one for uploaded media (&lt;code&gt;project/files&lt;/code&gt;) and a public one for auto-generated Open Graph images (&lt;code&gt;project/og-images&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Originally, the app generated URLs directly to object storage using &lt;code&gt;Storage::url()&lt;/code&gt;. This meant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private bucket URLs were inaccessible (and switching to public was not an option)&lt;/li&gt;
&lt;li&gt;Provider details were exposed in every page's HTML&lt;/li&gt;
&lt;li&gt;No control over caching at the application level&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Build a URL helper
&lt;/h2&gt;

&lt;p&gt;First, I created a &lt;code&gt;MediaUrlBusiness&lt;/code&gt; class that centralizes URL generation for both disks. Instead of calling &lt;code&gt;Storage::disk('og-images')-&amp;gt;url($path)&lt;/code&gt; or &lt;code&gt;Storage::url($path)&lt;/code&gt; in blade templates, I now call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;MediaUrlBusiness&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forOgImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// → /storage/og-images/posts/slug.png&lt;/span&gt;
&lt;span class="nc"&gt;MediaUrlBusiness&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;forMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// → /storage/media/posts/slug/cover.png&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns a clean relative path like &lt;code&gt;/storage/og-images/...&lt;/code&gt;. All 6+ blade templates that previously generated raw S3 URLs now use this single helper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: The proxy controller
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ObjectProxyController&lt;/code&gt; catches all &lt;code&gt;/storage/{disk}/{path}&lt;/code&gt; requests. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validates the disk is one of the allowed ones (&lt;code&gt;media&lt;/code&gt; → private bucket, &lt;code&gt;og-images&lt;/code&gt; → public bucket)&lt;/li&gt;
&lt;li&gt;Resolves the full S3 key using the disk's configured prefix&lt;/li&gt;
&lt;li&gt;Streams the file from object storage using &lt;code&gt;response()-&amp;gt;stream()&lt;/code&gt; with proper &lt;code&gt;Content-Type&lt;/code&gt; and &lt;code&gt;Content-Length&lt;/code&gt; headers&lt;/li&gt;
&lt;li&gt;Sets a &lt;code&gt;Cache-Control: public, max-age=86400&lt;/code&gt; header so Cloudflare and browsers cache aggressively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the core of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$disk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Storage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$diskMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$diskSegment&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$disk&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;readStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fullPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;fpassthru&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$disk&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fullPath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'Content-Length'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$disk&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fullPath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s1"&gt;'Cache-Control'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'public, max-age=86400, immutable'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A detail that tripped me up: &lt;code&gt;Storage::download()&lt;/code&gt; and &lt;code&gt;streamDownload()&lt;/code&gt; buffer the entire file into memory. For large images, that wastes memory. Switching to &lt;code&gt;readStream() + response()-&amp;gt;stream()&lt;/code&gt; sends the file directly from S3 to the client without buffering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Laravel's S3 driver supports &lt;code&gt;fileSize()&lt;/code&gt;. For custom disks, use &lt;code&gt;$disk-&amp;gt;size()&lt;/code&gt; instead.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important: anything in the private bucket is now accessible through the proxy if someone guesses the path. Make sure that bucket only holds public-facing assets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 3: Route and middleware setup
&lt;/h2&gt;

&lt;p&gt;The proxy route lives in &lt;code&gt;routes/static.php&lt;/code&gt; alongside other cacheable frontend routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'/storage/{disk}/{path}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectProxyController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'path'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'storage.proxy'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also modified the &lt;code&gt;SetCacheControlHeader&lt;/code&gt; middleware to skip responses that already have a &lt;code&gt;Cache-Control&lt;/code&gt; header set (since the proxy controller sets its own). This way the middleware doesn't override our carefully tuned 24-hour cache policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Wire it up everywhere
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MediaUrlBusiness&lt;/code&gt; helper is now used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post, page, and tag show views, for both OG images and feature images&lt;/li&gt;
&lt;li&gt;Homepage and archive listings, for post card images&lt;/li&gt;
&lt;li&gt;Case study components, for service images&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OgImageBusiness&lt;/code&gt;, for storing and retrieving generated OG images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every call to &lt;code&gt;Storage::disk('og-images')-&amp;gt;url(...)&lt;/code&gt; or &lt;code&gt;Storage::url(...)&lt;/code&gt; was replaced with the appropriate &lt;code&gt;MediaUrlBusiness::for*()&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the admin panel?
&lt;/h2&gt;

&lt;p&gt;The Filament admin panel has its own media proxy. The existing &lt;code&gt;MediaProxyController&lt;/code&gt; handles CORS issues when editors browse and insert images in the RichEditor. That stays as-is; it's authenticated and not meant for public caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://storage.example.com/my-bucket/project/files/posts/hello-world/cover.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/storage/media/posts/hello-world/cover.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, provider-agnostic, and cache-friendly. The URL no longer leaks my storage provider or bucket name. And if I ever switch providers, I only need to change the disk configuration. The public URLs stay the same.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Need this for your site? If your team doesn't have the bandwidth to implement this, I can set it up for you: clean proxied image URLs, CDN caching, and private bucket security.&lt;/em&gt; &lt;a href="https://danielpetrica.com/work-with-me" rel="noopener noreferrer"&gt;&lt;em&gt;Get in touch →&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>devops</category>
      <category>objectstorage</category>
    </item>
    <item>
      <title>50,000 Spam Emails and a 3 AM Panic: What Happened When I Forgot About a Side Project</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Mon, 25 May 2026 14:28:57 +0000</pubDate>
      <link>https://dev.to/danielpetrica/50000-spam-emails-and-a-3-am-panic-what-happened-when-i-forgot-about-a-side-project-5190</link>
      <guid>https://dev.to/danielpetrica/50000-spam-emails-and-a-3-am-panic-what-happened-when-i-forgot-about-a-side-project-5190</guid>
      <description>&lt;p&gt;&lt;a href="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%2F33h3if0mhtkabfevhgb0.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F33h3if0mhtkabfevhgb0.png" alt="50,000 Spam Emails and a 3 AM Panic: What Happened When I Forgot About a Side Project" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version:&lt;/strong&gt; Someone exploited an outdated Livewire version on a dormant side project of mine. They stole my &lt;code&gt;.env&lt;/code&gt; file, used the Mailcoach API keys to send 50,000 spam emails, and I spent a panicked night tearing through every project I own trying to find the source.&lt;/p&gt;

&lt;p&gt;Here is the full story, what I learned, and why Docker saved me from a much worse outcome.&lt;/p&gt;

&lt;p&gt;It was Wednesday, May 20. I was in class when my phone buzzed with an email from Mailcoach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Your submissions have been blocked due to a high bounce rate or spam reports.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I read it. Felt that cold drop in my stomach. And then I had to put my phone away and finish class.&lt;/p&gt;

&lt;p&gt;There is a special kind of dread that comes from knowing something is wrong but not being able to look at it. I sat through the rest of my Japanese lesson with half my brain running through worst-case scenarios.&lt;/p&gt;

&lt;p&gt;Around 18:00, I finally opened my laptop.&lt;/p&gt;

&lt;h3&gt;
  
  
  The moment of terror
&lt;/h3&gt;

&lt;p&gt;I logged into Mailcoach and my heart stopped. Over 50,000 emails had been sent from my account. All of them spam. Phishing links. Going out under my name.&lt;/p&gt;

&lt;p&gt;I had never experienced anything like this before. I was shocked. My immediate reaction was to delete every single API token in Mailcoach and my GitHub API tokens. Then I wrote to their support team asking for help figuring out how this happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  The long night
&lt;/h3&gt;

&lt;p&gt;I spent the next nine hours reviewing every project I own.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;danielpetrica.com&lt;/code&gt;. &lt;code&gt;laraplugins.io&lt;/code&gt;. &lt;code&gt;adventcalendar.tech&lt;/code&gt;. And some other smaller, unused projects. Every small demo site, every experiment, every dormant project sitting on my server. I checked logs, checked file permissions, checked for anything unusual. Nothing.&lt;/p&gt;

&lt;p&gt;To make things worse, that same day Symfony announced 19 CVEs across their projects. My brain went there immediately. Was it Symfony? Was one of my sites running an affected version? I went down that rabbit hole for a while.&lt;/p&gt;

&lt;p&gt;Nothing.&lt;/p&gt;

&lt;p&gt;At 3 AM, I had to make a call. I secured what I could, changed what I could, and went to sleep. I was frustrated. I was tired. And I still had no idea what happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding the source
&lt;/h3&gt;

&lt;p&gt;The next day I kept digging. Project by project. And then I found it.&lt;/p&gt;

&lt;p&gt;A small side project. One of those things you build, launch, and forget about. It was running an outdated version of Livewire with a public CVE. I had not updated it. That was my fault.&lt;/p&gt;

&lt;p&gt;The attacker found it through automated scanning. These bots crawl the web looking for known vulnerabilities in exposed applications. They found Livewire, found the CVE, and were inside within hours. They uploaded a web admin script that let them read anything the Apache user had access to inside that Docker container.&lt;/p&gt;

&lt;p&gt;Including my &lt;code&gt;.env&lt;/code&gt; file. Which held my Mailcoach API keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Docker blessing
&lt;/h3&gt;

&lt;p&gt;Here is where things could have been much worse.&lt;/p&gt;

&lt;p&gt;That side project was running inside a Docker container. The attacker had access to that container, but they could not escape it. They could not reach my other projects, my other databases, or the host system itself. The blast radius was limited to that one service.&lt;/p&gt;

&lt;p&gt;I originally set up Docker Compose just as a convenience for myself. I never thought of it as a security measure in the beginning. But it ended up being the wall that stopped the attack from spreading.&lt;/p&gt;

&lt;h3&gt;
  
  
  The evidence I lost
&lt;/h3&gt;

&lt;p&gt;This part still stings.&lt;/p&gt;

&lt;p&gt;When I finally identified the compromised container, I did the natural thing. I took it down: &lt;code&gt;docker compose down -v&lt;/code&gt;. Volumes included.&lt;/p&gt;

&lt;p&gt;And just like that, the attacker's files were gone. The web shell, the logs of what they did, any clues about their entry point,all of it erased.&lt;/p&gt;

&lt;p&gt;I realized my mistake later. I should have copied the container's storage before killing it. I should have preserved the evidence. But in the moment, my only thought was, "Shut it down now."&lt;/p&gt;

&lt;p&gt;I spent the next few hours going through my reverse proxy logs instead. Those survived. They showed the attacker's pattern clearly. Automated scanners hit the site repeatedly. Once they confirmed the Livewire vulnerability, the actual compromise happened within hours. This was not a targeted attack on me. I was just another domain on a list.&lt;/p&gt;

&lt;p&gt;What scared me most was how fast everything happened. The scan, the exploit, the credential harvest, the spam campaign. It felt automated end-to-end. If AI is making these attacks faster and more efficient, we are all going to need to be much more proactive about monitoring and maintenance. Myself included.&lt;/p&gt;

&lt;h3&gt;
  
  
  The silver lining
&lt;/h3&gt;

&lt;p&gt;Mailcoach handled this better than I could have hoped.&lt;/p&gt;

&lt;p&gt;They noticed the spam spike before I did. They suspended my submissions proactively. When I reached out, they worked with me to investigate. And when the dust settled, they dropped the charges for those 50,000+ emails from my invoice entirely.&lt;/p&gt;

&lt;p&gt;That is the kind of provider behavior that builds loyalty for life.&lt;/p&gt;

&lt;p&gt;Thank you to the Mailcoach team.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I changed
&lt;/h3&gt;

&lt;p&gt;Since this happened, I have made a few changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I set up automated dependency update alerts for every project, including the dormant ones. If a project has a &lt;code&gt;composer.json&lt;/code&gt;, I get notified when its dependencies are outdated.&lt;/li&gt;
&lt;li&gt;I conducted a review of all my side projects. Some got updated. Some got archived. Some got shut down entirely.&lt;/li&gt;
&lt;li&gt;I reviewed my API token strategy. Tokens now have strict scopes and shorter lifespans where possible.&lt;/li&gt;
&lt;li&gt;I am also looking into environment variable management strategies and exploring how to better align them with my Docker setup.&lt;/li&gt;
&lt;li&gt;I accepted that I need better monitoring. A 15:52 alert that I cannot act on until 18:00 is useless if I do not have a plan for that gap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The uncomfortable truth
&lt;/h3&gt;

&lt;p&gt;This happened because I made a mistake. I had a public, dormant website with an outdated dependency. I knew better; I just did not prioritize it until I forgot about the site entirely.&lt;/p&gt;

&lt;p&gt;But the takeaway is not just "be more careful." It is that our industry has a long tail of forgotten projects that are ticking time bombs. Every developer I know has side projects gathering dust on a server somewhere. Those are exactly what the scanners are looking for.&lt;/p&gt;

&lt;p&gt;Go update your dependencies. Or shut down what you are not maintaining. Because the bots are not going to wait until you have time. I learned that the hard way.&lt;/p&gt;

&lt;p&gt;Have fun building. And update your Livewire, please.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; I was already convinced of this before, but now I am certain: Mailcoach is the best email tool for campaigns and transactional emails. Go check them out &lt;a href="https://www.mailcoach.app/solutions/solutions-for-developers/?via=danielBlogIncident&amp;amp;ref=danielpetrica.com" rel="noopener noreferrer"&gt;here (referral link)&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>personalprojects</category>
      <category>news</category>
      <category>ghost</category>
      <category>safety</category>
    </item>
    <item>
      <title>The State of Laravel Packages 2026</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Sat, 31 Jan 2026 23:00:00 +0000</pubDate>
      <link>https://dev.to/danielpetrica/the-state-of-laravel-packages-2026-35ce</link>
      <guid>https://dev.to/danielpetrica/the-state-of-laravel-packages-2026-35ce</guid>
      <description>&lt;p&gt;&lt;a href="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%2F4s220a6anl8v987yzzf9.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F4s220a6anl8v987yzzf9.png" alt="The State of Laravel Packages 2026" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the end of November, I shared a questionnaire to discover what the community thinks about the state of Laravel packages today. I wanted to focus on the real-world pain points developers face. To ensure I got busy developers to respond, I kept it short, under 3 minutes on average. &lt;/p&gt;

&lt;p&gt;From this findings &lt;a href="https://laraplugins.io/?ref=danielpetrica.com" rel="noopener noreferrer"&gt;Laraplugins.io&lt;/a&gt; was born. Now it indexes more than 16000 plugins. Go find their health status now&lt;/p&gt;

&lt;p&gt;Without an established audience, I managed to reach around 200 responses.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thank you to everyone who participated or shared it; the insights gathered were eye-opening.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article illustrates what the community had to say. &lt;/p&gt;

&lt;h2&gt;
  
  
  Get my updates in your &lt;strong&gt;inbox&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Register to be the first to receive my new articles on Laravel, DevOps, my projects, and the future of the Laravel package ecosystem.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                &amp;lt;span&amp;gt;Subscribe&amp;lt;/span&amp;gt;
                &amp;lt;span&amp;gt;&amp;lt;svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"&amp;gt;
    &amp;lt;g stroke-linecap="round" stroke-width="2" fill="currentColor" stroke="none" stroke-linejoin="round"&amp;gt;
        &amp;lt;g&amp;gt;
            &amp;lt;circle cx="4" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
            &amp;lt;circle cx="12" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
            &amp;lt;circle cx="20" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
        &amp;lt;/g&amp;gt;

    &amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&amp;lt;/span&amp;gt;



            Email sent! Check your inbox to complete your signup.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;No spam. Unsubscribe anytime. Thank You.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who responded?
&lt;/h3&gt;

&lt;p&gt;To ensure the data reflected active ecosystem users, I first asked how often respondents develop new features or applications using Laravel. &lt;/p&gt;

&lt;p&gt;82% develop new Laravel features &lt;strong&gt;Daily or Weekly&lt;/strong&gt;. That number grows to &lt;strong&gt;94%&lt;/strong&gt; if we include monthly respondents. This tells me the majority of you aren't just maintaining legacy code; you're actively choosing Laravel for new work. That's awesome to see. &lt;/p&gt;

&lt;p&gt;(Going forward, the data below focuses on this active daily/weekly/monthly cohort to ensure relevance.) &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fkkgh0udz8hy8u70j350m.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fkkgh0udz8hy8u70j350m.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How often do you develop new features or applications using Laravel?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Build vs. Buy" Mentality
&lt;/h3&gt;

&lt;p&gt;When needing standard functionality (e.g., SEO, Media handling, Payments), what is the default reaction? Do developers reinvent the wheel or look for existing solutions? &lt;/p&gt;

&lt;p&gt;The results show a strong preference for existing solutions. &lt;strong&gt;96%&lt;/strong&gt; of respondents indicated they either immediately look for existing packages/SDKs (65%) or search for packages first before potentially deciding to build it themselves (31%). &lt;/p&gt;

&lt;p&gt;This confirms that Laravel developers prefer not to rebuild standard functionality unless forced to. Remember that detail for later. &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fyc0nfu6pxetkdi05ynn6.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fyc0nfu6pxetkdi05ynn6.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;When you need standard functionality what is your default reaction?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do developers find packages?
&lt;/h3&gt;

&lt;p&gt;I was curious if my personal habit of just Googling everything was normal. It turns out, it is. (Note: Respondents could select multiple options). &lt;/p&gt;

&lt;p&gt;Unsurprisingly, &lt;strong&gt;Web Search (74%)&lt;/strong&gt; dominates. However, it is closely followed by &lt;strong&gt;Packagist (51%)&lt;/strong&gt; and community news sources like &lt;strong&gt;Laravel News or newsletters (49%)&lt;/strong&gt;. Interestingly, developers seem to trust curated news sources and general web results significantly more than &lt;strong&gt;GitHub search (42%)&lt;/strong&gt; or social media feeds &lt;strong&gt;(19%)&lt;/strong&gt; when looking for tools. So, a bit surprisingly, this means we choose to trust other developers' recommendations via news sites more than random posts on social media. &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fle8m8cnwampdqkp1m8it.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fle8m8cnwampdqkp1m8it.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Where do you primarily go to find Laravel packages today?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How heavy are our composer.json files?
&lt;/h3&gt;

&lt;p&gt;I asked how many third-party packages (excluding default Laravel dependencies) are in an average project to gauge the "baggage" we're willing to carry. &lt;/p&gt;

&lt;p&gt;Over half of the respondents &lt;strong&gt;(54%)&lt;/strong&gt; fall into the &lt;strong&gt;6–15 package&lt;/strong&gt; range. Given standard best practices today (involving tools like PHPStan, Pint, Debugbar, or Telescope), this feels normal. &lt;/p&gt;

&lt;p&gt;I was surprised that &lt;strong&gt;38%&lt;/strong&gt; managed to keep projects between &lt;strong&gt;0 and 5 packages,&lt;/strong&gt; that is impressive discipline! Honestly, how do you manage to keep it so low? Please send me a DM, I'm very curious. Finally, &lt;strong&gt;7%&lt;/strong&gt; have &lt;strong&gt;16 or more packages&lt;/strong&gt;. That seems heavy, how long does your composer update take at that point? Luckily Composer is fast, but still. &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F7rsnc7oei4tkylti7p9w.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F7rsnc7oei4tkylti7p9w.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Roughly how many third-party packages are in your average project?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Vetting Process
&lt;/h3&gt;

&lt;p&gt;How much time do you spend researching before typing composer require? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;61%&lt;/strong&gt; spend between &lt;strong&gt;5 and 30 minutes&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&amp;lt;5 minutes&lt;/strong&gt; was the next largest group with 19%
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30%&lt;/strong&gt; spend more than &lt;strong&gt;30 minutes&lt;/strong&gt; doing a deeper dive. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This suggests that for the majority, the criteria chosen for selection needs to be scannable quickly, things like update recency, documentation quality, and popularity, rather than deep code audits. We have what Italians call "&lt;em&gt;grilletto facile&lt;/em&gt;" (a quick trigger) for packages that look good on the surface. &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F9pibwzbuqqb5y6idz11z.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F9pibwzbuqqb5y6idz11z.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How much time do you typically spend researching and auditing a package&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When asked to rank the most important factors when choosing between similar packages, the results confirmed this: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Recency of updates / Maintenance status&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation quality&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Stars / Popularity&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Author reputation&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The quality and frequency of updates are clearly king. &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Forogqr5t5rvied6o33a5.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Forogqr5t5rvied6o33a5.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;What is the most important factor when choosing between two similar packages?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A related note on compatibility:&lt;/strong&gt; I also asked if you verify if a package supports your specific tech stack (e.g., Blade vs. Vue/React) before installing. &lt;strong&gt;56%&lt;/strong&gt; said yes, as compatibility is often an issue. &lt;strong&gt;32%&lt;/strong&gt; mainly use headless packages, and &lt;strong&gt;11%&lt;/strong&gt; don't check too much, planning to adapt the code anyway. &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fdhj8hg3w78mbk4ci7pse.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fdhj8hg3w78mbk4ci7pse.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Do you verify if a package supports the specific tech stack you use before installing?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Biggest Frustrations
&lt;/h3&gt;

&lt;p&gt;This was the most critical part of the survey: what makes developers unsatisfied with the current ecosystem? &lt;/p&gt;

&lt;p&gt;It is a statistical tie for the top frustration. &lt;strong&gt;70%&lt;/strong&gt; cited &lt;strong&gt;lack of documentation or usage examples&lt;/strong&gt; , while virtually the same amount cited the issue of &lt;strong&gt;too many abandoned or outdated packages&lt;/strong&gt; cluttering search results. &lt;/p&gt;

&lt;p&gt;We have all experienced searching for functionality and finding five packages that haven't been updated since Laravel 8.  &lt;/p&gt;

&lt;p&gt;In third place &lt;strong&gt;(28%)&lt;/strong&gt; was the difficulty of comparing features between similar packages. And finally, not knowing if a package is compatible with my Laravel version represents &lt;strong&gt;13%&lt;/strong&gt; of results.  &lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Foeullzkcnwvq101qtxzv.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Foeullzkcnwvq101qtxzv.png" alt="The State of Laravel Packages 2026" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;What is your biggest frustration when searching for a package?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Community Wish-list
&lt;/h3&gt;

&lt;p&gt;I finally asked an open-ended question: &lt;em&gt;"If you could wave a magic wand and improve one thing about the Laravel ecosystem today, what would it be?"&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;I received 32 wonderful, detailed responses. While some covered broader topics, the vast majority focused specifically on the pain of managing third-party packages. Here are some representative voices from the community: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the broader community:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"...less expensive Laracons..."&lt;/em&gt; . I can understand this! Have you heard of L&lt;a href="https://laravellive.jp/en?utm_source=danielpetrica_com&amp;amp;utm_medium=blog&amp;amp;utm_campaign=pluginreport" rel="noopener noreferrer"&gt;aravelLive.jp&lt;/a&gt;? The price is very low and japan is japan, we could even meet for a coffee there. &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"More popularity with employers"&lt;/em&gt; . We all want this. &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Laravel patterns often don't scale well. More education around team-oriented patterns..."&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"More focus on plain Laravel + Blade"&lt;/em&gt; and &lt;em&gt;"I want to make it more type safe..."&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On packages specifically (this is where it got really interesting):&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"Making keeping packages up to date for each Laravel version the norm. Many packages are abandoned after a few versions."&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Standardize package info presentation to include age of project, last update, version compatibility, preq, open issues."&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Less fragmentation of third party packages would be nice."&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Reduce the number of duplicate packages that do the same or similar functions."&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"A Laravel centric site with packages including their usages... a dedicated site would be better."&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also saw some direct debate in the responses, like requests for &lt;em&gt;"More livewire support, fewer paid libraries"&lt;/em&gt; sitting right next to a simple &lt;em&gt;"get rid of livewire"&lt;/em&gt;. The community has strong and mixed feelings! &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The data paints a clear picture: Laravel developers want to use packages, but the friction involved in finding reliable, well-documented, and up-to-date tools is a major pain point. The ecosystem is vibrant, but that vibrancy creates noise that is hard to filter. &lt;/p&gt;

&lt;p&gt;The recurring theme in your open-ended responses was a desire for a centralized, standardized way to evaluate packages specifically for Laravel. Those suggestions literally gave me an idea. &lt;/p&gt;

&lt;p&gt;Inspired by this data and your specific feedback, I started working on &lt;a href="https://laraplugins.io/?utm_source=danielpetrica_com&amp;amp;utm_medium=blog&amp;amp;utm_campaign=pluginreport" rel="noopener noreferrer"&gt;&lt;strong&gt;LaraPlugins.io&lt;/strong&gt;&lt;/a&gt; as an attempt to address these frustrations. It’s a new directory focused on helping developers find, compare, and check maintenance status for Laravel-specific packages. It can even be connected to your ai agent with a simple fast mcp connection now! See how here &lt;a href="https://laraplugins.io/mcp?ref=danielpetrica.com" rel="noopener noreferrer"&gt;https://laraplugins.io/mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The beta of the site is up but with an initial health score algorithm.&lt;br&gt;&lt;br&gt;
I don't pretend to have the perfect way to judge article healthy so please give the site a try then send me a feedback on the site health score system.&lt;br&gt;&lt;br&gt;
Only a collective effort can produce something really useful to all of us.&lt;br&gt;&lt;br&gt;
in the incoming AI development having a trustworthy directory would make AI agents able to pick healthy packages for the development project.&lt;/p&gt;

&lt;p&gt;P.S. Laravel is a trademark of Taylor Otwell. LaraPlugins.io is an independent, community-driven directory and is not officially affiliated with, endorsed by, or sponsored by Laravel or Taylor Otwell. Trademark usage is intended solely to identify the Laravel framework and its ecosystem packages.​&lt;/p&gt;

</description>
      <category>larapluginsio</category>
      <category>report</category>
      <category>laravel</category>
      <category>news</category>
    </item>
    <item>
      <title>LaraPlugins Devlog: Sub-Second Search, Vendor Profiles, and Building an AI Brain (MCP)</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Sun, 18 Jan 2026 18:44:26 +0000</pubDate>
      <link>https://dev.to/danielpetrica/laraplugins-devlog-sub-second-search-vendor-profiles-and-building-an-ai-brain-mcp-5ddp</link>
      <guid>https://dev.to/danielpetrica/laraplugins-devlog-sub-second-search-vendor-profiles-and-building-an-ai-brain-mcp-5ddp</guid>
      <description>&lt;p&gt;&lt;a href="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%2Fsg6bgconm8svvdnd1ogt.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fsg6bgconm8svvdnd1ogt.png" alt="LaraPlugins Devlog: Sub-Second Search, Vendor Profiles, and Building an AI Brain (MCP)" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you are building for scale, technical debt eventually knocks on the door, this weekend, I answered. Here is what shipped:&lt;/p&gt;

&lt;h2&gt;
  
  
  Sub-Second Search &amp;amp; Pagination Fixes
&lt;/h2&gt;

&lt;p&gt;Thanks to community feedback, I prioritized the "slow search" issue. Digging into the metrics, I found the culprit: classic N+1 query problems that were dragging down the &lt;code&gt;/plugins&lt;/code&gt; list response times.&lt;/p&gt;

&lt;p&gt;I optimized the underlying queries and eager-loaded the necessary relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get my updates in your &lt;strong&gt;inbox&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Register to be the first to receive my new articles on Laravel, DevOps, my projects, and the future of the Laravel package ecosystem.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                &amp;lt;span&amp;gt;Subscribe&amp;lt;/span&amp;gt;
                &amp;lt;span&amp;gt;&amp;lt;svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"&amp;gt;
    &amp;lt;g stroke-linecap="round" stroke-width="2" fill="currentColor" stroke="none" stroke-linejoin="round"&amp;gt;
        &amp;lt;g&amp;gt;
            &amp;lt;circle cx="4" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
            &amp;lt;circle cx="12" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
            &amp;lt;circle cx="20" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
        &amp;lt;/g&amp;gt;

    &amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&amp;lt;/span&amp;gt;



            Email sent! Check your inbox to complete your signup.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;No spam. Unsubscribe anytime. Thank you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt; : Search and pagination now load in under 1 second. &lt;a href="https://dev.to/danielpetrica/how-i-built-a-high-performance-directory-with-laravel-octane-and-filament-404p-temp-slug-7692170"&gt;Check here to se how i built the site for that&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Lesson&lt;/strong&gt; : Even experienced developers miss N+1 queries sometimes. This reinforces why optimization isn't just "nice to have" it is a core feature that requires constant observability. When you can't measure it, you can't fix it.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fexghr9xuuwh0rmihgk02.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fexghr9xuuwh0rmihgk02.png" alt="LaraPlugins Devlog: Sub-Second Search, Vendor Profiles, and Building an AI Brain (MCP)" width="800" height="442"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;LaraPlugins screenshot, what will be your next plugin?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New "Vendor" &amp;amp; "Maintainer" Pages
&lt;/h2&gt;

&lt;p&gt;I have started rolling out dedicated pages for plugin vendors and maintainers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current State&lt;/strong&gt; : Basic listings are live, with clean profiles for major vendors like Spatie, BeyondCode, and others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://laraplugins.io/vendors/spatie?ref=danielpetrica.com" rel="noopener noreferrer"&gt;&lt;img 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%2Fjfsx686af10qsz0nndph.png" alt="LaraPlugins Devlog: Sub-Second Search, Vendor Profiles, and Building an AI Brain (MCP)" width="800" height="481"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Spatie Vendor Page, showcasing all the plugins where they are the vendor.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Goal&lt;/strong&gt; : Turn these into rich profiles with insightful stats like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total downloads across all packages&lt;/li&gt;
&lt;li&gt;Average health score of maintained packages&lt;/li&gt;
&lt;li&gt;Update frequency and responsiveness&lt;/li&gt;
&lt;li&gt;Community trust indicators&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;What specific data points would you want to see on a Maintainer's profile to judge the quality of their work? Let me know in the comments your feedback drives this roadmap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With these new pages my site reached the 10k pages count, are you wondering how I host it to allow for such a size? &lt;a href="https://danielpetrica.com/a-production-ready-laravel-architecture-with-traefik-and-frankenphp/" rel="noopener noreferrer"&gt;Check my stack in this dedicated article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the "Brain" (MCP Server)
&lt;/h2&gt;

&lt;p&gt;This is the most exciting update. I am actively building a &lt;strong&gt;Model Context Protocol (MCP) server&lt;/strong&gt; for LaraPlugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Vision&lt;/strong&gt; : Enable AI agents (like Claude or Cursor) to query my directory directly. Instead of hallucinating packages or using outdated packages due to their cut date, your AI editor could ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"What's the best PDF generation package for Laravel?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Show me the most actively maintained charting libraries"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Find packages that solve authentication with minimal overhead"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI agent would query LaraPlugins in real-time, pulling verified, healthy packages with actual health scores containing "pdf generation" or pdf. No more guessing. No more outdated recommendations. The agent would be then able to choose a plugin based on their health status, php and laravel compatibility, maintenance status and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status&lt;/strong&gt; : The server is live, but search integration is still a Work In Progress. I am currently refining the caching strategy, since Cloudflare cannot easily cache these dynamic API hits, to ensure stability and performance before opening it to a broader audience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why This Matters: Right now, AI models hallucinate package recommendations because they were trained on static data. By providing a real-time MCP interface, I hope to solve a real problem: How do AI agents find the healthiest, most actively maintained Laravel packages?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quality of Life Updates
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Improved version compatibility badges on plugin cards (clearer visual)&lt;/li&gt;
&lt;li&gt;Refined the "Health Score" algorithm (still tuning this, signals are hard!)&lt;/li&gt;
&lt;li&gt;Added breadcrumb navigation to vendors and maintainers for improved discoverability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Tomorrow is for polishing. I will be finalizing the MCP search integration and ensuring the new Vendor index pages are SEO-ready for organic discovery.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For you&lt;/strong&gt; : Give the new search a spin and tell me if it feels snappier. Does the sub-second speed make a difference in how you explore packages? As always, your feedback drives this roadmap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What's coming next&lt;/strong&gt; : In February, I am building curated collections ("Featured: Filament Ecosystem", "Top 10 Database Packages") and opening early access to the MCP server for beta testers. If you want to be notified when the MCP is ready, drop a comment or reach out in any way.&lt;/p&gt;

&lt;p&gt;Until then, happy package hunting.&lt;/p&gt;

</description>
      <category>larapluginsio</category>
      <category>news</category>
      <category>personalprojects</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I built a high-performance directory with Laravel Octane and Filament</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Sun, 11 Jan 2026 12:06:03 +0000</pubDate>
      <link>https://dev.to/danielpetrica/how-i-built-a-high-performance-directory-with-laravel-octane-and-filament-5b4l</link>
      <guid>https://dev.to/danielpetrica/how-i-built-a-high-performance-directory-with-laravel-octane-and-filament-5b4l</guid>
      <description>&lt;p&gt;&lt;a href="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%2Fzs4g5cpir255wm4dwuom.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fzs4g5cpir255wm4dwuom.png" alt="How I built a high-performance directory with Laravel Octane and Filament" width="799" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back when I launched the survey on the state of the Laravel plugin ecosystem, one statistic stood out immediately:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;70%+ of developers spend between 5 and 30 minutes just to determine if a plugin is healthy enough to install&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is " &lt;strong&gt;Dependency Anxiety.&lt;/strong&gt;" It’s the recurring cost we pay every time we search for a package or audit our &lt;code&gt;composer.json&lt;/code&gt;. Is this package abandoned? Does it support PHP 8.5? Are the tests passing? Multiply those 30 minutes by every package in your stack, and the productivity loss is massive.&lt;/p&gt;

&lt;p&gt;To solve this, I built &lt;strong&gt;Laraplugins.io&lt;/strong&gt; , an automated intelligence tool designed to do that vetting for you and display it to you so you can get a pretty good idea of the health status in seconds.&lt;/p&gt;

&lt;p&gt;I launched LaraPlugins.io on product hunt today. Please help me get it in front of developers with and upvote and tell me in the comments over there what you would change about my health score algorithm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.producthunt.com/products/laraplugins-io?utm_source=other&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Upvote on product hunt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F2ks2n95ciavx9yaweh69.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F2ks2n95ciavx9yaweh69.png" alt="How I built a high-performance directory with Laravel Octane and Filament" width="799" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Built for Speed and Scale
&lt;/h2&gt;

&lt;p&gt;As a DevOps and developers, I wanted the infrastructure to be as robust as the data it serves. I designed a high-performance architecture capable of handling heavy traffic on a single multi-site VPS running over 30 projects and nearly 100 Docker containers. here more info if curious about my &lt;a href="https://danielpetrica.com/a-production-ready-laravel-architecture-with-traefik-and-frankenphp/" rel="noopener noreferrer"&gt;production-ready FrankenPHP setup.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;The application runs on a modern, containerized stack optimized for concurrency and low latency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Laravel Octane with FrankenPHP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing:&lt;/strong&gt; Traefik Reverse Proxy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching:&lt;/strong&gt; Redis &amp;amp; Cloudflare CDN&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; Docker Compose&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Request Lifecycle
&lt;/h2&gt;

&lt;p&gt;The flow is designed to minimize hit-rate on the application server:&lt;br&gt;&lt;br&gt;
&lt;code&gt;User -&amp;gt; Cloudflare CDN -&amp;gt; Traefik -&amp;gt; FrankenPHP (Octane) -&amp;gt; Redis&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Edge Caching:&lt;/strong&gt; Public pages are cached by Cloudflare for 2 hours. This drastically reduces server load by serving static content directly from the edge.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Routing:&lt;/strong&gt; When traffic reaches my VPS, Traefik handles the routing. It ensures fast, reliable directing of requests across the dozens of micro-services and sites running in parallel.​&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory Bootstrapping:&lt;/strong&gt; Finally, Laravel Octane and FrankenPHP take over. Because the application stays booted in memory, we eliminate the traditional PHP-FPM overhead, ensuring responses are nearly instantaneous.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The "Health Score" Algorithm
&lt;/h2&gt;

&lt;p&gt;The core of Laraplugins.io is the Health Score. It’s not a magic number, but an aggregate of about 10 key signals that determine a package's viability.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Update Recency
&lt;/h2&gt;

&lt;p&gt;This is the baseline. Developers need active maintenance. I track the last commit date and release history to ensure you aren't installing abandonware.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Version Compatibility
&lt;/h2&gt;

&lt;p&gt;I rigorously check &lt;code&gt;composer.json&lt;/code&gt; constraints to verify active support for modern Laravel and PHP versions. If a package is stuck on Laravel 9, you need to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The "Archived" Penalty
&lt;/h2&gt;

&lt;p&gt;If a project is archived on GitHub, we apply a heavy penalty. This marks a definitive end of life for the package, and it should generally be avoided for new projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Normalized Download Stats
&lt;/h2&gt;

&lt;p&gt;We monitor download counts, but we’ve intentionally reduced their weight in the final score. We want to highlight quality, not just popularity. This ensures new, high-quality plugins aren't unfairly penalized just because they haven't been around for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Best Practices &amp;amp; Quality
&lt;/h2&gt;

&lt;p&gt;Finally, we scan for indicators of a mature engineering culture: presence of CI/CD pipelines, active test suites, and valid licenses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback Welcome
&lt;/h2&gt;

&lt;p&gt;The Health Score is currently in beta. I’m building this for the community, so I want to hear from you. What signals do you look for before composer require-ing a new package?&lt;/p&gt;

&lt;p&gt;Let me know your thoughts, and check out the launch on&lt;a href="https://www.producthunt.com/products/laraplugins-io?utm_source=danielpetrica.com&amp;amp;utm_medium=blog" rel="noopener noreferrer"&gt;product hunt please&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>tool</category>
      <category>traefik</category>
      <category>personalprojects</category>
    </item>
    <item>
      <title>My new project: Coz.jp</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Sun, 09 Nov 2025 06:06:40 +0000</pubDate>
      <link>https://dev.to/danielpetrica/my-new-project-cozjp-45o</link>
      <guid>https://dev.to/danielpetrica/my-new-project-cozjp-45o</guid>
      <description>&lt;p&gt;Hello, Dev Community! I'm excited to finally pull back the curtain on my latest side project: Coz.jp, a new link shortening service.&lt;/p&gt;

&lt;p&gt;While "yet another link shortener" might sound simple, the goal here was to build something fast, reliable, and deeply integrated, all while using a modern and scalable tech stack. I want to share a little bit about what it does and the architecture I chose.&lt;/p&gt;

&lt;p&gt;Why I Built It&lt;/p&gt;

&lt;p&gt;As a developer, I've always needed a link shortener that gives me full control after the link is created. That's what Coz.jp is all about: fast creation, but also the ability to go back and fix errors by editing the target URL, or deleting the link entirely. It focuses on:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fast and Reliable URL Shortening: Speed is non-negotiable for link redirects.

Complete Link Management: Easily fix mistakes or update destinations after publishing.

Privacy-Friendly Analytics: Gain insights without compromising user security.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The Technical Core: My Stack&lt;/p&gt;

&lt;p&gt;For a project like this, I needed a setup that was robust, easy to deploy, and scalable. I went with a modern, containerized architecture that uses some of my favorite tools:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Framework: Laravel The back-end is powered by Laravel. Its elegant syntax and robust features made developing the API endpoints and the link management dashboard incredibly efficient. Laravel's Eloquent ORM provides a secure and structured way to handle the thousands of daily redirects.

Containerization: Docker Compose Everything runs inside Docker Compose. This ensures that the local development environment is an exact mirror of the production environment, eliminating the dreaded "it works on my machine" problem and making deployment rock-solid.

Database: MySQL The reliable backbone of the application is MySQL. It handles the quick lookups required for redirects and securely stores all the user and link data.

Reverse Proxy: Traefik I used Traefik as the edge router. Traefik handles all the incoming traffic, manages HTTPS certificates automatically, and routes traffic efficiently to the correct Docker containers. This setup gives me excellent performance and a truly scalable, production-ready infrastructure.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ready for Your Workflow&lt;/p&gt;

&lt;p&gt;One of the key features I focused on was developer and business integration. Coz.jp offers:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full API Integration: Ready for you to integrate into scripts or custom applications.

N8N Node: For those using low-code automation, I've built an n8n node to allow seamless integration into your automated workflows.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can manage your links with a simple email verification process, ensuring only you control your shortened URLs.&lt;/p&gt;

&lt;p&gt;Try It Out!&lt;/p&gt;

&lt;p&gt;I'd love for you to check it out. &lt;a&gt;You can login and Start your free trial today.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Production-Ready Laravel Architecture with Traefik and FrankenPHP</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Sun, 09 Nov 2025 05:49:04 +0000</pubDate>
      <link>https://dev.to/danielpetrica/a-production-ready-laravel-architecture-with-traefik-and-frankenphp-1led</link>
      <guid>https://dev.to/danielpetrica/a-production-ready-laravel-architecture-with-traefik-and-frankenphp-1led</guid>
      <description>&lt;p&gt;Laravel is a very performant framework, but a standard architecture has one big flaw derived from how PHP works: It has to rebuild the entire framework on every single request.&lt;/p&gt;

&lt;p&gt;Even with optimizations, this process still takes 40 to 60 ms on my machine with PHP 8.4. Luckily, for years, the PHP and Laravel worlds have had a solution that dramatically reduces this load time: Laravel Octane and FrankenPHP. The booting time for the Laravel framework can drop to just 4 to 6 ms per request. Incredible, isn't it?&lt;/p&gt;

&lt;p&gt;Now, if you're new to Laravel Octane or FrankenPHP, you may wonder: How is this possible?&lt;/p&gt;

&lt;p&gt;The simple answer is that the framework is kept in memory. After FrankenPHP starts, Laravel is always ready to serve requests without a full reboot. The real explanation is more complex and out of scope for this article. If you're curious, you can read the official Laravel Octane and FrankenPHP docs for a deeper dive.&lt;/p&gt;

&lt;p&gt;read the full article at: &lt;a href="https://coz.jp/IWz4E3" rel="noopener noreferrer"&gt;DanielPetrica.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>webdev</category>
      <category>programming</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Laravel and Traefik: Dynamic Configuration for Effortless Multi-Domain Management</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Sat, 13 Sep 2025 16:34:05 +0000</pubDate>
      <link>https://dev.to/danielpetrica/laravel-and-traefik-dynamic-configuration-for-effortless-multi-domain-management-4kni</link>
      <guid>https://dev.to/danielpetrica/laravel-and-traefik-dynamic-configuration-for-effortless-multi-domain-management-4kni</guid>
      <description>&lt;p&gt;&lt;a href="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%2F3xpmk0a1j9qa9nvo0l6d.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F3xpmk0a1j9qa9nvo0l6d.png" alt="Laravel and Traefik: Dynamic Configuration for Effortless Multi-Domain Management" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After finishing my full-time employment, I suddenly found myself with a lot of free time. To make use of it, I decided to stay up to date by working on some new side projects and experiments.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge: Dynamic Multi-Domain Support in Laravel with Traefik
&lt;/h3&gt;

&lt;p&gt;One of these experiments was related to supporting multiple domains in Laravel in a dynamic way. I initially found this relatively easy, but in a hypothetical production environment, handling everything automatically would not be quite as seamless. For example, Traefik usually relies on label-based or file-based configurations, which means the &lt;em&gt;dynamic&lt;/em&gt; part disappears entirely, leaving you with one big configuration file to manage manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discovering Traefik’s HTTP Configuration Provider
&lt;/h3&gt;

&lt;p&gt;Just when I was about to abandon this project, I remembered the existence of the HTTP configuration provider in the Traefik documentation. According to the docs, it allows you to configure Traefik by pointing it to a specific URL that returns either a JSON or YAML configuration.&lt;/p&gt;

&lt;p&gt;That’s when inspiration struck: I could configure Laravel to expose a JSON configuration representing the router setup. This configuration would then point to a single service defined by Docker service labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Docker Service Labels
&lt;/h3&gt;

&lt;p&gt;With some blind trust, I jumped into implementing the idea. Creating the service labels was fairly easy. I also included a default domain host to ensure I always had an accessible admin interface. Here’s the snippet from my &lt;code&gt;compose.yaml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;     &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.example-name-https.rule=Host(`example-name`)&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.example-name-https.tls=true&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.example-name-service.loadbalancer.server.port=80&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.example-name-https.tls.certresolver=cloudflare&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.example-name-https.entrypoints=websecure&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.example-name-https.middlewares=forward-auth_blog-network"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.middlewares.forward-auth_example-name.headers.customrequestheaders.X-Forwarded-Proto=https"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.middlewares.forward-auth_example-name.headers.customrequestheaders.X-Forwarded-Host=example-name"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generating the Dynamic Configuration in Laravel
&lt;/h2&gt;

&lt;p&gt;On the Laravel side, I was able to expose a JSON structure fairly easily. Since I had a collection of domains to generate, I prepared a multidimensional array like the one in the snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'routers'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nv"&gt;$domainName&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-https'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'rule'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Host(`'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'`)'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'tls'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'service'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$serviceName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'middlewares'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$middlewareName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'middlewares'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nv"&gt;$middlewareName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'headers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'customrequestheaders'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'X-Forwarded-Proto'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'X-Forwarded-Host'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re already familiar with YAML or Traefik configuration, you can see this structure is very similar to the earlier Docker labels example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring Traefik to Consume Laravel’s Endpoint
&lt;/h3&gt;

&lt;p&gt;At this point, all I had to do was tell Traefik to call this new Laravel-powered endpoint. In &lt;code&gt;traefik.yml&lt;/code&gt;, I went to the &lt;code&gt;providers&lt;/code&gt; section and added the following HTTP provider configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://admin.example.com/internal/traefik_config"&lt;/span&gt;
  &lt;span class="na"&gt;pollInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15s"&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;customRequestHeaders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;X-Traefik-Passphrase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yoursecrettoken"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup is straightforward. You specify the endpoint (reachable from the Traefik container), configure the polling interval to tell Traefik how often it should check for updates, and optionally add headers to secure requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Setback: JSON Format Issues
&lt;/h3&gt;

&lt;p&gt;At this point I tested everything, hopeful that it would just work. Obviously, that wasn’t the case. After trying different versions and settings — and reading through forum discussions — I realized nobody had been able to get the JSON HTTP provider working properly. It made me suspect the documentation was outdated, so I started looking for alternatives.&lt;/p&gt;

&lt;p&gt;The breakthrough came when I decided to serve the configuration in YAML instead of JSON. I chose the &lt;code&gt;symfony/yaml&lt;/code&gt; library to convert my Laravel arrays into YAML format easily. The updated Laravel response looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Yaml&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'text/yaml'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final Results and Practical Benefits
&lt;/h3&gt;

&lt;p&gt;After configuring Cloudflare to point to the correct server and managing domains through Laravel, I achieved the dynamic multi-domain setup I aimed for. Traefik not only serves the domains correctly but also respects domain removals—after the polling interval, removed domains cease to be reachable.&lt;/p&gt;

&lt;p&gt;This seamless integration between Laravel and Traefik solves a complex problem and will form the foundation for a new tool I’m developing to improve Laravel developers’ workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want to Stay Updated?
&lt;/h2&gt;

&lt;p&gt;If you’re interested in early updates, pre-launch offers, or beta invitations for this tool, please subscribe to my website. Your support means a lot on this journey!&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;This project is a proof of concept showcasing how dynamic domain routing can be effectively managed by Laravel in conjunction with Traefik, combining automation and flexibility for scalable deployments.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>guides</category>
      <category>personalprojects</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Self-Hosting n8n with Docker Compose and Traefik for AI-Powered Workflow Automation</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Mon, 07 Jul 2025 22:27:10 +0000</pubDate>
      <link>https://dev.to/danielpetrica/self-hosting-n8n-with-docker-compose-and-traefik-for-ai-powered-workflow-automation-2efc</link>
      <guid>https://dev.to/danielpetrica/self-hosting-n8n-with-docker-compose-and-traefik-for-ai-powered-workflow-automation-2efc</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Tired of juggling apps and manual tasks?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1677442135703-1787eea5ce01%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDE4fHxhaSUyMGFnZW50fGVufDB8fHx8MTc1MTg4MzUzNnww%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1677442135703-1787eea5ce01%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDE4fHxhaSUyMGFnZW50fGVufDB8fHx8MTc1MTg4MzUzNnww%26ixlib%3Drb-4.1.0%26q%3D80%26w%3D2000" alt="Self-Hosting n8n with Docker Compose and Traefik for AI-Powered Workflow Automation" width="2000" height="1125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Self-hosting n8n could be a game-changer. It’s a powerful, open-source automation tool, and setting it up yourself using Docker Compose and Traefik makes it both flexible and super accessible. I'll walk you through the setup and show off the cool AI features that really make n8n shine.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;So, what exactly is n8n?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Think of n8n as your digital duct tape. It's a free, open-source tool that lets you visually connect different apps and services to automate just about any workflow you can imagine. Drag and drop nodes to build sequences that handle all those boring, repetitive tasks for you. It saves a ton of time and gives you way more control over your data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want my expertize applied to you company? Contact me
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;n8n's Secret Sauce: AI Power&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;n8n isn't just about simple "if this, then that" rules anymore. It's evolved into a legit platform for building &lt;em&gt;smart&lt;/em&gt;, AI-driven applications. How? By using something called "agentic AI." This means your workflows can actually make decisions, understand context, and interact with your data intelligently, not just follow a rigid script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here’s what makes the AI side so powerful:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The AI Agent Node:&lt;/strong&gt; This is the brains of the operation. It processes info, makes choices, and uses built-in "tools" to talk to other apps or data sources. It connects to big AI models like OpenAI's GPT, Google's Gemini, or Anthropic's Claude to understand what you need and give smart replies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangChain Built Right In:&lt;/strong&gt; n8n plays nicely with LangChain, a popular framework for building complex AI logic. This means you can create chains of AI actions or even agents that decide &lt;em&gt;which&lt;/em&gt; actions to take next, all within your workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talk to Your Data (Vector DBs):&lt;/strong&gt; Connect n8n to vector databases like Pinecone or Supabase, or use its simple built-in memory store. This is key for building RAG systems – where the AI can pull answers &lt;em&gt;from your own private docs or data&lt;/em&gt;, making it super relevant and useful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endless Possibilities:&lt;/strong&gt; With these tools, you can build things like: smart chatbots for customers, AI assistants that summarize your emails and book meetings, or systems that dig insights out of messy, unstructured data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What You'll Need Before We Start&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Don't sweat it, it's mostly standard gear for self-hosters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker &amp;amp; Docker Compose:&lt;/strong&gt; Make sure they're installed and running. (Docker Compose usually comes bundled with Docker these days).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traefik:&lt;/strong&gt; You'll need this running for your reverse proxy. &lt;em&gt;(If you're not set up yet, check out this guide on configuring Traefik).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Domain Name:&lt;/strong&gt; Grab a domain or subdomain to point to your n8n instance (places like Namecheap often have domains starting around $2).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Docker Compose Setup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We'll use a &lt;code&gt;compose.yaml&lt;/code&gt; file to spin up both n8n and its database (we're using PostgreSQL here). Traefik integration is handled smoothly with labels right in the file – it takes care of routing traffic and HTTPS automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the &lt;code&gt;compose.yaml&lt;/code&gt; file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8nio/n8n&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:5678:5678"&lt;/span&gt; &lt;span class="c1"&gt;# Only exposed locally, Traefik handles external access&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_TYPE=postgresdb&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_POSTGRESDB_HOST=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_POSTGRESDB_PORT=5432&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_POSTGRESDB_DATABASE=${POSTGRES_DB}&lt;/span&gt; &lt;span class="c1"&gt;# Comes from .env file&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_POSTGRESDB_USER=${POSTGRES_USER}&lt;/span&gt; &lt;span class="c1"&gt;# Comes from .env file&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt; &lt;span class="c1"&gt;# Comes from .env file&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_FUNCTION_ALLOW_EXTERNAL=langchain&lt;/span&gt; &lt;span class="c1"&gt;# Important for LangChain nodes!&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;n8n_data:/home/node/.n8n&lt;/span&gt; &lt;span class="c1"&gt;# Persist your workflows and settings&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Traefik magic happens here&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.n8n.rule=Host(`n8n.yourdomain.com`)"&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt; REPLACE WITH YOUR DOMAIN!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.n8n.entrypoints=websecure"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.n8n.tls.certresolver=myresolver"&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt; REPLACE 'myresolver' with your Traefik resolver name!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.services.n8n.loadbalancer.server.port=5678"&lt;/span&gt;

  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:14&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n_postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=${POSTGRES_DB}&lt;/span&gt; &lt;span class="c1"&gt;# From .env&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=${POSTGRES_USER}&lt;/span&gt; &lt;span class="c1"&gt;# From .env&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt; &lt;span class="c1"&gt;# From .env&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres_data:/var/lib/postgresql/data&lt;/span&gt; &lt;span class="c1"&gt;# Persist your database&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Assumes your Traefik network already exists&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Don't forget the .env file!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the same folder as your &lt;code&gt;compose.yaml&lt;/code&gt; to keep your database secrets safe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;n8n&lt;/span&gt;
&lt;span class="py"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;n8nuser&lt;/span&gt;
&lt;span class="py"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;a_very_strong_and_secret_password # Make it a good one!&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Let's Get n8n Running!&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Make a Home:&lt;/strong&gt; Create a directory for your n8n setup and save both the &lt;code&gt;compose.yaml&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; files inside it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traefik Takes Over:&lt;/strong&gt; Traefik should automatically spot your new service, grab an SSL certificate, and start routing traffic to &lt;code&gt;https://n8n.yourdomain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Almost There!&lt;/strong&gt; Once the containers are running (give it a minute after the command finishes), open your domain in a web browser. The n8n web interface will greet you and guide you through the initial user setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breathe Easy:&lt;/strong&gt; Notice the n8n port (&lt;code&gt;5678&lt;/code&gt;) is only exposed &lt;em&gt;locally&lt;/em&gt; on your server. Traefik is the secure gatekeeper handling all outside traffic. we can go even further, on my server I don't even expose that port internally as it's not needed and better not expose things we don't need. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Fire it Up:&lt;/strong&gt; Open a terminal, navigate to that directory, and run:&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 up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Your self-hosted n8n automation playground is ready. Go build something awesome!&lt;/p&gt;

&lt;p&gt;Want to learn how to secure your database? I have an article about that&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;p&gt;Easy database backups with docker-compose&lt;/p&gt;

&lt;p&gt;I implemented a backup tool for my new docker compose and traefik stack to help save and restore my databases and avoid loss of data&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fgnm0rqub1ucpzzz5whyu.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fgnm0rqub1ucpzzz5whyu.png" alt="Self-Hosting n8n with Docker Compose and Traefik for AI-Powered Workflow Automation" width="256" height="256"&gt;&lt;/a&gt;Daniel PetricaDaniel, Andrei-Daniel Petrica&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdanielpetrica.com%2Fcontent%2Fimages%2Fthumbnail%2Fphoto-1575729853562-e3ad7084c28d" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdanielpetrica.com%2Fcontent%2Fimages%2Fthumbnail%2Fphoto-1575729853562-e3ad7084c28d" alt="Self-Hosting n8n with Docker Compose and Traefik for AI-Powered Workflow Automation" width="2000" height="1333"&gt;&lt;/a&gt;&lt;br&gt;
](&lt;a href="https://danielpetrica.com/easy-database-backups-with-docker-compose/" rel="noopener noreferrer"&gt;https://danielpetrica.com/easy-database-backups-with-docker-compose/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If N8N is not your sauce active pieces is actually a great compelling alternative too&lt;/p&gt;

&lt;p&gt;[&lt;/p&gt;

&lt;p&gt;Install Activepieces with Docker &amp;amp; Traefik for self-hosted automation&lt;/p&gt;

&lt;p&gt;Activepieces is an open-source automation tool enabling users to create custom workflows across many apps. We’ll install it on docker and traefik&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fdy1lceo27d0zozzki0mr.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fdy1lceo27d0zozzki0mr.png" alt="Self-Hosting n8n with Docker Compose and Traefik for AI-Powered Workflow Automation" width="256" height="256"&gt;&lt;/a&gt;Daniel PetricaDaniel, Andrei-Daniel Petrica&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2F41qqvjfbnsee03485a5q.webp" class="article-body-image-wrapper"&gt;&lt;img 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%2F41qqvjfbnsee03485a5q.webp" alt="Self-Hosting n8n with Docker Compose and Traefik for AI-Powered Workflow Automation" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
](&lt;a href="https://danielpetrica.com/installing-activepieces-with-docker-compose-and-traefik/" rel="noopener noreferrer"&gt;https://danielpetrica.com/installing-activepieces-with-docker-compose-and-traefik/&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Want my expertize applied to you company? Contact me
&lt;/h2&gt;

</description>
      <category>ai</category>
      <category>guides</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Tired of Manual Calendar Management? I Was Too. So I Built This Tool</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Mon, 07 Jul 2025 22:21:06 +0000</pubDate>
      <link>https://dev.to/danielpetrica/tired-of-manual-calendar-management-i-was-too-so-i-built-this-tool-4p36</link>
      <guid>https://dev.to/danielpetrica/tired-of-manual-calendar-management-i-was-too-so-i-built-this-tool-4p36</guid>
      <description>&lt;p&gt;&lt;a href="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%2F8d45pw3d9a0lsi0ny751.png" class="article-body-image-wrapper"&gt;&lt;img 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%2F8d45pw3d9a0lsi0ny751.png" alt="Tired of Manual Calendar Management? I Was Too. So I Built This Tool" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately, I’ve been trying to organize my life better. Like many people, I kept hearing about &lt;strong&gt;calendar blocking&lt;/strong&gt; and other productivity techniques.&lt;/p&gt;

&lt;p&gt;But let’s be honest — am I really expected to manually create countless little event blocks, keep track of holidays, and constantly update my calendar?&lt;/p&gt;

&lt;p&gt;No thanks. Instead, &lt;strong&gt;I built a tool that does it all for me&lt;/strong&gt; — fast, efficiently, and with no friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Tool Does
&lt;/h2&gt;

&lt;p&gt;This streamlined web app lets you build complex, recurring schedules in just a few clicks. Define your time blocks once, customize your settings, and instantly generate a complete calendar file ready to import into any major calendar application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want my expertize applied to you company? Contact me
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Multiple Time Slots&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Create recurring events with custom titles, days, and times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexible Scheduling&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Set schedules on any combination of days — weekdays, weekends, or fully custom patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart Off-Days&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Exclude specific dates, such as holidays or vacations, where your recurring events shouldn’t apply.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Tracking&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Get an overview of how many events will be created and the total time commitment involved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dark Mode Support&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Includes automatic dark mode detection for a more comfortable viewing experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsive Design&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Works seamlessly on both desktop and mobile devices.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ideal Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Work Schedules&lt;/strong&gt; — Block out time for focus sessions, meetings, or project work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fitness Routines&lt;/strong&gt; — Plan gym sessions, yoga classes, or training blocks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Study Plans&lt;/strong&gt; — Organize consistent learning sessions across subjects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal Projects&lt;/strong&gt; — Allocate time for hobbies, side gigs, or creative work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Coordination&lt;/strong&gt; — Create shared, recurring schedules for collaborative tasks&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set Your Date Range&lt;/strong&gt;
Define the start and end dates for your schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Time Slots&lt;/strong&gt;
Add as many recurring time blocks as needed, each with its own settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exclude Off-Days&lt;/strong&gt;
Remove holidays, breaks, or other non-working days from your schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate and Download&lt;/strong&gt;
Export your setup as a standard &lt;code&gt;.ics&lt;/code&gt; calendar file, compatible with Google Calendar, Outlook, Apple Calendar, and others.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;If you're tired of repeating the same scheduling steps week after week, this tool will change how you manage your time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://danielpetrica.com/periodic-schedule-calendar-generator/?adaoidad=adadaq" rel="noopener noreferrer"&gt;&lt;strong&gt;Visit the Periodic Schedule Calendar Generator&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Manual scheduling is tedious and error-prone. This tool eliminates that hassle. With just a few clicks, it generates hundreds of recurring events, accurately accounts for off-days, and gives you insight into your total time allocation before you even start.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Built using &lt;strong&gt;Vue 3&lt;/strong&gt; and &lt;strong&gt;Tailwind CSS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Pure &lt;strong&gt;JavaScript&lt;/strong&gt; generation of &lt;code&gt;.ics&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;No external dependencies beyond CDN libraries&lt;/li&gt;
&lt;li&gt;Fully &lt;strong&gt;responsive design&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Compatible with all major calendar platforms&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Built with Vue.js. Designed for clarity. Powered by smart scheduling logic.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Say goodbye to manual calendar entry — and take control of your time.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>tool</category>
      <category>productivity</category>
      <category>startup</category>
    </item>
    <item>
      <title>How I Survived the Front Page of Hacker News Without Crashing My Site</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Wed, 30 Apr 2025 13:00:00 +0000</pubDate>
      <link>https://dev.to/danielpetrica/how-i-survived-the-front-page-of-hacker-news-without-crashing-my-site-1h8f</link>
      <guid>https://dev.to/danielpetrica/how-i-survived-the-front-page-of-hacker-news-without-crashing-my-site-1h8f</guid>
      <description>&lt;p&gt;In this post, I share my journey of surviving a massive traffic spike when my article reached the front page of Hacker News. I discuss how I optimized my Ghost CMS setup for handling high traffic using caching strategies with Cloudflare, Docker, and Traefik. I'll also dive into practical tips on setting up caching headers and how I scaled my multi-site server infrastructure without crashing. If you’re dealing with high traffic or want to future-proof your site, this guide will help you manage big surges with ease.&lt;/p&gt;

&lt;p&gt;Read the complete article and view the graphs here: &lt;a href="https://danielpetrica.com/surviving-hacker-news-front-page/" rel="noopener noreferrer"&gt;https://danielpetrica.com/surviving-hacker-news-front-page/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>traefik</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How I Survived the Front Page of Hacker News Without Crashing My Server</title>
      <dc:creator>Daniel, Petrica Andrei-Daniel</dc:creator>
      <pubDate>Wed, 30 Apr 2025 10:56:23 +0000</pubDate>
      <link>https://dev.to/danielpetrica/how-i-survived-the-front-page-of-hacker-news-without-crashing-my-server-dp5</link>
      <guid>https://dev.to/danielpetrica/how-i-survived-the-front-page-of-hacker-news-without-crashing-my-server-dp5</guid>
      <description>&lt;h3&gt;
  
  
  Some context: My First Front Page on Hacker News
&lt;/h3&gt;

&lt;p&gt;&lt;a href="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%2Fqxy66r93j9twlvipr2w2.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fqxy66r93j9twlvipr2w2.png" alt="How I Survived the Front Page of Hacker News Without Crashing My Server" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week, I published a post about my experience at a startup weekend competition—our team won, and I wanted to share the lessons.&lt;/p&gt;

&lt;p&gt;On April 23rd, I submitted the link to &lt;a href="https://news.ycombinator.com/item?id=43746109&amp;amp;ref=danielpetrica.com" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt;. The next morning, I woke up to a surprise: Umami showed a &lt;strong&gt;5,000% increase&lt;/strong&gt; in visitors over the past 24 hours.&lt;/p&gt;

&lt;p&gt;Normally, my blog gets 50–100 daily views. But in just 4 hours, I had nearly 1,300. According to the &lt;a href="https://web.archive.org/web/20250424031312/https://news.ycombinator.com/" rel="noopener noreferrer"&gt;Wayback Machine&lt;/a&gt;, the article peaked at &lt;strong&gt;#16 on Hacker News&lt;/strong&gt; —something I’d never even dreamed of.&lt;/p&gt;

&lt;p&gt;By the end of the day, my site had served &lt;strong&gt;194,000 requests&lt;/strong&gt; —and it never went down.&lt;/p&gt;

&lt;p&gt;And yes… I even started a Docker build on the same server during the spike before reviewing the analytics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want my expertize applied to you company? Contact me
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Was I Ready for That Much Traffic?
&lt;/h3&gt;

&lt;p&gt;No. At least, not intentionally.&lt;/p&gt;

&lt;p&gt;But thanks to past experimentation with &lt;strong&gt;caching&lt;/strong&gt; and &lt;strong&gt;web performance optimization&lt;/strong&gt; , my setup handled it. I use &lt;strong&gt;Ghost CMS&lt;/strong&gt; for my blog, and last year I invested time in tuning it for performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I Prepared: Two Layers of Caching
&lt;/h3&gt;

&lt;p&gt;💡&lt;/p&gt;

&lt;p&gt;The key to surviving unexpected spikes is &lt;strong&gt;caching&lt;/strong&gt; —especially layered caching. Here's what worked for me:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cloudflare in Front
&lt;/h3&gt;

&lt;p&gt;My blog isn’t directly exposed to the internet—it’s behind a &lt;strong&gt;Cloudflare proxy&lt;/strong&gt;. This helps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Block malicious traffic&lt;/li&gt;
&lt;li&gt;Provide a global CDN for caching static assets&lt;/li&gt;
&lt;li&gt;Reduce server load by serving cached responses from edge nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Cache-Friendly Ghost CMS Configuration
&lt;/h3&gt;

&lt;p&gt;I also fine-tuned Ghost’s cache headers to help Cloudflare do its job.&lt;/p&gt;

&lt;p&gt;Here’s what I set in my Docker Compose &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;caching&lt;/span&gt; &lt;span class="err"&gt;__&lt;/span&gt;&lt;span class="n"&gt;contentApi__&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;=&lt;span class="m"&gt;60&lt;/span&gt;
&lt;span class="n"&gt;caching&lt;/span&gt; &lt;span class="err"&gt;__&lt;/span&gt;&lt;span class="n"&gt;frontend__&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;=&lt;span class="m"&gt;60&lt;/span&gt;
&lt;span class="n"&gt;caching&lt;/span&gt; &lt;span class="err"&gt;__&lt;/span&gt;&lt;span class="n"&gt;robotstxt__&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;=&lt;span class="m"&gt;36000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Ghost to set proper &lt;code&gt;Cache-Control&lt;/code&gt; headers, so responses are cached both in browsers and by Cloudflare—especially useful when hundreds of users hit the same page simultaneously.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 Learn more in the &lt;a href="https://ghost.org/docs/config/?ref=danielpetrica.com#caching" rel="noopener noreferrer"&gt;official Ghost documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Cloudflare Saved My Server
&lt;/h2&gt;

&lt;p&gt;Cloudflare was critical. Here’s how I set it up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admin portal excluded&lt;/strong&gt; from caching (for security and accuracy)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything else&lt;/strong&gt; set to “cache everything” with respect to origin headers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, &lt;strong&gt;94% of all requests were served from cache&lt;/strong&gt; during the Hacker News spike, according to Cloudflare Analytics.&lt;/p&gt;

&lt;p&gt;This drastically reduced the number of requests reaching my actual server and you can see that in the following graph.&lt;/p&gt;

&lt;p&gt;&lt;a href="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%2Fhlnm71t9n9cm564iv8fu.png" class="article-body-image-wrapper"&gt;&lt;img 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%2Fhlnm71t9n9cm564iv8fu.png" alt="How I Survived the Front Page of Hacker News Without Crashing My Server" width="800" height="537"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Cloudflare cached up to 94% of all traffic going to danielpetrica.com&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Stack: Minimal, Scalable, Docker-Based
&lt;/h2&gt;

&lt;p&gt;My infrastructure uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt; + &lt;strong&gt;Traefik&lt;/strong&gt; for reverse proxying. read more &lt;a href="https://danielpetrica.com/ghost-blog-migration-how-i-mov/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare&lt;/strong&gt; for security and caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ghost CMS&lt;/strong&gt; for blogging&lt;/li&gt;
&lt;li&gt;~24 self-hosted sites and tools (like &lt;a href="https://danielpetrica.com/installing-activepieces-with-docker-compose-and-traefik/" rel="noopener noreferrer"&gt;Activepieces&lt;/a&gt; ) on a single 4 core ARM server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even while building a Docker image during the spike, the system stayed fast and responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: Want Your Blog to Survive Hacker News?
&lt;/h2&gt;

&lt;p&gt;Here’s what worked for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put Cloudflare in front of your site&lt;/li&gt;
&lt;li&gt;Configure your CMS to set cache headers correctly&lt;/li&gt;
&lt;li&gt;Use Docker + Traefik for modular, scalable hosting&lt;/li&gt;
&lt;li&gt;Avoid overcomplicated setups—opt for stability and cacheability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Need Help Setting This Up?
&lt;/h2&gt;

&lt;p&gt;I’m a freelance &lt;strong&gt;DevOps and monitoring consultant&lt;/strong&gt; , and I can help configure your Ghost (or other) stack for performance, caching, and observability.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mail me or visit click the button bellow if you'd like help prepping your server for a Hacker News-level spike.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Contact me via mail to discuss how I can help you.&lt;/p&gt;

&lt;p&gt;&lt;a href="mailto://freelance@danielpetrica.com"&gt;Write an email to me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading this far! I’ll definitely share more about my stack, my experience as a startup founder, and programming tips in future posts. If that sounds interesting, feel free to subscribe—it's free, and you'll be the first to know when new content drops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign up for Daniel Petrica
&lt;/h2&gt;

&lt;p&gt;Learn about docker, self-hosting, programming and more with me&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                &amp;lt;span&amp;gt;Subscribe for free&amp;lt;/span&amp;gt;
                &amp;lt;span&amp;gt;&amp;lt;svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"&amp;gt;
    &amp;lt;g stroke-linecap="round" stroke-width="2" fill="currentColor" stroke="none" stroke-linejoin="round"&amp;gt;
        &amp;lt;g&amp;gt;
            &amp;lt;circle cx="4" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
            &amp;lt;circle cx="12" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
            &amp;lt;circle cx="20" cy="12" r="3"&amp;gt;&amp;lt;/circle&amp;gt;
        &amp;lt;/g&amp;gt;

    &amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&amp;lt;/span&amp;gt;



            Email sent! Check your inbox to complete your signup.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;No spam. Unsubscribe anytime.&lt;/p&gt;

</description>
      <category>ghost</category>
      <category>guides</category>
      <category>personalprojects</category>
      <category>selfhost</category>
    </item>
  </channel>
</rss>
