{"id":136,"date":"2025-10-02T00:00:00","date_gmt":"2025-10-01T22:00:00","guid":{"rendered":"https:\/\/helloblog.io\/sl\/zero-downtime-deploy-wordpress-s-trellis\/"},"modified":"2026-01-20T06:33:06","modified_gmt":"2026-01-20T05:33:06","slug":"zero-downtime-deploy-wordpress-s-trellis","status":"publish","type":"post","link":"https:\/\/helloblog.io\/sl\/zero-downtime-deploy-wordpress-s-trellis\/","title":{"rendered":"Zero downtime deploy za WordPress s Trellis: atomarni releasi brez panike"},"content":{"rendered":"\n<p>V modernem razvoju aplikacij je samoumevno, da novi release na produkciji ne sme prekiniti delovanja. Pri WordPress projektih pa se \u0161e vedno pogosto dogaja ravno to: datoteke se prepisujejo \u201cv \u017eivo\u201d, uporabniki vmes zadenejo \u010duden miks stare in nove kode, rezultat pa so napake, prazne strani ali nedelujo\u010di admini.<\/p>\n\n\n\n<p>Trellis (del ekosistema Roots) ima to te\u017eavo re\u0161eno zelo elegantno: uporablja <strong>atomarne deploye<\/strong> (atomic deployments), kjer se nova verzija pripravi lo\u010deno od live strani, nato pa se na koncu v trenutku preklopi. To pomeni <em>zero downtime<\/em> za kodo \u2013 in v praksi precej manj stresa pri vsakem deployu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kaj v praksi pomeni \u201czero downtime\u201d pri deployu<\/h2>\n\n\n\n<p>Zero downtime deploy pomeni, da je spletna stran za obiskovalce ves \u010das dosegljiva in funkcionalna. Klju\u010dna razlika do klasi\u010dnega WordPress deploya je, da se obstoje\u010de datoteke ne prepisujejo postopoma. Namesto tega se celoten novi release pripravi v izolaciji, \u0161ele nato se naredi instant preklop.<\/p>\n\n\n\n<p>Pri tradicionalnem pristopu (FTP, rsync ali \u201cdeployment\u201d prek vti\u010dnika) se pogosto zgodi, da med nalaganjem del kode \u017ee ka\u017ee na novo stanje, del pa je \u0161e star. WordPress je ob\u010dutljiv na tak\u0161ne vmesne faze: dovolj je, da se plugin posodobi, tema pa \u0161e ne, ali obratno, in dobimo napake, ki jih je te\u017eko reproducirati.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zakaj so klasi\u010dni WordPress deployi problemati\u010dni<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>FTP upload<\/strong>: ro\u010dno prepisovanje datotek. \u010casovno potratno, med prenosom pa stre\u017enik servira me\u0161anico starega in novega.<\/li>\n\n\n<li><strong>Sinhronizacija datotek (npr. <code>rsync<\/code>)<\/strong>: hitrej\u0161e, ampak konceptualno enak problem \u2013 datoteke se \u0161e vedno prepisujejo na live sistemu.<\/li>\n\n\n<li><strong>Deploy prek vti\u010dnika na managed hostingu<\/strong>: udobno, a pogosto brez pravega rollback mehanizma in \u0161e vedno z \u201cin-place\u201d posodobitvami.<\/li>\n\n<\/ul>\n\n\n\n<p>Skupni imenovalec: med deployem je mo\u017eno, da stran za kratek \u010das deluje napa\u010dno, in \u010de gre kaj narobe, je vra\u010danje na prej\u0161nje stanje zamudno (ali pa sploh ni jasno, kaj to\u010dno je treba povrniti).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kako Trellis to re\u0161i: atomarni in nespremenljivi releasi<\/h2>\n\n\n\n<p>Trellis uporabi pristop, ki je v drugih ekosistemih standard: vsak deploy ustvari <strong>nov, popoln release direktorij<\/strong>, ki se po koncu deploya nikoli ve\u010d ne spreminja (immutable release). Live promet pa vedno gleda v mapo <code>current<\/code>, ki je v resnici samo simbolna povezava (symlink) do aktivnega release direktorija.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tipi\u010dna struktura direktorijev na stre\u017eniku<\/h3>\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 do aktivnega releasa\n\u251c\u2500\u2500 releases\/            # vsi deployani releasi\n\u2502   \u251c\u2500\u2500 20250930124530\/\n\u2502   \u251c\u2500\u2500 20250930083045\/\n\u2502   \u2514\u2500\u2500 20250930141622\/  # najnovej\u0161i\n\u251c\u2500\u2500 shared\/              # deljene datoteke med releasi\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 do aktivnega releasa<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> releases\/<\/span><span style=\"color:#6A737D\">            # vsi deployani releasi<\/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\">  # najnovej\u0161i<\/span><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">\u251c\u2500\u2500<\/span><span style=\"color:#9ECBFF\"> shared\/<\/span><span style=\"color:#6A737D\">              # deljene datoteke med releasi<\/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<p>Web server je nastavljen tako, da servira iz <code>current<\/code>. Ko je nov release pripravljen, Trellis samo preusmeri <code>current<\/code> symlink na novo mapo. Preklop je prakti\u010dno takoj\u0161en, brez vmesne faze prepisovanja datotek.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Kaj se zgodi ob <code>trellis deploy production<\/code><\/h3>\n\n\n\n<p>Trellis deploy je sestavljen iz ve\u010d jasnih korakov. Pomembno je, da se \u201cnevarni\u201d del (priprava nove kode in dependencyjev) izvaja lo\u010deno od live direktorija:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>Initialize<\/strong>: preveri\/ustvari strukturo map in pripravi nov release direktorij z timestamp imenom.<\/li>\n\n\n<li><strong>Update<\/strong>: iz Git repozitorija pridobi najnovej\u0161o kodo v lo\u010den prostor (ne v live mapo).<\/li>\n\n\n<li><strong>Prepare<\/strong>: pripravi release direktorij za novo verzijo.<\/li>\n\n\n<li><strong>Build<\/strong>: za\u017eene <code>composer install<\/code> in s tem postavi PHP odvisnosti.<\/li>\n\n\n<li><strong>Share<\/strong>: v novi release se pove\u017eejo deljeni direktoriji\/datoteke (npr. <code>uploads<\/code>) iz <code>shared<\/code>.<\/li>\n\n\n<li><strong>Finalize<\/strong>: posodobi <code>current<\/code> symlink, da ka\u017ee na nov release.<\/li>\n\n<\/ol>\n\n\n\n<p>V enem trenutku produkcija \u0161e ka\u017ee na prej\u0161nji release, v naslednjem pa na novega. Ker preklop ni postopen, uporabniki ne morejo ujeti \u201cpolovi\u010dnega\u201d stanja aplikacije.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Baza ni del \u201czero downtime\u201d \u010darovnije (in to je pomembno)<\/h2>\n\n\n\n<p>Trellis z atomarnim deployem poskrbi za <strong>kodo in datote\u010dni sistem<\/strong>. Spremembe sheme baze (migracije) pa so lo\u010dena tema. V dokumentaciji Trellis je izrecno navedeno, da migracije baze niso samodejni del deploy procesa.<\/p>\n\n\n\n<p>\u010ce uporablja\u0161 Acorn (Rootsov sloj, ki v WordPress projekte pripelje Laravel koncepte), lahko migracije vodi\u0161 kot <strong>Laravel migrations<\/strong> in jih po potrebi vklju\u010di\u0161 v deploy proces. Klju\u010d je v tem, da migracije na\u010drtuje\u0161 tako, da so kompatibilne z \u201crolling\u201d prehodom med staro in novo kodo (npr. najprej dodaj stolpec, \u0161ele potem ga za\u010dni obvezno uporabljati).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rollback: najve\u010dja prakti\u010dna zmaga atomarnega deploya<\/h2>\n\n\n\n<p>Ker vsak release obstaja kot samostojen direktorij in se po deployu ne spreminja, je rollback trivialen: samo preusmeri\u0161 <code>current<\/code> symlink na prej\u0161nji release. Trellis ima za to vgrajen ukaz:<\/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 privzetih nastavitvah Trellis na stre\u017eniku obdr\u017ei nekaj zadnjih releaseov (v izvoru je navedeno pet). To pomeni, da se lahko v nekaj sekundah vrne\u0161 na delujo\u010do verzijo, brez ro\u010dnega kopiranja datotek ali iskanja \u201ckaj je \u0161lo na server\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy hooks: ko rabi\u0161 nekaj ve\u010d kot \u201csamo\u201d deploy<\/h2>\n\n\n\n<p>Trellis vklju\u010duje hooks (to so to\u010dke v procesu deploya, kjer lahko doda\u0161 svoje korake), npr. pred ali po buildu ter pred ali po finalizaciji. To omogo\u010da, da deploy prilagodi\u0161 svojemu stacku in hostingu, brez hackanja jedra Trellis-a.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>deploy_build_before<\/code> \/ <code>deploy_build_after<\/code>: dodatni build koraki (npr. kompilacija assetov, dodatni dependency check).<\/li>\n\n\n<li><code>deploy_finalize_before<\/code> \/ <code>deploy_finalize_after<\/code>: opravila tik pred preklopom ali takoj po njem.<\/li>\n\n\n<li>Hooks po posameznih fazah (initialize, update, prepare, build, share, finalize): ko \u017eeli\u0161 fino kontrolo nad flowom.<\/li>\n\n<\/ul>\n\n\n\n<p>Tipi\u010dni primeri v praksi: pred deployem narediti backup baze, po deployu po\u010distiti cache, poslati obvestilo ekipi ali zagnati osnovni smoke test proti novi verziji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kako za\u010deti, \u010de Trellis \u0161e ne uporablja\u0161<\/h2>\n\n\n\n<p>Za Trellis zero downtime deploy ti ni nujno, da z njim vodi\u0161 celoten lokalni razvojni workflow. Veliko ekip ga uporablja predvsem kot deployment orodje za Bedrock projekte, lokalno pa ostanejo pri svojem okolju (npr. Valet, Lando, DDEV ipd.). Po opisu v izvoru je osnovni \u201chappy path\u201d takle:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Projekt strukturiraj z <strong>Bedrock<\/strong> (bolj predvidljiva struktura, Composer-first pristop).<\/li>\n\n\n<li>Namesti in konfiguriraj <strong>Trellis<\/strong> ter deployment nastavitve.<\/li>\n\n\n<li>V <code>wordpress_sites.yml<\/code> nastavi podatke o Git repozitoriju.<\/li>\n\n\n<li>Za\u017eeni deploy z <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\">Opomba glede prvega deploya<\/h4>\n\n\n<p>Prvi deploy je praviloma po\u010dasnej\u0161i, ker se postavi struktura direktorijev in potegnejo vse odvisnosti. Naslednji deployi so hitrej\u0161i, klju\u010dna razlika pa je, da so tudi \u201cvarnej\u0161i\u201d za uporabnike, ker ni vmesnega prepisovanja live datotek.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Povzetek<\/h2>\n\n\n\n<p>Trellis s <strong>atomarnimi (atomic)<\/strong> in <strong>nespremenljivimi (immutable)<\/strong> releasi pripelje v WordPress svet deployment vzorec, ki ga v drugih okoljih jemljemo kot standard. Najve\u010dji prakti\u010dni koristi sta dve: med deployem ne servira\u0161 me\u0161anice starih in novih datotek, in \u010de gre kaj narobe, je rollback hiter in enostaven. Pri vsem tem pa ostaja pomembno, da spremembe baze obravnava\u0161 lo\u010deno in jih na\u010drtuje\u0161 premi\u0161ljeno.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Reference \/ Viri<\/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\/bedrock\/\" target=\"_blank\" rel=\"noopener noreferrer\">Bedrock<\/a><\/li><li><a href=\"https:\/\/roots.io\/trellis\/\" target=\"_blank\" rel=\"noopener noreferrer\">Trellis<\/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><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>\u010ce si \u017ee kdaj deployal WordPress prek FTP-ja in vmes dobil klic, da je stran \u201cpokvarjena\u201d, je \u010das za atomarni pristop. Trellis prinese moderni zero downtime deploy v WordPress svet \u2013 z instant preklopom in rollbackom na en ukaz.<\/p>\n","protected":false},"author":45,"featured_media":135,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[70,74,75,73,10],"class_list":["post-136","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ekosistem-wordpress","tag-bedrock","tag-deploy","tag-devops","tag-trellis","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/posts\/136","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/users\/45"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/comments?post=136"}],"version-history":[{"count":1,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/posts\/136\/revisions"}],"predecessor-version":[{"id":152,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/posts\/136\/revisions\/152"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/media\/135"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/media?parent=136"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/categories?post=136"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/sl\/wp-json\/wp\/v2\/tags?post=136"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}