[{"data":1,"prerenderedAt":754},["ShallowReactive",2],{"blog-en-\u002Fen\u002Fblog\u002Fstrapi-directus-ghost-self-hosted-guide":3,"blog-en-surround-\u002Fen\u002Fblog\u002Fstrapi-directus-ghost-self-hosted-guide":739},{"id":4,"title":5,"author":6,"body":7,"category":718,"cover":719,"date":720,"description":721,"draft":722,"extension":723,"lastReviewed":719,"meta":724,"navigation":725,"path":726,"readingTime":727,"seo":728,"sitemap":729,"stem":730,"tags":731,"__hash__":738},"blog_en\u002Fen\u002Fblog\u002Fstrapi-directus-ghost-self-hosted-guide.md","Self-hosted Strapi, Directus, and Ghost: honest guide for agencies and indie hackers","HeroCtl team",{"type":8,"value":9,"toc":702},"minimark",[10,14,17,20,23,28,31,38,44,55,61,67,71,74,77,80,83,86,89,93,96,99,102,105,108,111,115,118,121,124,127,130,133,137,140,356,359,363,366,390,419,446,450,453,459,465,471,477,481,484,490,496,502,505,509,512,518,524,530,536,542,546,552,558,564,570,576,580,583,589,595,601,607,613,616,620,626,632,638,644,650,656,662,666,669,672,675,685,699],[11,12,13],"p",{},"Every Brazilian agency hosting client sites knows the dilemma. You have thirty active accounts, each with a Wordpress on Wordpress.com Business costing between US$25 and US$45 per month — when the customer doesn't demand Wordpress.com VIP, which goes to three digits. Add that, multiply by thirty, divide by the dollar of the month, and the margin disappears. The oldest alternative is renting cheap shared hosting and stacking thirty sites on a PHP server that falls together on the first Tuesday of the month — reputation burned for saving five hundred reais.",[11,15,16],{},"There's a middle path that became viable in the last two years: replace the PHP monolith with a modern self-hosted CMS. Strapi, Directus, and Ghost are the three that most appear in agency projects and in indie SaaS in Brazil. Each solves a different problem, each has its own trap, and each one's official documentation sells the product instead of comparing honestly. This post is the comparison that was missing.",[11,18,19],{},"The audience here is dual. On one side, the agency of five to twenty people that delivers site or editorial platform to client — that profile needs to decide between managed cloud and self-hosting based on cost per client, not technical hype. On the other, the solo developer or indie hacker who's choosing the stack of their own project and wants to know which CMS scales better without becoming a Saturday headache.",[11,21,22],{},"The numbers are the post's skeleton. Costs in dollars were converted to reais using the current band of R$5.00 to R$5.30 per dollar — where the interval matters, it's marked. RAM and CPU requirements were collected from the official documentations and validated on test VPSes running synthetic workload. If any number seems optimistic, it's because it's the floor — real production usually asks for 30 to 50 percent more.",[24,25,27],"h2",{"id":26},"why-self-hosted-cms-became-viable-in-2026","Why self-hosted CMS became viable in 2026",[11,29,30],{},"Five combined factors unlocked the scenario. None of them is new alone; what changed is that they all matured at the same time.",[11,32,33,37],{},[34,35,36],"strong",{},"The cost of virtual machine fell to near absurd."," Hetzner, DigitalOcean, OVH, and even Brazilian providers like Magalu Cloud and UOL Host sell 2 vCPU and 4 GB RAM VPS for less than R$60 per month. Five years ago, the same capacity cost triple. For agency that historically outsourced infra to hosting resellers, now it makes more sense to rent a dedicated machine and stack workloads there.",[11,39,40,43],{},[34,41,42],{},"Self-hosted orchestration panels cover what was missing in ops."," Coolify, Dokploy, CapRover, and HeroCtl itself deliver what was exclusivity of expensive vendors: deploy from a config file, automatic TLS certificate, rollback from one version to another, basic metrics. The barrier to running a Strapi in production fell from \"a week of manual provisioning\" to \"five minutes after the server is up\".",[11,45,46,49,50,54],{},[34,47,48],{},"Modern CMSes publish official and mature Docker images."," It's been three years since you needed to mount your own Dockerfile for Strapi in production; today the official team publishes a tested image with reference docker-compose recipe. Even for Ghost, which historically had its own packaging, the ",[51,52,53],"code",{},"ghost:5-alpine"," image is the form recommended by the official team.",[11,56,57,60],{},[34,58,59],{},"Brazilian communities stopped being invisible."," The Strapi BR Discord channel has thousands of active members, the Directus official forum responds in English but with high participation of Brazilian devs, and Ghost documentation has been translated in pieces by local contributors. It's not the WordPress community (which is gigantic and full of PT-BR tutorials), but it's enough to unlock most problems without having to decipher technical English on the fourth consecutive error.",[11,62,63,66],{},[34,64,65],{},"Wordpress.com aggressively raised prices."," Whoever followed Heroku going paid in 2022 recognizes the pattern: free or cheap service becomes premium, old plan is discontinued, legacy account migrates or pays more. Wordpress.com did the equivalent over the last two years — the \"Personal\" tier rose, the \"Premium\" tier rose more, and features that previously came on the medium plan now require the Business tier or higher. Each increase is one more push toward self-hosting.",[24,68,70],{"id":69},"strapi-the-api-first-cms","Strapi — the API-first CMS",[11,72,73],{},"Strapi is what most resembles \"modern Wordpress for dev\". You define the content type in the admin interface (post, author, category, product, anything), and Strapi automatically generates a REST API and a GraphQL API to read and write that content. There's no frontend in it — it's pure headless backend. The frontend is your responsibility, generally a Next.js, Nuxt, or Astro consuming the API.",[11,75,76],{},"The stack is Node.js on the backend, Postgres or MySQL database for persistence, and a React admin panel that comes embedded. The panel is the product's strong point: non-technical editor manages to create content without training, organize media, schedule publication, manage users. For agency, that's an easy sell — the customer enters the admin and recognizes the \"Wordpress but cleaner\" paradigm.",[11,78,79],{},"The realistic minimum requirement in production is 2 vCPU, 2 GB of RAM, and 10 GB of storage. The official documentation talks of 1 GB, but with any active plugin and traffic beyond local test, memory blows. On VPS of R$50 to R$80 per month you run comfortably; on VPS of R$30 (1 GB of RAM) the process dies every time a larger media upload happens.",[11,81,82],{},"The strong points are consistent. Rich plugin ecosystem — social authentication, internationalization, S3 integration for media, sitemap generator, all already exist. Native GraphQL without extra configuration, which fits well with modern frontend. Custom hooks (lifecycle hooks, middlewares, policies) solve business rule without needing separate microservice. The admin interface is genuinely good — compared with Drupal or Wordpress without admin plugin, it's another level.",[11,84,85],{},"The weak points are also consistent, and worth saying out loud. The transition between major versions usually breaks — the migration from v4 to v5 was notorious, with incompatible API changes and need to rewrite custom plugins. If you adopt Strapi for a long-term project, reserve an upgrade window every twelve or eighteen months as recurring cost, not surprise. Schema migrations also require discipline — adding field is easy, renaming or typing differently without losing data asks for migration script written by hand. And some features that appear in the marketing only run in Strapi Cloud (their paid version), like live preview between environments — self-hosting you don't have it ready.",[11,87,88],{},"When it makes sense to choose Strapi: SaaS that needs own blog and knowledge base on the same CMS, agency that delivers to customer used to \"Wordpress but without PHP\", headless commerce project where SKUs are modeled as content type, and any scenario where having ready GraphQL saves days of work.",[24,90,92],{"id":91},"directus-the-cms-for-existing-data","Directus — the CMS for existing data",[11,94,95],{},"Directus is a different creature. Instead of forcing you to create content type from scratch within it, it puts an admin interface on top of any database you already have. You'd point to a legacy Postgres with twenty existing tables, and Directus shows each table as an editable collection, respecting column types, foreign keys, and even constraints. It's the tool that most resembles \"universal admin for any SQL database\".",[11,97,98],{},"The stack is Node.js on the backend, official support for Postgres, MySQL, MariaDB, SQLite, Oracle, and SQL Server, and an admin panel in Vue. Database support is deliberately broad — the product was designed to adapt, not to impose its own schema. You can use Directus against an empty database and let it create the tables via interface, or point to a database with ten years of history and expect everything to appear organized in admin.",[11,100,101],{},"The minimum requirement is lighter than Strapi. 1 vCPU, 1 GB of RAM, and 5 GB of storage run comfortably for small and medium workload. On VPS of R$30 to R$50 per month you can bring up a Directus serving dozens of collections with moderate traffic. For smaller projects, SQLite as database is sufficient — fits in a single file, simplifies backup, avoids having a separate Postgres to manage.",[11,103,104],{},"The strong points come from the design. The ability to adopt existing database without reformulating schema is genuinely unique — no popular CMS does this so well. Real-time updates via WebSockets come ready, which opens door to dashboards and internal tools that react to change in real time without needing an additional layer. Granular permissions per collection, per field, and even per row (based on condition) cover multi-tenancy scenarios without hack. The documentation is decent, kept active, and the team responds to questions in forum within reasonable timeframes.",[11,106,107],{},"The weak points: the learning curve for advanced customizations (extensions, custom hooks, dashboard panels) is steeper than Strapi. The plugin ecosystem is smaller — where Strapi has ten SEO plugins, Directus has two or three. And for non-technical editor, the interface is less friendly than Strapi's — Directus prioritizes power and flexibility, not smooth onboarding.",[11,109,110],{},"When it makes sense to choose Directus: agency that took on customer with ten-year-old legacy MySQL database and needs to deliver admin panel without redoing schema, internal tool where modeling is data-driven (custom CRM, inventory management, operations platform), application whose central entity is \"relational data\", not \"editorial document\". Also the obvious choice when the customer already has Postgres or MySQL running another system and wants to take advantage.",[24,112,114],{"id":113},"ghost-the-publishing-cms","Ghost — the publishing CMS",[11,116,117],{},"Ghost is the opposite of neutrality. It doesn't pretend to be universal CMS — it's blog and newsletter platform, specialized in editorial content. Whoever tries to use Ghost for e-commerce product or SaaS app is using the wrong tool. Whoever uses for corporate blog, media site, podcast with membership, or paid newsletter, finds a polished and focused product.",[11,119,120],{},"The stack is Node.js on the backend, MySQL or SQLite database (Postgres isn't officially supported), and frontend in Handlebars with theme. The frontend is part of the package — Ghost serves the pages directly, with theme installed via upload. There's headless mode (you use only the Content API and assemble the frontend separately), but the common case is Ghost serving everything.",[11,122,123],{},"The minimum requirement is the lightest of the three. 1 vCPU, 1 GB of RAM, and 5 GB of storage run Ghost with slack for medium-traffic blog. On VPS of R$30 you can run it — with care of configuring external SMTP for newsletter (sending email from the server itself is a recipe for falling into spam).",[11,125,126],{},"The strong points are sharp. Out-of-the-box SEO is the best among the three — meta tags, sitemap, schema.org, AMP (when it makes sense), all configured by default. Membership and paywall system comes native: you create subscription levels, charge via Stripe, release paid content automatically. The markdown editor is genuinely good, with cards (callouts, code) that cover the common case without becoming a Word editor. The themes focus on readability and editorial typography — nothing of the generic Wordpress theme aesthetic.",[11,128,129],{},"The weak points come from specialization. Plugin ecosystem is closed by design — integration apps exist on Ghost.org as paid product, and installing custom app is harder than in Strapi or Directus. Non-blog is hostile territory — trying to model product, author with rich profile, complex taxonomy bumps into design decisions that prioritize the \"post + author + tag\" case. And official Postgres support doesn't exist — if you have company standard on Postgres, you'll operate parallel MySQL just for Ghost.",[11,131,132],{},"When it makes sense to choose Ghost: corporate blog with paywall or premium content, media or independent journalism site, podcast that wants to monetize via membership, content marketing taken seriously with editor that will use the admin every day. For anything outside that scope, it's pushing the bar.",[24,134,136],{"id":135},"comparison-table","Comparison table",[11,138,139],{},"The three modern CMSes side by side with Wordpress (the inherited reference) and Payload (recent competitor worth mentioning):",[141,142,143,168],"table",{},[144,145,146],"thead",{},[147,148,149,153,156,159,162,165],"tr",{},[150,151,152],"th",{},"Criterion",[150,154,155],{},"Strapi",[150,157,158],{},"Directus",[150,160,161],{},"Ghost",[150,163,164],{},"Wordpress",[150,166,167],{},"Payload",[169,170,171,189,207,225,243,261,280,299,318,336],"tbody",{},[147,172,173,177,180,183,185,187],{},[174,175,176],"td",{},"Realistic minimum RAM",[174,178,179],{},"2 GB",[174,181,182],{},"1 GB",[174,184,182],{},[174,186,182],{},[174,188,179],{},[147,190,191,194,197,199,202,205],{},[174,192,193],{},"Time to first deploy",[174,195,196],{},"30–60 min",[174,198,196],{},[174,200,201],{},"15–30 min",[174,203,204],{},"10–20 min",[174,206,196],{},[147,208,209,212,215,217,220,223],{},[174,210,211],{},"Headless mode",[174,213,214],{},"Yes, default",[174,216,214],{},[174,218,219],{},"Optional",[174,221,222],{},"Optional (REST + GraphQL)",[174,224,214],{},[147,226,227,230,233,235,238,241],{},[174,228,229],{},"Native GraphQL",[174,231,232],{},"Yes",[174,234,232],{},[174,236,237],{},"No (REST)",[174,239,240],{},"External plugin",[174,242,232],{},[147,244,245,248,251,254,257,259],{},[174,246,247],{},"Easy multi-tenancy",[174,249,250],{},"Medium",[174,252,253],{},"Good",[174,255,256],{},"Hard",[174,258,240],{},[174,260,253],{},[147,262,263,266,269,271,274,277],{},[174,264,265],{},"Membership \u002F paywall",[174,267,268],{},"Plugin",[174,270,268],{},[174,272,273],{},"Native",[174,275,276],{},"Paid plugin",[174,278,279],{},"Custom",[147,281,282,285,288,290,293,296],{},[174,283,284],{},"Plugin ecosystem",[174,286,287],{},"Rich",[174,289,250],{},[174,291,292],{},"Weak",[174,294,295],{},"Very rich",[174,297,298],{},"Growing",[147,300,301,304,307,310,313,315],{},[174,302,303],{},"Cloud cost (initial USD\u002Fmonth)",[174,305,306],{},"15",[174,308,309],{},"25",[174,311,312],{},"11",[174,314,309],{},[174,316,317],{},"35",[147,319,320,323,326,329,331,333],{},[174,321,322],{},"Documentation in PT-BR",[174,324,325],{},"Partial",[174,327,328],{},"Minimal",[174,330,328],{},[174,332,295],{},[174,334,335],{},"English",[147,337,338,341,344,347,350,353],{},[174,339,340],{},"Ideal use range",[174,342,343],{},"API + admin",[174,345,346],{},"Admin over data",[174,348,349],{},"Editorial content",[174,351,352],{},"Generic site",[174,354,355],{},"Custom Node.js app",[11,357,358],{},"The \"time to first deploy\" column assumes server already provisioned and Docker installed. The \"Cloud cost\" column is the product's entry tier — price scale rises according to traffic, member, or admin seat limits. The \"documentation in PT-BR\" column reflects what exists official plus what the Brazilian community keeps active; none of the three has complete manual translated, but Strapi has the best learning path in Portuguese.",[24,360,362],{"id":361},"self-hosted-setup-at-a-high-level","Self-hosted setup at a high level",[11,364,365],{},"The recipe isn't copy-paste — it's the mental script of what will be needed. Specific details change per VPS and per orchestrator choice.",[11,367,368,369,371,372,375,376,379,380,379,383,379,386,389],{},"For ",[34,370,155],{},", the minimally serious setup is docker-compose with three services: Strapi, Postgres, and Redis (Redis is optional, but speeds up the admin noticeably when there are more than five editors). Named volume for ",[51,373,374],{},"\u002Fsrv\u002Fstrapi\u002Fuploads"," (media) and for Postgres data. Panel comes up on port 1337 internally, exposed via subdomain with TLS by the orchestrator's router. Critical environment variables: ",[51,377,378],{},"APP_KEYS",", ",[51,381,382],{},"JWT_SECRET",[51,384,385],{},"ADMIN_JWT_SECRET",[51,387,388],{},"DATABASE_*",". Forgetting any of those makes the admin not come up or lose session at every restart.",[11,391,368,392,394,395,379,398,379,401,379,404,379,407,410,411,414,415,418],{},[34,393,158],{},", the setup is similar but lighter. Docker-compose with Directus and database (SQLite fits in a single volume, Postgres if the expectation is multi-user with concurrent writing). No Redis necessary to start. Panel on port 8055. Critical variables: ",[51,396,397],{},"KEY",[51,399,400],{},"SECRET",[51,402,403],{},"ADMIN_EMAIL",[51,405,406],{},"ADMIN_PASSWORD",[51,408,409],{},"DB_*",". Attention point: if you point Directus to existing database with rich schema, open the admin calmly and configure permissions before giving access to any other user — by default the ",[51,412,413],{},"admin"," role sees everything and the ",[51,416,417],{},"public"," role sees nothing, which is reasonable; but if you create intermediate role without care, you expose entire collections without intending.",[11,420,368,421,423,424,427,428,431,432,379,435,438,439,441,442,445],{},[34,422,161],{},", docker-compose with Ghost and MySQL. SQLite serves for development but is discouraged in production by the official team. Named volume for ",[51,425,426],{},"\u002Fvar\u002Flib\u002Fghost\u002Fcontent"," (themes, media, configs) and for MySQL. Configuring external SMTP is mandatory step — Mailgun, Postmark, and Resend have free or cheap tier, any of them serves. Without SMTP, password recovery doesn't work, newsletter doesn't send, member signup is broken. Critical variables: ",[51,429,430],{},"url"," (public domain with https), ",[51,433,434],{},"database__connection__*",[51,436,437],{},"mail__*",". Common error: configuring ",[51,440,430],{}," as ",[51,443,444],{},"http:\u002F\u002Flocalhost"," in production and discovering only later that all email links came out broken.",[24,447,449],{"id":448},"compared-costs","Compared costs",[11,451,452],{},"The honest spreadsheet of managed cloud against self-hosted, in current currency (R$5.00 per dollar as reference):",[11,454,455,458],{},[34,456,457],{},"Strapi Cloud"," starts at US$15 per month on the Developer tier (R$75), rises to US$99 per month on the Pro tier (R$495) with features like separate staging and production environments, more admin seats, and support. Self-hosted on VPS of R$50 to R$80 per month runs Strapi with slack for small and medium workload. Monthly difference: from R$25 to R$445 depending on which tier you'd compare. For agency with five clients on Strapi, that translates to annual savings between R$1,500 and R$26,700.",[11,460,461,464],{},[34,462,463],{},"Directus Cloud"," starts at US$25 per month on the Standard tier (R$125), rises to US$99 per month on the Pro tier (R$495), and has Enterprise tier with price on consultation. Self-hosted on VPS of R$50 per month covers the common case. Difference similar to Strapi's — between R$75 and R$445 per month per instance.",[11,466,467,470],{},[34,468,469],{},"Ghost Pro"," starts at US$11 per month on the Starter tier (R$55) with up to 500 members and a single staff seat, scales to US$31 (R$155) with 1,000 members, and reaches US$249 per month (R$1,245) on the tier supporting 50,000 members. Self-hosted on VPS of R$50 to R$80 per month has no member ceiling — you can have 50,000 or 500,000 without changing the server (the only thing that changes is the volume of transactional email, which scales separately). For publication that grows in audience, the annual savings self-hosting Ghost passes R$10k quickly.",[11,472,473,476],{},[34,474,475],{},"Wordpress.com Business"," costs US$25 per month (R$125), VIP stays in three digits. Comparing with self-hosting Wordpress on a VPS of R$50 is meh — Wordpress is heavy by nature, requires more security and backup care, and the plugin ecosystem is recurring source of production incident. For new project in 2026, it's more sensible to choose between Strapi, Directus, or Ghost than to inherit PHP's complexity.",[24,478,480],{"id":479},"strategy-for-agency-hosting-thirty-clients","Strategy for agency hosting thirty clients",[11,482,483],{},"Three options with clear tradeoffs.",[11,485,486,489],{},[34,487,488],{},"Option A — one VPS per client."," Total isolation: if a client takes down their server, the other twenty-nine don't feel it. Direct cost: 30 VPS × R$30 to R$50 = R$900 to R$1,500 per month just on infra. Operational cost: thirty times everything — thirty OS updates, thirty certificates to monitor, thirty backups to orchestrate. For agency with more than ten clients, the operational overhead eats the margin the option had in the first place.",[11,491,492,495],{},[34,493,494],{},"Option B — a shared cluster running thirty CMS instances."," Four servers totaling 5 vCPU and 10 GB of RAM (the configuration we run in production here on HeroCtl) comfortably host thirty Strapi\u002FDirectus\u002FGhost instances with typical SME client traffic. Infra cost: about R$300 to R$400 per month for the entire cluster. Operational cost: a single monitoring strategy, a single backup strategy, a single place to look when something weighs the system. Agency margin increases because the point where you charge is the same and the point where you spend fell.",[11,497,498,501],{},[34,499,500],{},"Option C — shared cluster with each client on own subdomain."," Variation of option B, but with explicit routing by subdomain (client1.youragency.com, client2.youragency.com) or own client domain (client-shop.com.br). The orchestrator's integrated router solves the part of automatic TLS and traffic direction. Multi-tenancy stays at DNS + container level, not at CMS level — each client has isolated instance of Strapi\u002FDirectus\u002FGhost with own database. For agency that sells \"exclusive site\" as differentiator, it's the way to keep the promise without multiplying VPSes.",[11,503,504],{},"Option B with elements of C is what makes most sense for typical agency. Shared cluster, isolated instances, subdomain or own domain per client, centralized backup.",[24,506,508],{"id":507},"backup-and-migration-between-cms","Backup and migration between CMS",[11,510,511],{},"Migration between CMS is territory where vendors deliberately omit detail. The practical truth:",[11,513,514,517],{},[34,515,516],{},"Strapi to Strapi"," (between versions or between instances) has export and import via official plugin, generates JSON file with schema and data. Works well for migration between staging and production; between major versions, may ask for manual adjustment in the JSON before the import.",[11,519,520,523],{},[34,521,522],{},"Strapi to Directus"," has no ready tool. Schema is different enough to require manual mapping — Node script reading Strapi's REST API and writing on Directus's REST API, item by item. For base of one or ten thousand records, it's afternoon work; for larger base, worth parallelizing.",[11,525,526,529],{},[34,527,528],{},"Wordpress to Strapi"," has third-party tools (wp2strapi and variants), all partial. What migrates well is post + author + category + media. What doesn't migrate well is any complex custom post type, SEO plugin with own metadata, or menu structure. Reserve one to three days per site in migration and revise media manually.",[11,531,532,535],{},[34,533,534],{},"Ghost to Ghost"," has native export and import in admin — generates JSON with posts, authors, site configurations, members. Works clean between instances and between versions.",[11,537,538,541],{},[34,539,540],{},"Database backup"," is the non-negotiable step. Pg_dump (Postgres) or mysqldump (MySQL) daily, copied to object storage outside the server (S3, Backblaze B2, Wasabi). Without this, any incident — corrupted disk, accidental rm, hack — becomes extinction event for the client's data. S3 cost with versioning for a small cluster stays below R$50 per month even keeping thirty days of retention.",[24,543,545],{"id":544},"five-mistakes-that-kill-self-hosted-cms","Five mistakes that kill self-hosted CMS",[11,547,548,551],{},[34,549,550],{},"Not updating."," Outdated CMS is open vulnerability. Monthly update cron is the floor — fixed calendar, maintenance window combined with client, smoke test afterward. Not doing this means that sooner or later someone opens the client's admin without credential.",[11,553,554,557],{},[34,555,556],{},"Weak admin password."," Admin\u002Fadmin in production keeps happening in 2026. Strong password generated by password manager, two-factor authentication when the CMS supports, separate role for editor (the client doesn't get total admin password).",[11,559,560,563],{},[34,561,562],{},"No automatic backup."," Client sees six months of content disappear and the relationship ends. Daily database backup, retained for thirty days minimum, copied to storage outside the server hosting the CMS. Test restore at least once per quarter — backup that's never been restored is theory, not backup.",[11,565,566,569],{},[34,567,568],{},"Local media storage without CDN."," Large images on small VPS take down the server when a page goes viral. Configure object storage (S3, R2, Spaces) for media from day one, even if traffic is low at the start. Strapi and Directus have official providers for this; Ghost supports via configuration.",[11,571,572,575],{},[34,573,574],{},"Untested transactional email."," Strapi and Directus need SMTP configured for password reset to work. Ghost depends on SMTP for the entire newsletter. Configure and test on deploy day — send test email to yourself, check inbox and spam folder, adjust SPF\u002FDKIM if it falls in spam. Without this, the client discovers that the site broke on the day they need to change their own password.",[24,577,579],{"id":578},"heroctl-as-agency-infra","HeroCtl as agency infra",[11,581,582],{},"The last part of the guide is honest about how HeroCtl fits into this scenario. We don't pretend to be the only option — Coolify, Dokploy, and CapRover cover similar cases with different tradeoffs. What HeroCtl brings for agency hosting CMS is:",[11,584,585,588],{},[34,586,587],{},"Job templates to bring up new CMS in seconds."," Instead of writing docker-compose from scratch for each client, you keep a fifty-line config file with Strapi + Postgres already parameterized, change the domain and database name, and submit. New client enters production in less time than it takes to make coffee.",[11,590,591,594],{},[34,592,593],{},"Routing by subdomain with automatic TLS."," Each client on own subdomain (or own domain with DNS pointing) receives Let's Encrypt certificate without intervention. Renewal happens by itself. You don't touch web server config file — the integrated router handles it.",[11,596,597,600],{},[34,598,599],{},"Metrics per job."," Which client is weighing the cluster becomes visible on the panel — CPU, memory, requests per second, latency. When a client passes contracted volume, you see before the cluster feels.",[11,602,603,606],{},[34,604,605],{},"Managed backup"," (in the Business plan) covers all clients at once. Instead of configuring thirty separate pg_dump scripts, it's a central policy with configurable retention.",[11,608,609,612],{},[34,610,611],{},"Detailed audit"," (in the Business plan) covers LGPD requirement for client that needs to demonstrate who accessed what and when. For agency serving client in health, finance, or education, it stops being luxury.",[11,614,615],{},"The line between what comes in the Community plan (free, no server or job limit) and what's in Business is drawn by the type of requirement that appears when the agency grows. For five or ten clients, Community solves. For thirty clients where two of them require SSO and one requires audit report, Business pays for itself in the first month.",[24,617,619],{"id":618},"questions-we-get","Questions we get",[11,621,622,625],{},[34,623,624],{},"Wordpress vs these three — when does Wordpress still win?","\nWhen the client has internal team used to Wordpress, when the site depends on specific plugin that only exists in Wordpress (some hyper-localized e-commerce plugins, some LMS), and when the budget is so small that training editor on new CMS costs more than the hosting savings. For new project in 2026 without these restrictions, rarely.",[11,627,628,631],{},[34,629,630],{},"Can I run Strapi on R$30 VPS?","\nTechnically yes, in practice it's source of incident. 1 GB of RAM is the floor and any traffic spike or larger media upload takes down the process. Bump up to R$50 to R$80 — the difference is less than a lunch, and stability becomes another thing.",[11,633,634,637],{},[34,635,636],{},"Ghost and Strapi on the same server, ok?","\nOn small VPS (4 GB of RAM or less) it's tight and subject to contention. On 8 GB or more server with docker-compose separating resources, it works. On cluster with orchestrator, it's the common case — both run on different hosts or share with process isolation.",[11,639,640,643],{},[34,641,642],{},"How do I migrate Strapi v4 to v5 without burning the night?","\nDocument the current schema before touching. Bring up staging environment with v5 and the same database copied. Run the official migrator and verify everything in admin. Rewrite custom plugins before promoting to production — they don't migrate automatically. Reserve two to four business days for a medium Strapi. Without staging environment, don't turn the game directly in production.",[11,645,646,649],{},[34,647,648],{},"Transactional email for Ghost newsletter — which provider is cheapest?","\nMailgun has free tier up to five thousand emails per month, then costs by volume. Resend has free tier up to three thousand. Postmark is paid from the first email but is the most reliable in delivery. For small newsletter (up to two thousand members), free Mailgun or Resend solves. Above that, Postmark is worth the cost for the delivery rate.",[11,651,652,655],{},[34,653,654],{},"Is there a Brazilian agency case scaling like this?","\nThere are several, but those that speak in public are minority. The typical pattern is agency with ten to thirty clients, cluster of three or four servers on cloud provider, separate instances per client, centralized backup. When the agency publishes numbers, it usually talks of fifty to seventy percent savings over the equivalent in managed hosting — which matches the arithmetic above.",[11,657,658,661],{},[34,659,660],{},"Large image media — where to store?","\nObject storage outside the server hosting the CMS. AWS S3, Cloudflare R2, Backblaze B2, and DigitalOcean Spaces cover the case. R2 and B2 have better price than pure S3 for read-intensive workload. Configure from day one, even with low traffic — migrating media later is headache that doesn't compensate.",[24,663,665],{"id":664},"closing","Closing",[11,667,668],{},"The three modern CMSes cover three distinct cases. Strapi for those who want polished admin with headless API and plugin for everything. Directus for those who have data and need admin over it. Ghost for those who publish editorial content and want paywall without hack.",[11,670,671],{},"Self-hosting became viable because machine became cheap, self-hosted orchestrator became good, and the three products matured Docker packaging. For agency with more than five clients, the savings from cloud to self-hosting on shared cluster pays for one team person in a few months.",[11,673,674],{},"If you want to test the path of orchestrator on own cluster:",[676,677,682],"pre",{"className":678,"code":680,"language":681},[679],"language-text","curl -sSL https:\u002F\u002Fget.heroctl.com\u002Finstall.sh | sh\n","text",[51,683,680],{"__ignoreMap":684},"",[11,686,687,688,693,694,698],{},"Related posts that deepen specific points: ",[689,690,692],"a",{"href":691},"\u002Fen\u002Fblog\u002Fself-hosted-heroku-2026","Self-hosted Heroku in 2026"," covers the broader panorama of \"fleeing expensive PaaS\", and ",[689,695,697],{"href":696},"\u002Fen\u002Fblog\u002Fhow-much-to-host-a-brazilian-saas-2026","How much does it cost to host a Brazilian SaaS in 2026"," brings the complete infra spreadsheet for digital product starting from scratch.",[11,700,701],{},"Without ceremony.",{"title":684,"searchDepth":703,"depth":703,"links":704},2,[705,706,707,708,709,710,711,712,713,714,715,716,717],{"id":26,"depth":703,"text":27},{"id":69,"depth":703,"text":70},{"id":91,"depth":703,"text":92},{"id":113,"depth":703,"text":114},{"id":135,"depth":703,"text":136},{"id":361,"depth":703,"text":362},{"id":448,"depth":703,"text":449},{"id":479,"depth":703,"text":480},{"id":507,"depth":703,"text":508},{"id":544,"depth":703,"text":545},{"id":578,"depth":703,"text":579},{"id":618,"depth":703,"text":619},{"id":664,"depth":703,"text":665},"case-study",null,"2026-03-25","The three modern open-source CMSes Brazilian devs most self-host. One for each case. Comparison table, real requirements, and when it's worth paying for the cloud version.",false,"md",{},true,"\u002Fen\u002Fblog\u002Fstrapi-directus-ghost-self-hosted-guide","13 min",{"title":5,"description":721},{"loc":726},"en\u002Fblog\u002Fstrapi-directus-ghost-self-hosted-guide",[732,733,734,735,736,737],"cms","strapi","directus","ghost","self-hosted","guide","w0SGNznUB5Hl4gKpjXRhJFVwEuj1lP6cUT-GxG5eGj8",[740,747],{"title":741,"path":742,"stem":743,"description":744,"date":745,"category":746,"children":-1},"Is service mesh overkill for a Brazilian startup? When Istio\u002FLinkerd is worth installing","\u002Fen\u002Fblog\u002Fservice-mesh-when-its-worth-for-small-saas","en\u002Fblog\u002Fservice-mesh-when-its-worth-for-small-saas","Service mesh solves real problems (mTLS, inter-service observability, traffic shaping). But adds 30-50% RAM\u002FCPU overhead and complexity. When it's worth it and when it's overkill.","2026-05-29","engineering",{"title":748,"path":749,"stem":750,"description":751,"date":752,"category":753,"children":-1},"Why we built HeroCtl","\u002Fen\u002Fblog\u002Fwhy-we-built-heroctl","en\u002Fblog\u002Fwhy-we-built-heroctl","Kubernetes demands an SRE team. Simple panels lack real high availability. The closest technical competitor changed its license and was acquired. An alternative was missing — so we built one.","2025-11-12","release",1777362214073]