{"id":125,"date":"2025-10-02T00:00:00","date_gmt":"2025-10-01T22:00:00","guid":{"rendered":"https:\/\/helloblog.io\/hr\/zero-downtime-wordpress-deployment-trellis-atomic-rollback\/"},"modified":"2026-01-20T06:33:04","modified_gmt":"2026-01-20T05:33:04","slug":"zero-downtime-wordpress-deployment-trellis-atomic-rollback","status":"publish","type":"post","link":"https:\/\/helloblog.io\/hr\/zero-downtime-wordpress-deployment-trellis-atomic-rollback\/","title":{"rendered":"Zero-downtime deployment za WordPress s Trellisom: kako rade atomic releaseovi i rollback"},"content":{"rendered":"\n<p>U modernom web developmentu je normalno o\u010dekivati da deploy ne prekida aplikaciju. U WordPress svijetu to i dalje \u010desto izgleda kao \u201cuploadaj nove fajlove pa se moli da sve pro\u0111e\u201d. Roots Trellis tu donosi pristup koji je bli\u017ei onome \u0161to rade ozbiljni app deploy pipelineovi: <strong>atomic deployments<\/strong> (atomski deploy), uz <strong>immutable releases<\/strong> (nepromjenjive verzije) i brzi rollback.<\/p>\n\n\n\n<p>Bitno: Trellis ne mora\u0161 koristiti za cijeli workflow. Puno timova ga koristi <em>samo<\/em> za deployment Bedrock projekta na razne hosting okoline (uklju\u010duju\u0107i managed hostove), dok lokalno rade u okru\u017eenju koje im ve\u0107 pa\u0161e (Valet, Lando, DDEV\u2026).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u0160to \u201czero downtime deployment\u201d stvarno zna\u010di u praksi<\/h2>\n\n\n\n<p>Zero downtime deployment zna\u010di da je web u cijelom procesu deploya i dalje <strong>funkcionalan i dostupan<\/strong>. Nema perioda u kojem server poslu\u017euje mje\u0161avinu stare i nove verzije koda, niti trenutaka kad su neke datoteke ve\u0107 prepisane, a neke jo\u0161 nisu stigle.<\/p>\n\n\n\n<p>Klju\u010dna ideja je <strong>izolirana priprema nove verzije<\/strong> i onda <strong>trenutno prebacivanje<\/strong> na nju (bez postupnog prepisivanja live fajlova).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Za\u0161to su klasi\u010dni WordPress deployi rizi\u010dni<\/h2>\n\n\n\n<p>Naj\u010de\u0161\u0107i na\u010dini kako se WordPress i dalje deploya na produkciju imaju isti temeljni problem: a\u017euriranje ide \u201cin-place\u201d dok je site live.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>FTP upload<\/strong>: ru\u010dno prebacivanje i prepisivanje fajlova. Kako upload traje, produkcija mo\u017ee poslu\u017eivati polu-staro\/polu-novo stanje, \u0161to \u010desto rezultira gre\u0161kama.<\/li>\n\n\n<li><strong>rsync \/ file sync alati<\/strong>: br\u017ee od FTP-a, ali i dalje radi\u0161 prepisivanje postoje\u0107ih fajlova dok korisnici surfaju.<\/li>\n\n\n<li><strong>plugin-based deployment<\/strong> na managed hostovima: zgodno za kliknuti, ali \u010desto bez pravog rollback mehanizma i opet s in-place updateom.<\/li>\n\n<\/ul>\n\n\n\n<p>Rezultat: deployment prozor u kojem se mogu pojaviti 500 gre\u0161ke, fatal errori, missing class, nedostaju\u0107e asset datoteke ili napuknuti cache. A kad ne\u0161to krene po zlu, vra\u0107anje na staro zna biti sporo i ru\u010dno.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kako Trellis radi atomic deployment (atomski deploy)<\/h2>\n\n\n\n<p>Trellis preuzima provjereni obrazac iz svijeta aplikacija: svaka verzija se deploya u <strong>novi release direktorij<\/strong>, potpuno odvojeno od aktivne verzije. Tek kad je sve spremno (kod, dependencyji, symlinkovi), Trellis jednim potezom prebaci web na novu verziju.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Struktura direktorija na serveru<\/h3>\n\n\n\n<p>Kod Trellisa je najva\u017eniji detalj <code>current<\/code> \u2014 to je symlink (simboli\u010dka poveznica) na release koji je trenutno aktivan. Web server uvijek poslu\u017euje iz <code>current<\/code>, a <code>current<\/code> se samo preusmjeri na novu verziju.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/srv\/www\/example.com\/\n\u251c\u2500\u2500 current\/             # Symlink na aktivni release\n\u251c\u2500\u2500 releases\/            # Svi deployani releaseovi\n\u2502   \u251c\u2500\u2500 20250930124530\/\n\u2502   \u251c\u2500\u2500 20250930083045\/\n\u2502   \u2514\u2500\u2500 20250930141622\/  # Najnoviji\n\u251c\u2500\u2500 shared\/              # Dijeljeni fajlovi izme\u0111u releaseova\n\u2502   \u2514\u2500\u2500 uploads\/\n\u2514\u2500\u2500 logs\/\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#B392F0\">\/srv\/www\/example.com\/<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> current\/<\/span><span style=\"color:#6A737D\">             # Symlink na aktivni release<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> releases\/<\/span><span style=\"color:#6A737D\">            # Svi deployani releaseovi<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u2502<\/span><span style=\"color:#9ECBFF\">   \u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> 20250930124530\/<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u2502<\/span><span style=\"color:#9ECBFF\">   \u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> 20250930083045\/<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u2502<\/span><span style=\"color:#9ECBFF\">   \u2514\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> 20250930141622\/<\/span><span style=\"color:#6A737D\">  # Najnoviji<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> shared\/<\/span><span style=\"color:#6A737D\">              # Dijeljeni fajlovi izme\u0111u releaseova<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u2502<\/span><span style=\"color:#9ECBFF\">   \u2514\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> uploads\/<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u2514\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> logs\/<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">\u0160to se dogodi kad pokrene\u0161 deploy<\/h3>\n\n\n\n<p>Kad izvr\u0161i\u0161 <code>trellis deploy production<\/code>, Trellis odradi deployment u vi\u0161e faza, ali bez diranja live releasea do samog kraja:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>Initialize<\/strong>: provjera\/kreiranje strukture direktorija i otvaranje novog release direktorija (timestamp).<\/li>\n\n\n<li><strong>Update<\/strong>: kloniranje najnovijeg koda iz Git repozitorija u odvojeni source direktorij (izvan live patha).<\/li>\n\n\n<li><strong>Prepare<\/strong>: kopiranje pripremljenih datoteka u novi release direktorij.<\/li>\n\n\n<li><strong>Build<\/strong>: pokretanje <code>composer install<\/code> za dependencyje.<\/li>\n\n\n<li><strong>Share<\/strong>: symlinkanje dijeljenih direktorija\/fajlova (npr. media <code>uploads<\/code>) iz <code>shared<\/code> u novi release.<\/li>\n\n\n<li><strong>Finalize<\/strong>: prebacivanje <code>current<\/code> symlinka na novi release.<\/li>\n\n<\/ul>\n\n\n\n<p>Efekt je jednostavan: u jednom trenutku web servira <code>releases\/\u2026stari\u2026<\/code>, a odmah nakon toga <code>releases\/\u2026novi\u2026<\/code>. Nema \u201cme\u0111ustanja\u201d i nema prepisivanja fajlova koje korisnici mogu uhvatiti usred requesta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Baza podataka: deploy koda nije isto \u0161to i migracije<\/h2>\n\n\n\n<p>Ovdje treba biti realan: Trellis rje\u0161ava zero downtime za <strong>kod i filesystem<\/strong>, ali promjene sheme baze (migracije) su zasebna tema. Prema dokumentaciji Trellisa, migracije baze nisu automatski dio Trellis deploya.<\/p>\n\n\n\n<p>Ako koristi\u0161 Acorn, mo\u017ee\u0161 raditi migracije na Laravel na\u010din (Laravel migrations) i ugraditi njihovo izvo\u0111enje u deployment proces. To je \u010desto naj\u010di\u0161\u0107i put ako \u017eeli\u0161 disciplinirano verzioniranje promjena u bazi, ali zahtijeva da migracije pi\u0161e\u0161 \u201cproduction-safe\u201d (npr. kompatibilnost unazad dok traje rollout).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rollback u par sekundi (i za\u0161to je to velika stvar)<\/h2>\n\n\n\n<p>Atomic + immutable releaseovi zna\u010de da se release nakon deploya vi\u0161e ne mijenja. Ako nova verzija napravi problem, rollback je samo prebacivanje symlinka natrag na prethodni release.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>trellis rollback production\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#B392F0\">trellis<\/span><span style=\"color:#9ECBFF\"> rollback<\/span><span style=\"color:#9ECBFF\"> production<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Po defaultu Trellis na serveru zadr\u017eava zadnjih pet releaseova, \u0161to je obi\u010dno dovoljno da se brzo vrati\u0161 na stabilnu verziju bez ikakvog \u201ckopiraj nazad fajlove\u201d scenarija.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy hookovi: gdje ubaciti svoje korake<\/h2>\n\n\n\n<p>Trellis ima hookove (to\u010dke pro\u0161irenja) za prilagodbu deployment flowa. Prakti\u010dno: mo\u017ee\u0161 dodati vlastite korake bez forkanja deploy logike.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>deploy_build_before<\/code> i <code>deploy_build_after<\/code> za custom build korake.<\/li>\n\n\n<li><code>deploy_finalize_before<\/code> i <code>deploy_finalize_after<\/code> za pre\/post switch zadatke.<\/li>\n\n\n<li>Hookovi postoje i po fazama (initialize, update, prepare, build, share, finalize).<\/li>\n\n<\/ul>\n\n\n\n<p>To otvara tipi\u010dne obrasce iz \u201cpravog\u201d DevOpsa: backup baze prije deploya, \u010di\u0161\u0107enje cachea nakon switcha, slanje notifikacija timu, ili pokretanje smoke testova na novom releaseu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kako krenuti (minimalni put do prvog zero-downtime deploya)<\/h2>\n\n\n\n<p>Ako ti je cilj samo dobiti stabilniji deployment bez prekida rada, najkra\u0107i put izgleda ovako:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Postavi projekt na <a href=\"https:\/\/roots.io\/bedrock\/\">Bedrock<\/a> strukturu (ure\u0111eniji WordPress projekt, Composer-first).<\/li>\n\n\n<li>Instaliraj i konfiguriraj <a href=\"https:\/\/roots.io\/trellis\/\">Trellis<\/a> za deployment postavke.<\/li>\n\n\n<li>U <code>wordpress_sites.yml<\/code> upi\u0161i podatke o repozitoriju i target environmentu.<\/li>\n\n\n<li>Pokreni <code>trellis deploy production<\/code>.<\/li>\n\n<\/ol>\n\n\n\n<div class=\"wp-block-group callout callout-info is-style-info is-layout-flow wp-block-group-is-layout-flow\" style=\"border-width:1px;border-radius:8px;padding-top:1rem;padding-right:1.5rem;padding-bottom:1rem;padding-left:1.5rem\">\n\n<h4 class=\"wp-block-heading callout-title\">Napomena o prvom deployu<\/h4>\n\n\n<p>Prvi deploy tipi\u010dno traje dulje jer se inicijalno postavlja struktura direktorija i povla\u010de dependencyji. Kasniji deployevi su br\u017ei \u2014 i najva\u017enije, bez prekida rada.<\/p>\n\n<\/div>\n\n\n<div class=\"references-section\">\n                <h2>Reference \/ Izvori<\/h2>\n                <ul class=\"references-list\"><li><a href=\"https:\/\/roots.io\/zero-downtime-wordpress-deployments-with-trellis\/\" target=\"_blank\" rel=\"noopener noreferrer\">Zero Downtime WordPress Deployments with Trellis<\/a><\/li><li><a href=\"https:\/\/roots.io\/trellis\/docs\/deployments\/\" target=\"_blank\" rel=\"noopener noreferrer\">Trellis Documentation: Deployments<\/a><\/li><li><a href=\"https:\/\/roots.io\/acorn\/docs\/creating-and-running-laravel-migrations\/\" target=\"_blank\" rel=\"noopener noreferrer\">Acorn Documentation: Creating and running Laravel migrations<\/a><\/li><li><a href=\"https:\/\/roots.io\/bedrock\/\" target=\"_blank\" rel=\"noopener noreferrer\">Bedrock<\/a><\/li><li><a href=\"https:\/\/roots.io\/trellis\/\" target=\"_blank\" rel=\"noopener noreferrer\">Trellis<\/a><\/li><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>Ako si ikad deployao WordPress preko FTP-a i nadao se da korisnici ba\u0161 tada ne\u0107e klikati, Trellisov atomic deployment model rje\u0161ava taj stres: nova verzija se pripremi odvojeno, a prebacivanje je trenutno.<\/p>\n","protected":false},"author":44,"featured_media":124,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31],"tags":[66,71,72,70,10],"class_list":["post-125","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wordpress-ekosustav","tag-bedrock","tag-deploy","tag-devops","tag-trellis","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts\/125","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/users\/44"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/comments?post=125"}],"version-history":[{"count":1,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts\/125\/revisions"}],"predecessor-version":[{"id":141,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/posts\/125\/revisions\/141"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/media\/124"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/media?parent=125"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/categories?post=125"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/hr\/wp-json\/wp\/v2\/tags?post=125"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}