<?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: Serhiy K</title>
    <description>The latest articles on DEV Community by Serhiy K (@byte8io).</description>
    <link>https://dev.to/byte8io</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%2F4068563%2Fff4260a6-4d23-4cfe-ae09-c4ce900ff8f4.jpg</url>
      <title>DEV Community: Serhiy K</title>
      <link>https://dev.to/byte8io</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/byte8io"/>
    <language>en</language>
    <item>
      <title>Anatomy of a Magento Card Skimmer: How Injected JavaScript Steals Cards — and Why Uptime Checks Miss It</title>
      <dc:creator>Serhiy K</dc:creator>
      <pubDate>Wed, 16 Sep 2026 09:39:12 +0000</pubDate>
      <link>https://dev.to/byte8io/anatomy-of-a-magento-card-skimmer-how-injected-javascript-steals-cards-and-why-uptime-checks-4am8</link>
      <guid>https://dev.to/byte8io/anatomy-of-a-magento-card-skimmer-how-injected-javascript-steals-cards-and-why-uptime-checks-4am8</guid>
      <description>&lt;p&gt;A Magento store can be fully up, fast, and passing every uptime check while quietly sending each customer's card number to a criminal. Nothing looks broken. Orders complete, pages load in 400ms, the status page is green — and card data is being copied at the moment it's typed.&lt;/p&gt;

&lt;p&gt;That's a card skimmer. It's one of the most common and most damaging things that happens to a Magento store, and it's built from the ground up to be invisible. This post walks through exactly how a skimmer gets in, what the injected code does, why traditional monitoring can't see it, and how to catch and remove one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Magento card skimmer?
&lt;/h2&gt;

&lt;p&gt;A Magento card skimmer — a form of &lt;strong&gt;Magecart&lt;/strong&gt; or &lt;strong&gt;digital skimming&lt;/strong&gt; attack — is malicious JavaScript injected into a store's frontend that reads payment and personal details from the checkout form and sends them to an attacker-controlled server. The customer sees a normal checkout. The order goes through. The card just gets stolen on the way.&lt;/p&gt;

&lt;p&gt;The important part for anyone running a store: a skimmer doesn't break anything visible. It adds a small, silent listener to a page that's otherwise working perfectly. The store keeps returning HTTP 200, the page stays fast, and no PHP exception is ever thrown. Detection is hard precisely because, by every conventional signal, the store looks healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a card skimmer gets into a Magento store
&lt;/h2&gt;

&lt;p&gt;The attacker's goal is simple: get their JavaScript to execute on your checkout page. Magento offers several routes to that, and most of them live in the database rather than in your codebase — which is why redeploying from clean git often doesn't remove a skimmer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;core_config_data&lt;/code&gt;.&lt;/strong&gt; Magento has admin fields whose contents are rendered into every page: the "Miscellaneous HTML" boxes (header/footer), the head includes, tracking-script fields. A single row in &lt;code&gt;core_config_data&lt;/code&gt; can inject a script store-wide. This is the single most common Magento skimmer vector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMS blocks and pages.&lt;/strong&gt; A widget or static block that appears on many pages — a footer block, a promo banner — is edited to carry the payload. It renders wherever the block is placed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout XML and theme templates.&lt;/strong&gt; After a server or admin compromise, the attacker edits &lt;code&gt;.phtml&lt;/code&gt; templates or layout XML directly to add a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. File-level, so it survives cache flushes but not a clean redeploy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A compromised admin account or extension.&lt;/strong&gt; The entry point for most of the above: a reused admin password with no 2FA, or a vulnerable third-party extension that allows content to be written. Recent unauthenticated RCE flaws have let attackers skip the login step entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A third-party or CDN script (supply chain).&lt;/strong&gt; A legitimate external script the storefront already loads — analytics, a chat widget, a tag manager — is swapped at its source. The store's own database is untouched, which makes this variant especially sneaky.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The attack, step by step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Get in
&lt;/h3&gt;

&lt;p&gt;The attacker gains write access to content: a guessed or phished admin login, an exploited extension, or in the worst case remote code execution on the server. No 2FA on even one admin account is often all it takes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Inject the skimmer
&lt;/h3&gt;

&lt;p&gt;They add a few lines of JavaScript to one of the injection points above — most often a &lt;code&gt;core_config_data&lt;/code&gt; field or a CMS block, because those render site-wide and don't require touching the filesystem. The payload is usually obfuscated so it doesn't read as "skimmer" to a casual glance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Harvest at checkout
&lt;/h3&gt;

&lt;p&gt;The script waits for the checkout page. Many skimmers check the URL and only activate on &lt;code&gt;/checkout&lt;/code&gt; to reduce their footprint. They read the payment and address fields — card number, expiry, CVV, name, billing address — either by watching keystrokes or by scraping the form just before submit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Exfiltrate
&lt;/h3&gt;

&lt;p&gt;The harvested data is sent to an attacker-controlled domain, frequently one that mimics a real service (a lookalike of a CDN, analytics, or font host) so it blends into normal network traffic. Exfiltration often rides on an image request or a &lt;code&gt;fetch&lt;/code&gt; to a domain that looks innocuous in a list of third-party calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — Stay hidden
&lt;/h3&gt;

&lt;p&gt;Good skimmers are quiet. They throw no errors, add no visible latency, and often re-inject themselves from a second foothold if the first is cleaned. The store keeps working normally, which is the whole point — the longer it looks healthy, the longer the cards keep flowing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why uptime checks — and even APM — are blind to it
&lt;/h2&gt;

&lt;p&gt;This is the part that catches teams out. Every conventional monitoring signal says the store is fine, because a skimmer doesn't touch any of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;signal                         what it sees          skimmer detected?
----------------------------   -------------------   -----------------
uptime / HTTP check            200 OK, page loads    no
response-time / APM            fast, ~400ms          no
error-rate / exceptions        none thrown           no
synthetic checkout             order completes       no (order still works)
server / infra metrics         normal load           no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An uptime monitor asks "did the page respond?" — it did. An APM tool asks "is it fast, and is the code healthy?" — it is. Even a synthetic checkout that drives a real browser will &lt;strong&gt;complete the order&lt;/strong&gt;, because the skimmer doesn't stop the purchase — it rides alongside it. The failure isn't availability or performance. It's &lt;strong&gt;integrity&lt;/strong&gt;: the page is serving code it shouldn't. Nothing built to watch "is it up?" or "is it fast?" is built to notice that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to detect a card skimmer on your Magento store
&lt;/h2&gt;

&lt;p&gt;You can look for a skimmer by hand today. The checks that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read &lt;code&gt;core_config_data&lt;/code&gt; for script content.&lt;/strong&gt; Query the config fields that render to the frontend (the Miscellaneous HTML and head-include paths) and look for any &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; you didn't put there, or references to external domains you don't recognise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit CMS blocks and pages.&lt;/strong&gt; Scan block and page content for inline scripts and unfamiliar external &lt;code&gt;src&lt;/code&gt; domains, especially in site-wide footer/header blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List every external script your storefront loads,&lt;/strong&gt; particularly on the checkout page, and confirm each domain is one you trust. A lookalike domain (a near-miss of a real CDN or analytics host) is a red flag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diff your templates against clean git.&lt;/strong&gt; If layout XML or &lt;code&gt;.phtml&lt;/code&gt; files differ from what's committed, something wrote to the filesystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy a Content-Security-Policy and watch its reports.&lt;/strong&gt; A CSP in report-only mode will tell you when a page tries to load or exfiltrate to an unexpected domain — a strong tripwire for skimmers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check whether the injection only fires on checkout.&lt;/strong&gt; Many skimmers are URL-gated, so comparing the scripts loaded on a product page versus the checkout page can surface a payload that only appears where the cards are.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The catch with all of these is that they're point-in-time. A skimmer injected the day after your last manual audit runs for weeks before the next one. Integrity is not a thing you check once; it's a thing that has to be watched.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Pulsar detects injected skimmers
&lt;/h2&gt;

&lt;p&gt;This is exactly the gap &lt;a href="https://byte8.io/products/pulsar" rel="noopener noreferrer"&gt;Pulsar&lt;/a&gt; is built to close, and it does it in two ways that matter here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-integrity monitoring.&lt;/strong&gt; Pulsar's content-integrity collector reads the places skimmers actually hide — &lt;code&gt;core_config_data&lt;/code&gt; and CMS content — and flags injected &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags, unexpected external script domains, and known skimmer signatures. Because it reads Magento's own stored content rather than just fetching the page, it catches the database-resident injection that's invisible from the outside. It runs continuously, so a script added an hour ago is caught in the next check, not at the next manual audit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A first-class "compromised" status.&lt;/strong&gt; Most monitoring tools only know two states: up and down. But a skimmed store is &lt;strong&gt;up&lt;/strong&gt; — that's the problem. Pulsar treats &lt;strong&gt;compromised&lt;/strong&gt; as its own status, separate from the uptime SLA, so a store that's serving customers perfectly while leaking cards doesn't hide behind a green "100% uptime" number. A skimmer is a security incident, and it's surfaced as one.&lt;/p&gt;

&lt;p&gt;A note on honesty, because this category is still maturing: content-integrity monitoring catches the common Magento vector — code injected into your store's content — extremely well. A skimmer loaded through a &lt;strong&gt;compromised third-party script&lt;/strong&gt; lives outside your database, which is why watching your external script sources (and running a CSP) matters alongside it. No single check is a silver bullet; defence in depth is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to remove a skimmer and keep it out
&lt;/h2&gt;

&lt;p&gt;Finding it is half the job. Removing it cleanly and closing the door is the other half.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Remove the injected code at the source&lt;/strong&gt; — the &lt;code&gt;core_config_data&lt;/code&gt; row, the CMS block, or the template file. Redeploying from clean git fixes file-level injections but &lt;strong&gt;not&lt;/strong&gt; database ones, so check both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assume the admin credentials are compromised.&lt;/strong&gt; Reset all admin passwords and enforce 2FA on every account, no exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patch and audit the entry point.&lt;/strong&gt; Apply outstanding Magento security patches, review third-party extensions, and check for unauthorised admin users, integration tokens, and API keys created during the breach window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate secrets if there was server access.&lt;/strong&gt; If the compromise reached the filesystem, treat &lt;code&gt;app/etc/env.php&lt;/code&gt; — database credentials and the encryption key — as stolen, and rotate accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a Content-Security-Policy&lt;/strong&gt; to constrain which domains can run scripts and receive data, turning the next attempt into a blocked, reported event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor content integrity continuously&lt;/strong&gt; so the next injection is caught in minutes, not at the next quarterly audit — or the next chargeback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can a Magento card skimmer be detected by uptime monitoring?&lt;/strong&gt;&lt;br&gt;
No. A skimmer doesn't affect availability — the store stays up, the checkout still completes, and every HTTP response is a healthy 200. Uptime monitoring asks whether the page responded; the skimmer doesn't stop it from responding. Detecting a skimmer requires watching the &lt;strong&gt;integrity&lt;/strong&gt; of what the page serves, not whether it serves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where do skimmers hide in Magento?&lt;/strong&gt;&lt;br&gt;
Most often in the database: &lt;code&gt;core_config_data&lt;/code&gt; fields that render site-wide (the Miscellaneous HTML and head-include boxes) and CMS blocks or pages. Less commonly in layout XML or &lt;code&gt;.phtml&lt;/code&gt; templates after a filesystem compromise, or in a third-party script loaded from a compromised external source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why doesn't redeploying from clean git remove the skimmer?&lt;/strong&gt;&lt;br&gt;
Because the most common injection points are in the database, not the codebase. A clean redeploy overwrites files but leaves &lt;code&gt;core_config_data&lt;/code&gt; and CMS content untouched, so a database-resident skimmer survives it. You have to clean the content, not just the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a card skimmer the same as being "hacked and down"?&lt;/strong&gt;&lt;br&gt;
No — and that's what makes it dangerous. A skimmed store is fully operational. It's compromised &lt;strong&gt;and&lt;/strong&gt; up at the same time, which is why monitoring that only distinguishes up from down misses it entirely, and why a compromised store needs its own status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How fast should a skimmer be detected?&lt;/strong&gt;&lt;br&gt;
As close to immediately as possible — every hour it runs is more stolen cards and more liability. That's the argument for continuous content-integrity monitoring over periodic manual audits: the window between injection and detection is exactly the window in which customers get hurt.&lt;/p&gt;

&lt;p&gt;A skimmer is the clearest example of why "is the site up?" is the wrong question. The store is up. It's fast. It's green on every dashboard built to measure availability and performance — and it's stealing cards. Watching the store's integrity, and treating a compromise as its own first-class state, is how you see the failure that every other tool is built to miss.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://byte8.io/products/pulsar" rel="noopener noreferrer"&gt;See how Pulsar monitors Magento →&lt;/a&gt;&lt;/p&gt;

</description>
      <category>magento</category>
      <category>php</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Magento Deployment Tools Compared: Orbit vs Deployer, Capistrano, Adobe Commerce Cloud &amp; Magefan</title>
      <dc:creator>Serhiy K</dc:creator>
      <pubDate>Wed, 02 Sep 2026 10:30:22 +0000</pubDate>
      <link>https://dev.to/byte8io/magento-deployment-tools-compared-orbit-vs-deployer-capistrano-adobe-commerce-cloud-magefan-3l4j</link>
      <guid>https://dev.to/byte8io/magento-deployment-tools-compared-orbit-vs-deployer-capistrano-adobe-commerce-cloud-magefan-3l4j</guid>
      <description>&lt;p&gt;Search "Magento zero-downtime deployment" and you'll get a pile of results that look interchangeable but aren't. A generic PHP deploy script, a Ruby CLI, a six-figure managed platform, a Magento extension, and a purpose-built deploy agent all show up on the same page — as if picking between them is a matter of taste.&lt;/p&gt;

&lt;p&gt;It isn't. These five tools sit in genuinely different categories, solve different slices of the problem, and cost anywhere from nothing to a six-figure license. This is an honest look at what each one actually does for a Magento deploy, where it stops, and who each is right for. We build one of them (Orbit), and we've tried to be fair to the other four — including linking you to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does zero-downtime Magento deployment actually require?
&lt;/h2&gt;

&lt;p&gt;Before comparing tools, it helps to name the job. A Magento deploy is "zero-downtime" only if it solves five distinct problems, not one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Atomic release swap.&lt;/strong&gt; New code is fully prepared in a separate release directory, and going live is a single instantaneous symlink switch — never an in-place edit of the running site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The migration window.&lt;/strong&gt; &lt;code&gt;setup:upgrade&lt;/code&gt; can lock database tables. If a migration runs long, requests pile up or error. Something has to either keep the store serving or predict and bound that window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The build cost.&lt;/strong&gt; &lt;code&gt;composer install&lt;/code&gt;, &lt;code&gt;setup:di:compile&lt;/code&gt;, and &lt;code&gt;setup:static-content:deploy&lt;/code&gt; are slow, and they re-run on every deploy by default — even when nothing changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback.&lt;/strong&gt; When a release is bad, you need to get back to the previous one fast — ideally automatically, on a failed health check, not by hand at 2 AM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visibility and repeatability.&lt;/strong&gt; You want to see what a deploy did, trigger it from CI, and get the same result every time across every environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep those five in mind — no single tool below covers all of them the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  These five tools aren't the same category
&lt;/h2&gt;

&lt;p&gt;That's the crux, and it's why "which is best?" has no context-free answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PHP Deployer and Capistrano&lt;/strong&gt; are generic &lt;strong&gt;deploy orchestrators&lt;/strong&gt; — CLIs you script to assemble the release structure yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adobe Commerce Cloud&lt;/strong&gt; is a &lt;strong&gt;managed platform&lt;/strong&gt; with a deploy pipeline bundled in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Magefan's module&lt;/strong&gt; is an &lt;strong&gt;in-Magento extension&lt;/strong&gt; that runs the build in a temporary copy of your store and swaps it in — zero-downtime deploys from inside Magento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orbit&lt;/strong&gt; is a &lt;strong&gt;Magento-aware deploy agent&lt;/strong&gt; built to cover the whole zero-downtime lifecycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PHP Deployer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://deployer.org" rel="noopener noreferrer"&gt;Deployer&lt;/a&gt; is the default answer in the PHP world, and for good reason: it's free, open-source, mature, and ships a Magento 2 recipe. It gives you the atomic symlink release structure, shared files and dirs, keep-releases, and a &lt;code&gt;rollback&lt;/code&gt; task. If you're comfortable in &lt;code&gt;deploy.php&lt;/code&gt; and want full control, it's excellent.&lt;/p&gt;

&lt;p&gt;Where it stops is everything beyond the release mechanics. Deployer doesn't hold traffic during a long &lt;code&gt;setup:upgrade&lt;/code&gt;, doesn't predict how long a migration will lock the database, doesn't skip build phases whose inputs haven't changed, and doesn't roll back automatically on a &lt;em&gt;post-deploy health check&lt;/em&gt; (its rollback fires when a task fails, not when the site comes up broken). It's CLI-only — no dashboard, no team audit log — and the pipeline is yours to build and maintain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; teams who want a free, scriptable, self-hosted deployer and are happy owning the pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for:&lt;/strong&gt; the migration window, build time, and health-based rollback are on you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Capistrano
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://capistranorb.com" rel="noopener noreferrer"&gt;Capistrano&lt;/a&gt; is the grandparent of atomic-release deploys — Ruby-based, battle-tested, and conceptually identical to Deployer (release directories, symlink swap, rollback). It predates the PHP-native options, so on a Magento (PHP) stack it means running and maintaining a Ruby toolchain and writing your own Magento-specific recipes.&lt;/p&gt;

&lt;p&gt;Everything said about Deployer's gaps applies here too: no traffic hold, no migration forecast, no build-skip, no health-checked auto-rollback, CLI-only. If your organisation already lives in Capistrano across other apps, it's reasonable to extend it to Magento. Starting fresh on Magento, most teams now reach for a PHP-native tool.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; shops already standardised on Capistrano across a mixed stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for:&lt;/strong&gt; Ruby toolchain on a PHP project, and all the same lifecycle gaps as Deployer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adobe Commerce Cloud
&lt;/h2&gt;

&lt;p&gt;Adobe Commerce Cloud isn't a deploy tool you add — it's the managed platform, with a build-and-deploy pipeline included. If you're already on it, you get an integrated pipeline, infrastructure, CDN, and support in one contract, and you're not assembling any of this yourself.&lt;/p&gt;

&lt;p&gt;The trade-offs are lock-in and cost. It only runs on Adobe-managed infrastructure, the pipeline behaves the way Adobe designed it (with its own build and deploy phases), and it comes as part of a license that runs into six figures for many merchants. It's the right answer if you've chosen the Adobe-managed path and want everything in one place — and an expensive answer if all you actually needed was zero-downtime deploys on your own hosting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; merchants already committed to the Adobe-managed platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for:&lt;/strong&gt; you can't self-host it, and you're paying platform prices for the pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Magefan's Magento 2 Zero Downtime Deployment module
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://magefan.com/magento-2-zero-downtime-deployment" rel="noopener noreferrer"&gt;Magefan's extension&lt;/a&gt; takes a different, clever angle: instead of orchestrating releases from an external agent, it works &lt;em&gt;inside&lt;/em&gt; Magento. On deploy it copies your live store into a temporary folder, runs the heavy build steps there — &lt;code&gt;setup:di:compile&lt;/code&gt; and &lt;code&gt;setup:static-content:deploy&lt;/code&gt; (only for enabled themes and locales) — and swaps the finished build in, so the store never drops to a 503 during the build. That's a genuine build-and-swap zero-downtime mechanism delivered as a module, not just a maintenance-page toggle, and it's inexpensive (a commercial license, roughly $119–$303, with 365 days of updates).&lt;/p&gt;

&lt;p&gt;Where it stops is the wider deploy platform. It focuses on the build-and-swap for a single store from inside Magento, so there's no pre-deploy DB-migration block-window forecast, no automatic rollback on a failed post-deploy health check, and no cross-environment dashboard or audit log. And because it moves the &lt;em&gt;build&lt;/em&gt; off to the side, it targets build-phase downtime specifically — a long &lt;code&gt;setup:upgrade&lt;/code&gt; that locks the database is a separate problem it doesn't forecast or hold traffic for. Think of it as a focused, low-cost way to get zero-downtime builds, with the multi-environment orchestration living elsewhere.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; teams who want cheap, in-Magento zero-downtime builds and already have their release/CI approach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for:&lt;/strong&gt; DB-migration locks, health-based rollback, and multi-environment orchestration are outside its scope.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Orbit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://byte8.io/products/orbit" rel="noopener noreferrer"&gt;Orbit&lt;/a&gt; is what we build, so read this section knowing that — the facts are checkable against the tools above. Orbit is a small Rust agent you install on your own servers in one command, designed to cover the whole zero-downtime lifecycle for Magento specifically, not just the release swap.&lt;/p&gt;

&lt;p&gt;Against the five problems: it does atomic symlink releases; it holds incoming traffic during the cutover so a migration doesn't drop requests; it &lt;strong&gt;forecasts the DB-migration block window before you deploy&lt;/strong&gt; (it diffs the declarative schema, classifies each change as online or blocking DDL, and predicts the lock time — an advisory prediction, not a promise of zero lock); it smart-skips build phases whose inputs haven't changed, turning typical deploys from ~3 minutes to ~75 seconds; and it rolls back automatically on a failed post-deploy health check, even after the symlink has swapped. It adds a real-time dashboard with a team audit log, a &lt;code&gt;deploy --stream&lt;/code&gt; terminal view, and CI/CD triggers via scoped tokens. It's self-hostable, and PHP Deployer users can import an existing &lt;code&gt;deploy.php&lt;/code&gt; in one command.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Magento teams who want the full zero-downtime lifecycle on their own hosting, without a six-figure platform or a hand-built pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for:&lt;/strong&gt; it's a commercial product (flat monthly subscription, free trial), and it's Magento/Adobe Commerce-focused — not a general-purpose deployer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  At a glance
&lt;/h2&gt;

&lt;p&gt;A simplified view — read the sections above for the nuance behind each cell.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Deployer&lt;/th&gt;
&lt;th&gt;Capistrano&lt;/th&gt;
&lt;th&gt;Adobe Cloud&lt;/th&gt;
&lt;th&gt;Magefan&lt;/th&gt;
&lt;th&gt;Orbit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;CLI tool&lt;/td&gt;
&lt;td&gt;CLI tool&lt;/td&gt;
&lt;td&gt;Managed PaaS&lt;/td&gt;
&lt;td&gt;Magento module&lt;/td&gt;
&lt;td&gt;Deploy agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runs on your servers&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✗ (Adobe)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomic release swap&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;Managed&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handles DB-migration lock&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration-lock forecast&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skips unchanged builds&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto health rollback&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard + audit log&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD trigger&lt;/td&gt;
&lt;td&gt;DIY&lt;/td&gt;
&lt;td&gt;DIY&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Commands&lt;/td&gt;
&lt;td&gt;Token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Magento-aware&lt;/td&gt;
&lt;td&gt;Recipe&lt;/td&gt;
&lt;td&gt;DIY&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free OSS&lt;/td&gt;
&lt;td&gt;Free OSS&lt;/td&gt;
&lt;td&gt;Six-figure&lt;/td&gt;
&lt;td&gt;$119–$303&lt;/td&gt;
&lt;td&gt;Monthly sub&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Which should you choose?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You want free and you'll own the pipeline:&lt;/strong&gt; PHP Deployer. Add Magefan's module for low-cost, in-Magento zero-downtime builds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're already all-in on Capistrano across a mixed stack:&lt;/strong&gt; extend Capistrano to Magento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're committed to the Adobe-managed platform:&lt;/strong&gt; use the Cloud pipeline you're already paying for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want the full zero-downtime lifecycle on your own hosting — traffic hold, migration forecast, build-skip, auto-rollback, dashboard — without building or licensing a platform:&lt;/strong&gt; that's the gap Orbit was built for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's no universally "best" tool here. There's the one that matches how you host, how much you want to build yourself, and what you're willing to spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the best zero-downtime deployment tool for Magento 2?&lt;/strong&gt;&lt;br&gt;
There isn't a single best — it depends on your hosting and budget. PHP Deployer is the best free, self-hosted option if you'll maintain the pipeline. Adobe Commerce Cloud is the built-in choice if you're already on that platform. Orbit is the most complete purpose-built option for zero-downtime deploys on your own hosting (traffic hold, migration forecast, build-skip, auto-rollback). Magefan's module is a low-cost, in-Magento way to run zero-downtime builds — it builds in a temporary copy of your store and swaps it in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is PHP Deployer good for Magento?&lt;/strong&gt;&lt;br&gt;
Yes — it's free, mature, and has a Magento 2 recipe, and it handles atomic releases and rollback well. Its limits are the Magento-specific hard parts: it won't hold traffic during a long &lt;code&gt;setup:upgrade&lt;/code&gt;, forecast the migration lock window, skip unchanged build phases, or roll back on a failed post-deploy health check. Those you either build yourself or get from a Magento-aware tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need Adobe Commerce Cloud for zero-downtime deploys?&lt;/strong&gt;&lt;br&gt;
No. Adobe Commerce Cloud bundles a deploy pipeline, but you can get zero-downtime deploys on your own hosting with a deployer (Deployer, Capistrano) or a purpose-built agent (Orbit). Adobe Cloud only makes sense if you want the whole managed platform, not just the deploys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is Orbit different from PHP Deployer or Capistrano?&lt;/strong&gt;&lt;br&gt;
Deployer and Capistrano are generic orchestrators you script yourself; they nail the atomic release swap but stop there. Orbit is Magento-aware and covers the rest of the lifecycle: a traffic-holding cutover, a pre-deploy DB-migration block-window forecast, build-phase skipping, automatic health-checked rollback, a dashboard with audit logs, and CI triggers — and it can import your existing &lt;code&gt;deploy.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you deploy Magento without a maintenance page?&lt;/strong&gt;&lt;br&gt;
Yes. The maintenance-page downtime comes from running &lt;code&gt;setup:upgrade&lt;/code&gt; against the live site. You avoid it either by holding traffic during the migration (Orbit), by using an in-Magento module that keeps the store serving (Magefan), or by writing forward-compatible migrations so the old code tolerates the new schema. See our &lt;a href="https://byte8.io/blog/zero-downtime-magento-deployment" rel="noopener noreferrer"&gt;complete guide to zero-downtime Magento deployment&lt;/a&gt; for the mechanics.&lt;/p&gt;

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

&lt;p&gt;If you want free and don't mind assembling the pipeline, Deployer is a great starting point. If you're on Adobe's platform, use what you're paying for. If you want to kill just the maintenance window cheaply, Magefan's module does exactly that. And if you want the full zero-downtime lifecycle for Magento on your own hosting — without building it yourself or buying a platform — that's the specific gap Orbit was built to fill.&lt;/p&gt;

&lt;p&gt;Want to go deeper on the mechanics behind any of this? Read &lt;a href="https://byte8.io/blog/zero-downtime-magento-deployment" rel="noopener noreferrer"&gt;the complete guide to zero-downtime Magento deployment&lt;/a&gt;, &lt;a href="https://byte8.io/blog/speed-up-magento-deployments" rel="noopener noreferrer"&gt;how Orbit cuts deploy time to 75 seconds&lt;/a&gt;, or &lt;a href="https://byte8.io/blog/predicting-magento-migration-block-windows" rel="noopener noreferrer"&gt;how we predict the migration block window before deploy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://byte8.io/blog/magento-deployment-tools-compared" rel="noopener noreferrer"&gt;Byte8 blog&lt;/a&gt;. &lt;a href="https://byte8.io/products/orbit" rel="noopener noreferrer"&gt;See how Orbit deploys Magento with zero downtime →&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>magneto</category>
      <category>php</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Scariest Part of a Magento Deploy Is the Database Migration. We Made It a Number.</title>
      <dc:creator>Serhiy K</dc:creator>
      <pubDate>Wed, 12 Aug 2026 07:40:38 +0000</pubDate>
      <link>https://dev.to/byte8io/the-scariest-part-of-a-magento-deploy-is-the-database-migration-we-made-it-a-number-m3b</link>
      <guid>https://dev.to/byte8io/the-scariest-part-of-a-magento-deploy-is-the-database-migration-we-made-it-a-number-m3b</guid>
      <description>&lt;p&gt;We tell people we deploy Magento at 2pm on a Tuesday. The most common reply isn't "no you don't" — it's "sure, but the &lt;em&gt;database migration&lt;/em&gt; is the scary part." And they're right.&lt;/p&gt;

&lt;p&gt;The cutover itself is trivial. Swapping a &lt;code&gt;current&lt;/code&gt; symlink from one release directory to the next is atomic and instant; if it goes wrong you swap it back. Nobody loses sleep over the symlink. The part that actually makes a midday deploy frightening is &lt;code&gt;setup:upgrade&lt;/code&gt; — and specifically &lt;em&gt;not knowing&lt;/em&gt;, in advance, whether this release's schema change will finish in eight seconds or hold a lock on &lt;code&gt;sales_order_item&lt;/code&gt; for four minutes. On a traditional pipeline you find that out live, in production, which is the worst possible place to learn it.&lt;/p&gt;

&lt;p&gt;So we stopped guessing. Before &lt;code&gt;setup:upgrade&lt;/code&gt; runs, Orbit now forecasts the block window and puts a number on the screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the block time is a coin flip
&lt;/h2&gt;

&lt;p&gt;Since Magento 2.3, schema is &lt;strong&gt;declarative&lt;/strong&gt;: each module ships an &lt;code&gt;etc/db_schema.xml&lt;/code&gt; describing the tables it wants, and &lt;code&gt;setup:upgrade&lt;/code&gt; diffs the declared state against the live database and emits the DDL to close the gap. That's a genuine improvement over hand-written &lt;code&gt;InstallSchema&lt;/code&gt; scripts — but it hides the one thing you care about operationally, which is &lt;em&gt;how long the resulting &lt;code&gt;ALTER&lt;/code&gt; will block writes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On MySQL 8 that answer swings enormously depending on the change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding a column at the end of a table is &lt;strong&gt;instant&lt;/strong&gt; — a metadata-only change, free regardless of table size.&lt;/li&gt;
&lt;li&gt;Adding an index runs &lt;strong&gt;online&lt;/strong&gt; — writes keep flowing, and the cost scales with row count.&lt;/li&gt;
&lt;li&gt;Changing a column type forces a &lt;strong&gt;blocking table copy&lt;/strong&gt; — MySQL rebuilds the whole table, and on a multi-million-row &lt;code&gt;sales_*&lt;/code&gt; table that's minutes of held locks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same one-line diff in &lt;code&gt;db_schema.xml&lt;/code&gt;. Wildly different consequences. And nothing in the standard Magento tooling tells you which one you're about to trigger until you're already triggering it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The insight: everything you need to predict it is already sitting there
&lt;/h2&gt;

&lt;p&gt;The forecast doesn't require a staging replay or a dry run. Three inputs that already exist on the box are enough:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The old release's declarative schema&lt;/strong&gt; and &lt;strong&gt;the new release's&lt;/strong&gt; — merge every module's &lt;code&gt;db_schema.xml&lt;/code&gt; in each release tree exactly the way Magento does, then diff the two merged states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL 8's online-DDL rules&lt;/strong&gt; — a well-documented matrix mapping each kind of change to instant / online / blocking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live table statistics&lt;/strong&gt; — row counts straight from &lt;code&gt;information_schema.tables&lt;/code&gt;, to turn "online index on a big table" into an actual number of seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Put those together and the scariest unknown in Magento ops becomes arithmetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Orbit forecasts the window
&lt;/h2&gt;

&lt;p&gt;During the deploy, before it runs &lt;code&gt;setup:upgrade&lt;/code&gt;, Orbit builds the merged declarative schema for both the outgoing and incoming release, diffs them, and classifies every change against the online-DDL matrix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;change in db_schema.xml            class       cost model
--------------------------------   ---------   ----------------------------
new / dropped table                metadata    ~instant
add column (tail)                  instant     ~instant, any table size
drop index / drop constraint       metadata    ~instant
add index / add constraint         online      ~ rows / 100k  (writes flow)
drop column                        online      ~ rows / 100k
modify column type                 blocking    ~ rows / 50k   (table rebuild)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each online/blocking change is sized against the live row count for its table, the per-change estimates are summed, a little fixed overhead for Magento's own bootstrap is added, and the result is a single predicted hold in seconds. It reads like this in the deploy log:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;→ "1 online index on &lt;code&gt;sales_order_item&lt;/code&gt; (2.1M rows), ~12s. Within budget."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If it can't read a table's row count, it falls back to a conservative default and lowers its own &lt;strong&gt;confidence&lt;/strong&gt; — reported honestly as high / medium / low rather than hidden. An arbitrary PHP data patch in &lt;code&gt;Setup/Patch/Data&lt;/code&gt; can't be statically costed at all, so its presence pulls confidence down and says so. This is a forecast, and it's labelled like one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does with the number
&lt;/h2&gt;

&lt;p&gt;Two things, and it's worth being precise about the boundary between them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It tells you before you commit.&lt;/strong&gt; The prediction is advisory. It's written to the deploy record and surfaced in the log, and if the forecast exceeds the hold budget you set for that environment, Orbit warns you up front — "predicted hold ~90s exceeds the 25s budget; parked visitors will degrade to a waiting page." Whether to proceed now, or reschedule a genuinely long migration into a planned window, stays a human decision. Orbit's job is to make sure that decision is informed, not to quietly make it for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It makes the short windows a non-event.&lt;/strong&gt; For environments that opt in, a bounded, fail-open &lt;strong&gt;traffic hold&lt;/strong&gt; runs across the migration. It's a small buffer in front of the app that, for the few seconds the schema change needs, parks transactional requests — checkout, cart, customer actions — holding the connection open and replaying it against the app the instant the window clears. (Clients that give up are never replayed, so there are no double orders.) Everything else gets a lightweight waiting page with a live countdown driven by that same forecast, and anonymous browsing is served from cache. It's deliberately fail-open: if the buffer can't start for any reason, the deploy simply proceeds rather than blocking. A twelve-second online index becomes twelve seconds of "one moment" for a handful of in-flight checkouts — not a burst of 503s, and not a maintenance banner for everyone.&lt;/p&gt;

&lt;p&gt;The two systems are independent by design. The forecast informs you and drives the countdown; the hold protects in-flight requests. Neither one silently decides to skip or defer your migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does &lt;em&gt;not&lt;/em&gt; do
&lt;/h2&gt;

&lt;p&gt;It doesn't replay your migration on a copy of production, so it won't catch a pathological trigger or a data patch that does something expensive in PHP — those show up as lowered confidence, not a precise number. It doesn't turn a four-minute table rebuild into a fast one; physics still applies. What it removes is the &lt;em&gt;surprise&lt;/em&gt;. A blocking &lt;code&gt;MODIFY COLUMN&lt;/code&gt; on a huge table is still slow — but now you know that at 1:55pm, before you click deploy, instead of at 2:03pm with the phones ringing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The whole game
&lt;/h2&gt;

&lt;p&gt;The reason "deploy at 2pm on a Tuesday" sounds reckless is that the DB migration has always been an unbounded unknown. Turn that unknown into a number on a screen — before anyone clicks Deploy — and the fear goes with it. That's the entire point: not bravado, just refusing to find out the hard way.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://byte8.io/blog/predicting-magento-migration-block-windows" rel="noopener noreferrer"&gt;Byte8 blog&lt;/a&gt;. &lt;a href="https://byte8.io/products/orbit" rel="noopener noreferrer"&gt;See how Orbit deploys Magento with zero downtime →&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>magneto</category>
      <category>php</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
