{"id":1480,"date":"2025-11-07T14:15:17","date_gmt":"2025-11-07T11:15:17","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/vpse-sifir-kesinti-ci-cd-nasil-kurulur-rsync-sembolik-surumler-ve-systemd-ile-sicacik-bir-yolculuk\/"},"modified":"2025-11-07T14:15:17","modified_gmt":"2025-11-07T11:15:17","slug":"vpse-sifir-kesinti-ci-cd-nasil-kurulur-rsync-sembolik-surumler-ve-systemd-ile-sicacik-bir-yolculuk","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/vpse-sifir-kesinti-ci-cd-nasil-kurulur-rsync-sembolik-surumler-ve-systemd-ile-sicacik-bir-yolculuk\/","title":{"rendered":"VPS\u2019e S\u0131f\u0131r Kesinti CI\/CD Nas\u0131l Kurulur? rsync, Sembolik S\u00fcr\u00fcmler ve systemd ile S\u0131cac\u0131k Bir Yolculuk"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Giris_Bir_Gecenin_Sessizliginde_Dagitim_Panikleri\"><span class=\"toc_number toc_depth_1\">1<\/span> Giri\u015f: Bir Gecenin Sessizli\u011finde Da\u011f\u0131t\u0131m Panikleri<\/a><\/li><li><a href=\"#Neden_Sifir_Kesinti_Hani_Su_Parmak_Izi_Gibi_Dagitimlar\"><span class=\"toc_number toc_depth_1\">2<\/span> Neden S\u0131f\u0131r Kesinti? Hani \u015eu Parmak \u0130zi Gibi Da\u011f\u0131t\u0131mlar<\/a><\/li><li><a href=\"#Sembolik_Surum_Duzeni_releases_current_ve_sharedin_Ufak_Sirri\"><span class=\"toc_number toc_depth_1\">3<\/span> Sembolik S\u00fcr\u00fcm D\u00fczeni: releases, current ve shared\u2019\u0131n Ufak S\u0131rr\u0131<\/a><\/li><li><a href=\"#CI_Tarafi_GitHub_Actions_GitLab_CI_rsync_ve_Minik_Bir_Dans\"><span class=\"toc_number toc_depth_1\">4<\/span> CI Taraf\u0131: GitHub Actions \/ GitLab CI, rsync ve Minik Bir Dans<\/a><\/li><li><a href=\"#systemd_ile_Nazik_Gecisler_Reload_Health_Check_ve_Atomik_Anahtar\"><span class=\"toc_number toc_depth_1\">5<\/span> systemd ile Nazik Ge\u00e7i\u015fler: Reload, Health Check ve Atomik Anahtar<\/a><\/li><li><a href=\"#Rollback_Bir_Komutla_Dunku_Huzura_Donmek\"><span class=\"toc_number toc_depth_1\">6<\/span> Rollback: Bir Komutla D\u00fcnk\u00fc Huzura D\u00f6nmek<\/a><\/li><li><a href=\"#Guvenlik_Izinler_ve_Kucuk_Parlatmalar_Dagitimin_Kolay_Unutulan_Koseleri\"><span class=\"toc_number toc_depth_1\">7<\/span> G\u00fcvenlik, \u0130zinler ve K\u00fc\u00e7\u00fck Parlatmalar: Da\u011f\u0131t\u0131m\u0131n Kolay Unutulan K\u00f6\u015feleri<\/a><\/li><li><a href=\"#Dagitim_Betikleri_Kucuk_Dokunuslar_Buyuk_Huzurlar\"><span class=\"toc_number toc_depth_1\">8<\/span> Da\u011f\u0131t\u0131m Betikleri: K\u00fc\u00e7\u00fck Dokunu\u015flar B\u00fcy\u00fck Huzurlar<\/a><\/li><li><a href=\"#CICDyi_Takvime_Baglamak_Oto_Dagitim_mi_Elle_Onay_mi\"><span class=\"toc_number toc_depth_1\">9<\/span> CI\/CD\u2019yi Takvime Ba\u011flamak: Oto Da\u011f\u0131t\u0131m m\u0131, Elle Onay m\u0131?<\/a><\/li><li><a href=\"#Kapanis_Sessiz_Dagitimlarin_Rahat_Uykusu\"><span class=\"toc_number toc_depth_1\">10<\/span> Kapan\u0131\u015f: Sessiz Da\u011f\u0131t\u0131mlar\u0131n Rahat Uykusu<\/a><\/li><\/ul><\/div>\n<h2 id=\"section-1\"><span id=\"Giris_Bir_Gecenin_Sessizliginde_Dagitim_Panikleri\">Giri\u015f: Bir Gecenin Sessizli\u011finde Da\u011f\u0131t\u0131m Panikleri<\/span><\/h2>\n<p>Hi\u00e7 gece yar\u0131s\u0131 bir g\u00fcncelleme atay\u0131m, kimse fark etmeden biter diye d\u00fc\u015f\u00fcn\u00fcp, tam o s\u0131rada site kafas\u0131na g\u00f6re \u00e7\u00f6k\u00fcverdi mi? Ben bir ak\u015fam, \u201ciki dakikal\u0131k i\u015f\u201d diye tarif etti\u011fim bir da\u011f\u0131t\u0131mda, beklenmedik bir dosya izni ve ufak bir yap\u0131land\u0131rma hatas\u0131 y\u00fcz\u00fcnden anasayfay\u0131 bembeyaz b\u0131rakm\u0131\u015ft\u0131m. O an \u00f6\u011frendim ki, da\u011f\u0131t\u0131m dedi\u011fin \u015fey ak\u0131\u015f\u0131 bozmadan yap\u0131lmad\u0131\u011f\u0131nda, en sakin saat bile stresin en canl\u0131 h\u00e2line d\u00f6n\u00fc\u015febiliyor. Bir noktadan sonra amac\u0131m \u201c\u00e7abuk da\u011f\u0131tay\u0131m\u201d de\u011fil, \u201chi\u00e7 kimse fark etmeden da\u011f\u0131tay\u0131m\u201d oldu. \u0130\u015fte o kap\u0131dan girince, sembolik s\u00fcr\u00fcmler, rsync, systemd ve k\u00fc\u00e7\u00fck ama etkili rit\u00fcellerle tan\u0131\u015f\u0131yorsunuz.<\/p>\n<p>Bu yaz\u0131da, bir <a href=\"https:\/\/www.dchost.com\/tr\/vps\">VPS<\/a> \u00fczerinde s\u0131f\u0131r kesinti CI\/CD\u2019yi ad\u0131m ad\u0131m kuraca\u011f\u0131z. <strong>GitHub Actions<\/strong> ya da <strong>GitLab CI<\/strong> ile kodu in\u015fa edip, <strong>rsync<\/strong> ile sunucuya ta\u015f\u0131yaca\u011f\u0131z. Sunucuda versiyonlanm\u0131\u015f klas\u00f6r yap\u0131s\u0131 kullan\u0131p <strong>sembolik ba\u011f<\/strong> ile \u201ccurrent\u201d i\u015faretini yeni s\u00fcr\u00fcme atomik \u015fekilde \u00e7evirece\u011fiz. Ve elbette i\u015fin kalbinde <strong>systemd servisleri<\/strong> olacak; servis yeniden y\u00fcklemeyle, m\u00fcmk\u00fcn olan en yumu\u015fak ge\u00e7i\u015fi sa\u011flayaca\u011f\u0131z. Arada ufak anekdotlar, pratik tarifler, bir-iki kestirme komut; hepsi beraber. Hadi ba\u015flayal\u0131m.<\/p>\n<h2 id=\"section-2\"><span id=\"Neden_Sifir_Kesinti_Hani_Su_Parmak_Izi_Gibi_Dagitimlar\">Neden S\u0131f\u0131r Kesinti? Hani \u015eu Parmak \u0130zi Gibi Da\u011f\u0131t\u0131mlar<\/span><\/h2>\n<p>\u0130\u015fin \u00f6z\u00fcnde \u015fu var: ziyaret\u00e7i say\u0131s\u0131 en sonda bile s\u0131f\u0131ra d\u00fc\u015fm\u00fcyor. Gece \u00fc\u00e7te bile birileri bir \u00fcr\u00fcn sayfas\u0131n\u0131n resmini inceliyor veya bir blog yaz\u0131s\u0131n\u0131n ortas\u0131nda kalm\u0131\u015f olabiliyor. Da\u011f\u0131t\u0131m yapt\u0131\u011f\u0131n\u0131z anda sayfalar k\u0131r\u0131lm\u0131yor olabilir ama h\u0131z d\u00fc\u015f\u00fcyor, oturumlar kopuyor, anl\u0131k bir hata g\u00f6r\u00fcnebiliyor. S\u0131f\u0131r kesinti yakla\u015f\u0131m\u0131 ise treni durdurmadan vagon de\u011fi\u015ftirmek gibi; <strong>haz\u0131rl\u0131\u011f\u0131 arka planda<\/strong> yap\u0131p, <strong>ge\u00e7i\u015fi tek harekette<\/strong> tamaml\u0131yorsunuz.<\/p>\n<p>Benim i\u00e7in d\u00f6n\u00fcm noktas\u0131, dosyalar\u0131 do\u011frudan \u201c\/var\/www\/app\u201d i\u00e7ine kopyalamay\u0131 b\u0131rak\u0131p, \u201c\/releases\/tarih-saat\u201d \u015feklindeki klas\u00f6rlere y\u00fcklemek oldu. \u00c7\u00fcnk\u00fc yeni s\u00fcr\u00fcm haz\u0131r oldu\u011funda tek bir <strong>sembolik ba\u011flant\u0131 de\u011fi\u015fimi<\/strong> ile sistemi yeni dizine y\u00f6nlendirebiliyorsunuz. Bu hareket o kadar h\u0131zl\u0131 ki, \u00fczerine kahve i\u00e7ecek kadar bile zaman kalm\u0131yor. Kopyalama, ba\u011f\u0131ml\u0131l\u0131klar\u0131n kurulmas\u0131, yap\u0131 ara\u00e7lar\u0131n\u0131n \u00e7al\u0131\u015fmas\u0131; hepsi arkada. \u00d6nde ise tek bir klik hissi.<\/p>\n<p>Bu yakla\u015f\u0131m\u0131 bir kez kurduktan sonra, ba\u015far\u0131s\u0131z da\u011f\u0131t\u0131m korkusu da azal\u0131yor. Yeni s\u00fcr\u00fcm olmam\u0131\u015fsa, eski s\u00fcr\u00fcme geri d\u00f6nmek bir <strong>ln -sfn<\/strong> komutu kadar yak\u0131n. \u00dcstelik loglar, payla\u015f\u0131lan y\u00fckleme klas\u00f6rleri, cache ve anahtar dosyalar\u0131 gibi ortak alanlar\u0131 ak\u0131ll\u0131ca d\u0131\u015far\u0131 ald\u0131\u011f\u0131n\u0131zda, hem y\u00fckseltmek hem de geri almak rahatl\u0131yor.<\/p>\n<h2 id=\"section-3\"><span id=\"Sembolik_Surum_Duzeni_releases_current_ve_sharedin_Ufak_Sirri\">Sembolik S\u00fcr\u00fcm D\u00fczeni: releases, current ve shared\u2019\u0131n Ufak S\u0131rr\u0131<\/span><\/h2>\n<p>\u0130\u015fe dizin d\u00fczeniyle ba\u015flayal\u0131m. Mesela \u201c\/var\/www\/myapp\u201d bizim k\u00f6k dizin olsun. Bunun alt\u0131nda \u201creleases\u201d, \u201cshared\u201d ve \u201ccurrent\u201d ad\u0131nda \u00fc\u00e7 yap\u0131 ta\u015f\u0131 kuraca\u011f\u0131z. \u201creleases\u201d her yeni da\u011f\u0131t\u0131mda zaman damgas\u0131na sahip bir klas\u00f6r alacak. \u201cshared\u201d de\u011fi\u015fmeyecek, ortak dosyalar i\u00e7in g\u00fcvenli alan olacak. \u201ccurrent\u201d ise her zaman canl\u0131 uygulaman\u0131n k\u00f6k\u00fc, yani as\u0131l referans noktam\u0131z.<\/p>\n<p>G\u00f6z\u00fcn\u00fczde canlans\u0131n diye bir \u00f6rnek:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/var\/www\/myapp\n  \u251c\u2500 releases\/\n  \u2502   \u251c\u2500 2025-11-07_21-04-01\/\n  \u2502   \u2514\u2500 2025-11-07_22-10-32\/\n  \u251c\u2500 shared\/\n  \u2502   \u251c\u2500 storage\/\n  \u2502   \u251c\u2500 .env\n  \u2502   \u2514\u2500 uploads\/\n  \u2514\u2500 current -&gt; \/var\/www\/myapp\/releases\/2025-11-07_22-10-32\n<\/code><\/pre>\n<p>Da\u011f\u0131t\u0131m s\u0131ras\u0131nda yeni s\u00fcr\u00fcm \u201creleases\u201d alt\u0131na y\u00fcklenir. Gerekli ba\u011flant\u0131lar \u201cshared\u201d i\u00e7indeki dosyalara kurulur (mesela \u201cstorage\u201d veya \u201cuploads\u201d gibi yaz\u0131labilir klas\u00f6rler). En sonda \u201ccurrent\u201d sembolik ba\u011f yeni s\u00fcr\u00fcme \u00e7evrilir. \u0130\u015fin s\u0131rr\u0131 burada: sembolik ba\u011f\u0131n de\u011fi\u015fmesi atomik bir i\u015flemdir ve \u201cbir an\u201dda olur. Yani canl\u0131 trafik, eski dizinden yeni dizine \u0131\u015f\u0131k h\u0131z\u0131yla ge\u00e7er.<\/p>\n<p>Ben genellikle \u201cshared\u201d alt\u0131na yap\u0131 \u00e7\u0131kt\u0131lar\u0131n\u0131 de\u011fil, yaz\u0131labilir ve da\u011f\u0131t\u0131mlar aras\u0131nda de\u011fi\u015fmeyen \u015feyleri koyar\u0131m. \u00c7evre dosyas\u0131, kullan\u0131c\u0131 y\u00fcklemeleri, log klas\u00f6r\u00fc gibi. Mesela PHP d\u00fcnyas\u0131nda \u201cstorage\u201d ve \u201c.env\u201d, Node d\u00fcnyas\u0131nda \u201c.env\u201d ve y\u00fckleme klas\u00f6rleri, statik sitelerde ise \u201cuploads\u201d ya da \u201cmedia\u201d. Bu arada PHP ve Nginx ile \u00e7al\u0131\u015fan projeler i\u00e7in <a href=\"https:\/\/www.dchost.com\/blog\/laravel-uygulamalarini-vpste-nasil-yayinlarim-nginx-php%E2%80%91fpm-horizon-ve-sifir-kesinti-dagitimin-sicacik-yol-haritasi\/\">Nginx, PHP\u2011FPM ve s\u0131f\u0131r kesinti da\u011f\u0131t\u0131m\u0131n s\u0131cac\u0131k yol haritas\u0131n\u0131<\/a> ayr\u0131 bir rehberde konu\u015fmu\u015ftuk, ona da g\u00f6z atabilirsiniz.<\/p>\n<h2 id=\"section-4\"><span id=\"CI_Tarafi_GitHub_Actions_GitLab_CI_rsync_ve_Minik_Bir_Dans\">CI Taraf\u0131: GitHub Actions \/ GitLab CI, rsync ve Minik Bir Dans<\/span><\/h2>\n<p>Gelelim in\u015fa ve payla\u015f\u0131ma. Kod depoya gelince CI sistemi build alacak, \u00e7\u0131kt\u0131y\u0131 paketleyecek ve rsync ile VPS\u2019e g\u00f6nderecek. Bu i\u015flemde iki k\u00fc\u00e7\u00fck kurala dikkat etmek i\u015finizi kolayla\u015ft\u0131r\u0131r: build\u2019i CI \u00fczerinde yap\u0131p sadece gereken dosyalar\u0131 yollamak ve rsync\u2019i \u201cidempotent\u201d davranacak \u015fekilde \u00e7a\u011f\u0131rmak. Yani \u201cbir daha \u00e7al\u0131\u015fsa da ayn\u0131 sonucu verecek\u201d tarzda.<\/p>\n<p>GitHub Actions kullan\u0131yorsan\u0131z, resmi belgeler gayet anla\u015f\u0131l\u0131r; detaylar i\u00e7in <a href=\"https:\/\/docs.github.com\/actions\" rel=\"nofollow noopener\" target=\"_blank\">GitHub Actions dok\u00fcmantasyonuna<\/a> denk getirebilirsiniz. Benim k\u00fc\u00e7\u00fck bir iskeletim \u015f\u00f6yle olmu\u015ftu:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">name: deploy\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  build-and-deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v4\n      - name: Build\n        run: |\n          npm ci --legacy-peer-deps\n          npm run build\n          # ya da composer install --no-dev --optimize-autoloader\n      - name: Pack\n        run: |\n          tar -czf release.tgz --exclude=node_modules --exclude=.git \n            dist\/ public\/ package.json .env.example scripts\/\n      - name: Upload via rsync\n        env:\n          SSH_HOST: ${{ secrets.SSH_HOST }}\n          SSH_USER: ${{ secrets.SSH_USER }}\n          SSH_KEY: ${{ secrets.SSH_KEY }}\n          APP_DIR: &quot;\/var\/www\/myapp&quot;\n          REL: &quot;$(date +&quot;%Y-%m-%d_%H-%M-%S&quot;)&quot;\n        run: |\n          echo &quot;$SSH_KEY&quot; &gt; key.pem &amp;&amp; chmod 600 key.pem\n          ssh -i key.pem -o StrictHostKeyChecking=yes $SSH_USER@$SSH_HOST &quot;mkdir -p $APP_DIR\/releases\/$REL $APP_DIR\/shared&quot;\n          rsync -az --delete-delay -e &quot;ssh -i key.pem -o StrictHostKeyChecking=yes&quot; \n            .\/ $SSH_USER@$SSH_HOST:$APP_DIR\/releases\/$REL\/\n          ssh -i key.pem -o StrictHostKeyChecking=yes $SSH_USER@$SSH_HOST \n            &quot;bash -lc 'cd $APP_DIR\/releases\/$REL &amp;&amp; ln -sfn $APP_DIR\/shared\/.env .env &amp;&amp; ln -sfn $APP_DIR\/shared\/uploads uploads'&quot;\n          ssh -i key.pem -o StrictHostKeyChecking=yes $SSH_USER@$SSH_HOST \n            &quot;ln -sfn $APP_DIR\/releases\/$REL $APP_DIR\/current &amp;&amp; sudo systemctl reload myapp.service || sudo systemctl restart myapp.service&quot;\n<\/code><\/pre>\n<p>Burada yap\u0131lan \u015fey net: yeni s\u00fcr\u00fcm klas\u00f6r\u00fc yarat\u0131l\u0131yor, dosyalar rsync ile ta\u015f\u0131n\u0131yor, shared ba\u011flant\u0131lar\u0131 yenileniyor, sonra da \u201ccurrent\u201d yeni s\u00fcr\u00fcme d\u00f6n\u00fcyor. <strong>reload<\/strong> komutu ba\u015far\u0131s\u0131z olursa kibarca <strong>restart<\/strong> deneniyor. Uygulaman\u0131z reload\u2019u destekliyorsa, ge\u00e7i\u015f genelde fark edilmez.<\/p>\n<p>GitLab taraf\u0131 da benzer. Merak edenler i\u00e7in resmi sayfa olan <a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/\" rel=\"nofollow noopener\" target=\"_blank\">GitLab CI belgeleri<\/a> rehberlik ediyor. A\u015fa\u011f\u0131daki ufak par\u00e7a da fikir versin:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">deploy:\n  stage: deploy\n  only:\n    - main\n  image: alpine:latest\n  before_script:\n    - apk add --no-cache openssh rsync bash\n  script:\n    - export REL=$(date +&quot;%Y-%m-%d_%H-%M-%S&quot;)\n    - mkdir -p ~\/.ssh &amp;&amp; echo &quot;$SSH_KEY&quot; &gt; ~\/.ssh\/id_rsa &amp;&amp; chmod 600 ~\/.ssh\/id_rsa\n    - ssh -o StrictHostKeyChecking=yes $SSH_USER@$SSH_HOST &quot;mkdir -p $APP_DIR\/releases\/$REL $APP_DIR\/shared&quot;\n    - rsync -az --delete-delay -e &quot;ssh -o StrictHostKeyChecking=yes&quot; .\/ $SSH_USER@$SSH_HOST:$APP_DIR\/releases\/$REL\/\n    - ssh $SSH_USER@$SSH_HOST &quot;bash -lc 'cd $APP_DIR\/releases\/$REL &amp;&amp; ln -sfn $APP_DIR\/shared\/.env .env &amp;&amp; ln -sfn $APP_DIR\/shared\/uploads uploads'&quot;\n    - ssh $SSH_USER@$SSH_HOST &quot;ln -sfn $APP_DIR\/releases\/$REL $APP_DIR\/current &amp;&amp; sudo systemctl reload myapp.service || sudo systemctl restart myapp.service&quot;\n<\/code><\/pre>\n<p>rsync k\u0131sm\u0131nda \u201c&#8211;delete-delay\u201d sevdi\u011fim bir detay; hedefte art\u0131k olmayan dosyalar\u0131 bir kerede temizler ve kopyalama tamamlanana dek acele etmez. \u201c-a\u201d ar\u015fiv kipidir, izin ve zaman bilgilerini g\u00fczel ta\u015f\u0131r. \u201c-z\u201d s\u0131k\u0131\u015ft\u0131rmay\u0131 a\u00e7ar, \u00f6zellikle uzak sunucuya g\u00f6nderirken faydal\u0131 olur. Bir de \u201cStrictHostKeyChecking\u201d sizi ortadaki adam risklerinden korur; bilinen anahtarlar\u0131n\u0131zla konu\u015fursunuz, kafan\u0131z rahat eder.<\/p>\n<h2 id=\"section-5\"><span id=\"systemd_ile_Nazik_Gecisler_Reload_Health_Check_ve_Atomik_Anahtar\">systemd ile Nazik Ge\u00e7i\u015fler: Reload, Health Check ve Atomik Anahtar<\/span><\/h2>\n<p>Da\u011f\u0131t\u0131m\u0131n kalbi systemd taraf\u0131. Orada servis nas\u0131l ba\u015fl\u0131yor, nas\u0131l yeniden y\u00fckleniyor, hata an\u0131nda nas\u0131l toparl\u0131yor; hepsi bir davran\u0131\u015f meselesi. Basit bir servis tan\u0131m\u0131yla ba\u015flayal\u0131m, sonra k\u00fc\u00e7\u00fck iyile\u015ftirmeler katar\u0131z.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">[Unit]\nDescription=MyApp Service\nAfter=network.target\n\n[Service]\nUser=www-data\nWorkingDirectory=\/var\/www\/myapp\/current\nExecStart=\/var\/www\/myapp\/current\/bin\/server\nExecReload=\/bin\/kill -HUP $MAINPID\nRestart=always\nRestartSec=3\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n<p>Bu dosyay\u0131 \u201c\/etc\/systemd\/system\/myapp.service\u201d i\u00e7ine koydu\u011funuzu d\u00fc\u015f\u00fcn\u00fcn. \u201cExecStart\u201d canl\u0131 dizini i\u015faret ediyor, \u00e7\u00fcnk\u00fc \u201ccurrent\u201d hep son s\u00fcr\u00fcm. \u201cExecReload\u201d kibarca s\u00fcrece bir sinyal g\u00f6nderiyor; uygulama o sinyalle ayak de\u011fi\u015ftirmeyi biliyorsa, sihir gibi. \u201cRestart=always\u201d ise gecikmeden toparlanmak i\u00e7in iyi bir a\u011f.<\/p>\n<p>\u015eimdi k\u00fc\u00e7\u00fck bir dokunu\u015f daha ekleyelim: da\u011f\u0131t\u0131m\u0131 bitirince \u201ccurrent\u201d yeni s\u00fcr\u00fcm\u00fc g\u00f6stermi\u015f olacak, ama uygulaman\u0131n haz\u0131r oldu\u011fundan emin olmak istiyoruz. Ben bazen \u201cExecStartPost\u201d yerine, <strong>symlink\u2019i \u00e7evirmeden \u00f6nce<\/strong> bir \u201chealth check\u201d bekletirim. Yani yeni s\u00fcr\u00fcm dizininde bir mini HTTP sunucusu aya\u011fa kalkt\u0131 m\u0131, \u201c\/health\u201d 200 d\u00f6nd\u00fc m\u00fc, \u00f6yleyse ge\u00e7i\u015f gelsin. Bunun i\u00e7in ufak bir betik i\u015f g\u00f6r\u00fcr:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">#!\/usr\/bin\/env bash\nset -euo pipefail\nURL=${1:-&quot;http:\/\/127.0.0.1:8080\/health&quot;}\nfor i in {1..30}; do\n  if curl -fsS &quot;$URL&quot; &gt;\/dev\/null; then\n    echo &quot;healthy&quot;; exit 0\n  fi\n  sleep 1\ndone\nexit 1\n<\/code><\/pre>\n<p>CI ad\u0131mlar\u0131n\u0131zda bu beti\u011fi yeni s\u00fcr\u00fcm dizininde \u00e7al\u0131\u015ft\u0131r\u0131r, sa\u011fl\u0131kl\u0131 sinyal ald\u0131ktan sonra \u201cln -sfn\u201d ile \u201ccurrent\u201di \u00e7evirirsiniz. B\u00f6ylece hem systemd hem uygulama ritmini bulmu\u015f olur. Nginx kullan\u0131yorsan\u0131z, onun da yeniden ba\u015flatmaya gerek kalmadan konfig\u00fcrasyonlar\u0131 nazik\u00e7e <strong>reload<\/strong> edebildi\u011fini bilirsiniz; bunun kurulumu ve daha ileri h\u0131z dokunu\u015flar\u0131 i\u00e7in <a href=\"https:\/\/www.dchost.com\/blog\/nginx-ve-cloudflareda-http-2-ve-http-3-quic-nasil-etkinlestirilir-wordpress-icin-uctan-uca-kurulum-ve-test-rehberi\/\">HTTP\/2 ve HTTP\/3\u2019\u00fc u\u00e7tan uca etkinle\u015ftirme rehberine<\/a> g\u00f6z atmak g\u00fczel olur.<\/p>\n<p>Bu arada daha teknik merakl\u0131lar\u0131 i\u00e7in, systemd\u2019nin servis birim se\u00e7enekleri d\u00fcnyas\u0131 epey geni\u015f; resmi sayfa olan <a href=\"https:\/\/www.freedesktop.org\/software\/systemd\/man\/latest\/systemd.service.html\" rel=\"nofollow noopener\" target=\"_blank\">systemd.service dok\u00fcmantasyonu<\/a> \u201cType=notify\u201d, \u201cExecStartPre\u201d gibi ayr\u0131nt\u0131lar\u0131 anla\u015f\u0131l\u0131r anlat\u0131yor. Uygulaman\u0131z haz\u0131r sinyali g\u00f6nderiyorsa \u201cnotify\u201d tipi daha da p\u00fcr\u00fczs\u00fcz bir ge\u00e7i\u015f sa\u011flar.<\/p>\n<h2 id=\"section-6\"><span id=\"Rollback_Bir_Komutla_Dunku_Huzura_Donmek\">Rollback: Bir Komutla D\u00fcnk\u00fc Huzura D\u00f6nmek<\/span><\/h2>\n<p>En sevdi\u011fim anlardan biri \u015fudur: yeni s\u00fcr\u00fcm yay\u0131nland\u0131, sorun \u00e7\u0131kt\u0131, ama panik yok. \u00c7\u00fcnk\u00fc da\u011f\u0131t\u0131m klas\u00f6r\u00fc yakla\u015f\u0131m\u0131 buna haz\u0131r. \u201creleases\u201d alt\u0131nda \u00f6nceki s\u00fcr\u00fcmler duruyor; \u201ccurrent\u201din i\u015faretini bir \u00f6nceki s\u00fcr\u00fcme \u00e7evirmek tek hareket. \u0130\u015fte o k\u00fc\u00e7\u00fck <strong>g\u00fcven<\/strong> duygusu, \u201chata yaparsam nolur\u201d korkusunu azalt\u0131yor.<\/p>\n<p>K\u00fc\u00e7\u00fck bir geri alma beti\u011fi i\u015finizi daha da pratik hale getirir. Mesela \u201c\/var\/www\/myapp\/scripts\/rollback.sh\u201d:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">#!\/usr\/bin\/env bash\nset -euo pipefail\nAPP_DIR=\/var\/www\/myapp\nPREV=$(ls -1dt $APP_DIR\/releases\/* | sed -n '2p')\nif [ -z &quot;$PREV&quot; ]; then\n  echo &quot;\u00d6nceki s\u00fcr\u00fcm bulunamad\u0131&quot;; exit 1\nfi\nln -sfn &quot;$PREV&quot; &quot;$APP_DIR\/current&quot;\nsudo systemctl reload myapp.service || sudo systemctl restart myapp.service\n<\/code><\/pre>\n<p>Bu betik, en son s\u00fcr\u00fcmden bir \u00f6ncekinin yolunu yakalay\u0131p, \u201ccurrent\u201di ona \u00e7evirir ve servisi nazik\u00e7e yeniden y\u00fckler. Elbette \u201cls\u201d s\u0131ralamas\u0131na g\u00fcvenmek yerine, da\u011f\u0131t\u0131m an\u0131nda bir \u201creleases.json\u201d ya da \u201clatest\u201d dosyas\u0131 tutmak da tercih edilebilir; ben her iki y\u00f6ntemi de farkl\u0131 projelerde kulland\u0131m, ikisi de gayet i\u015f g\u00f6r\u00fcyor.<\/p>\n<p>Geri almadan sonra veritaban\u0131 \u015femas\u0131na dikkat etmek gerekir. E\u011fer ileri s\u00fcr\u00fcmde geri d\u00f6n\u00fc\u015f\u00fc olmayan bir \u015fema de\u011fi\u015fikli\u011fi yapt\u0131ysan\u0131z, kodu geri almak yetmez. O y\u00fczden <strong>migration<\/strong> mant\u0131\u011f\u0131n\u0131 yazarken \u201cileri\u201d kadar \u201cgeri\u201dyi de hesaplamak iyi bir al\u0131\u015fkanl\u0131k. Plan\u0131 da\u011f\u0131t\u0131m an\u0131ndan \u00f6nce netle\u015ftirince, gece uykular\u0131 daha derin oluyor.<\/p>\n<h2 id=\"section-7\"><span id=\"Guvenlik_Izinler_ve_Kucuk_Parlatmalar_Dagitimin_Kolay_Unutulan_Koseleri\">G\u00fcvenlik, \u0130zinler ve K\u00fc\u00e7\u00fck Parlatmalar: Da\u011f\u0131t\u0131m\u0131n Kolay Unutulan K\u00f6\u015feleri<\/span><\/h2>\n<p>Da\u011f\u0131t\u0131m boru hatt\u0131n\u0131 kurarken gizli anahtarlar\u0131n ve eri\u015fim bilgilerinin nas\u0131l sakland\u0131\u011f\u0131 \u00f6nemli. CI taraf\u0131nda \u201csecrets\u201d alanlar\u0131n\u0131 kullan\u0131p, kod deposuna \u015fifreli bile olsa kimlik koymamay\u0131 tercih ediyorum. Sunucu taraf\u0131nda da\u011f\u0131t\u0131m i\u00e7in ayr\u0131 bir kullan\u0131c\u0131 a\u00e7\u0131p, \u201csudo\u201d yetkisini sadece gerekli komutlarla s\u0131n\u0131rlamak iyi bir pratik. SSH\u2019de anahtar do\u011frulamay\u0131 zorunlu k\u0131lmak, \u201cknown_hosts\u201d ile sunucunun parmak izini sabitlemek, hatta gerekiyorsa \u201cForceCommand\u201d ile yaln\u0131zca belirli betiklere izin vermek i\u015finizi sa\u011flamla\u015ft\u0131r\u0131r.<\/p>\n<p>Dosya izinleri de sessiz hatalar\u0131n kayna\u011f\u0131 olabiliyor. Yaz\u0131labilir klas\u00f6rleri \u201cshared\u201d alt\u0131nda toplamak, \u201cwww-data\u201d ya da kulland\u0131\u011f\u0131n\u0131z servis kullan\u0131c\u0131s\u0131na sahipli\u011fini vermek ve <strong>yaln\u0131zca gerekli minimum izinleri<\/strong> atamak kula\u011fa s\u0131k\u0131c\u0131 gelse de \u00e7ok i\u015f kurtar\u0131r. rsync ile \u201c-a\u201d parametresi izinleri ta\u015f\u0131maya yard\u0131mc\u0131 olur, ama gerekirse hedefte \u201cchown\u201d ve \u201cchmod\u201d ile ince ayar yap\u0131n.<\/p>\n<p>Yedekleme taraf\u0131n\u0131 da da\u011f\u0131t\u0131mdan koparm\u0131yorum. Bir s\u00fcr\u00fcm yanl\u0131\u015f giderse kodu geri al\u0131yorsunuz; peki ya veri? Yedeklerinizi hem yerel hem uzak tutmak, s\u00fcr\u00fcmlendirmek ve gerekti\u011finde geri y\u00fcklemeyi prova etmek \u00f6nemli. Bunu ak\u0131c\u0131 bi\u00e7imde ele ald\u0131\u011f\u0131m\u0131z <a href=\"https:\/\/www.dchost.com\/blog\/restic-ve-borg-ile-s3-uyumlu-uzak-yedekleme-surumleme-sifreleme-ve-saklama-ne-zaman-nasil\/\">Restic ve Borg ile S3 uyumlu uzak yedekleme rehberi<\/a> tam burada i\u015f g\u00f6r\u00fcyor. Kodla veri birbirini kollad\u0131\u011f\u0131nda da\u011f\u0131t\u0131m daha cesur hale geliyor.<\/p>\n<p>Performans taraf\u0131nda, \u00f6nbellekleri da\u011f\u0131t\u0131mla birlikte nazik\u00e7e temizlemek g\u00fczel olur. Edge taraf\u0131nda CDN varsa \u201cinvalidation\u201d yapmak, uygulama taraf\u0131nda ise yaln\u0131zca de\u011fi\u015fen anahtarlar\u0131 temizlemek ak\u0131ll\u0131ca. WordPress gibi s\u0131k ziyaret edilen sistemlerde medya ve statik dosya trafi\u011fini d\u0131\u015far\u0131 ta\u015f\u0131mak isterseniz, <a href=\"https:\/\/www.dchost.com\/blog\/wordpress-medyani-s3e-tasiyalim-mi-cdn-imzali-url-ve-onbellek-gecersizlestirme-adim-adim\/\">medyay\u0131 S3\u2019e ta\u015f\u0131ma ve imzal\u0131 URL\u2019lerle \u00f6nbellek ge\u00e7ersizle\u015ftirme<\/a> hakk\u0131nda anlatt\u0131klar\u0131m ho\u015funuza gidebilir. Trafi\u011fi CDN\u2019e verdik\u00e7e da\u011f\u0131t\u0131mlar sahne arkas\u0131nda daha da g\u00f6r\u00fcnmez olur.<\/p>\n<p>Son olarak, da\u011f\u0131t\u0131m s\u00fcrecinden hemen sonra g\u00f6z\u00fcn\u00fcz\u00fc kula\u011f\u0131n\u0131z\u0131 a\u00e7an k\u00fc\u00e7\u00fck izleme kancalar\u0131 kurun. Birka\u00e7 dakika boyunca hata oran\u0131n\u0131, CPU ve bellek de\u011fi\u015fimini, tepkime s\u00fcrelerini izlemek al\u0131\u015fkanl\u0131k olmal\u0131. Bunun i\u00e7in <a href=\"https:\/\/www.dchost.com\/blog\/vps-izleme-ve-alarm-kurulumu-prometheus-grafana-ve-uptime-kuma-ile-baslangic\/\">Prometheus, Grafana ve Uptime Kuma ile izleme ve alarm kurulumuna ba\u015flang\u0131\u00e7 rehberi<\/a> g\u00fczel bir e\u015flik\u00e7i. Canl\u0131y\u0131 izlerken da\u011f\u0131t\u0131mlar\u0131n\u0131z\u0131n asl\u0131nda ne kadar g\u00f6r\u00fcnmez oldu\u011funu bizzat g\u00f6r\u00fcrs\u00fcn\u00fcz.<\/p>\n<h2 id=\"section-8\"><span id=\"Dagitim_Betikleri_Kucuk_Dokunuslar_Buyuk_Huzurlar\">Da\u011f\u0131t\u0131m Betikleri: K\u00fc\u00e7\u00fck Dokunu\u015flar B\u00fcy\u00fck Huzurlar<\/span><\/h2>\n<p>Bir s\u00fcre sonra CI yaml\u2019\u0131n\u0131z\u0131n \u015fi\u015fti\u011fini hissedebilirsiniz. Ben \u00e7o\u011fu zaman VPS \u00fczerinde k\u00fc\u00e7\u00fck betikler tutuyorum. \u201cscripts\u201d klas\u00f6r\u00fcnde \u201cactivate.sh\u201d, \u201ccleanup.sh\u201d, \u201chealthcheck.sh\u201d gibi. CI taraf\u0131 bu betikleri uzaktan \u00e7a\u011f\u0131r\u0131yor, g\u00fcnl\u00fck i\u015f orada d\u00f6n\u00fcyor. B\u00f6ylece CI dosyas\u0131 k\u0131sa kal\u0131yor, sunucu taraf\u0131nda tekrar kullan\u0131labilir ufak bir k\u00fct\u00fcphane olu\u015fuyor.<\/p>\n<p>\u00d6rne\u011fin \u201cactivate.sh\u201d \u015f\u00f6yle olabilir:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">#!\/usr\/bin\/env bash\nset -euo pipefail\nAPP_DIR=\/var\/www\/myapp\nREL=${1:?&quot;release dizini gerekli&quot;}\n# payla\u015f\u0131lanlar\ncd &quot;$APP_DIR\/releases\/$REL&quot;\nln -sfn &quot;$APP_DIR\/shared\/.env&quot; .env\nln -sfn &quot;$APP_DIR\/shared\/uploads&quot; uploads\n# sa\u011fl\u0131k kontrol\u00fc (opsiyonel)\n&quot;$APP_DIR\/scripts\/healthcheck.sh&quot; &quot;http:\/\/127.0.0.1:8080\/health&quot;\n# atomik ge\u00e7i\u015f\nln -sfn &quot;$APP_DIR\/releases\/$REL&quot; &quot;$APP_DIR\/current&quot;\nsudo systemctl reload myapp.service || sudo systemctl restart myapp.service\n<\/code><\/pre>\n<p>\u201ccleanup.sh\u201d ise gereksiz b\u00fcy\u00fcmeyi \u00f6nler. Eski s\u00fcr\u00fcmler bir noktada disk \u015fi\u015firmeye ba\u015flayabilir. Basit bir \u201cen son 5 s\u00fcr\u00fcm\u00fc tut\u201d yakla\u015f\u0131m\u0131 i\u015f g\u00f6r\u00fcr. Ben genelde log d\u00f6nd\u00fcrme ve yedekleme politikas\u0131yla uyumlu gidiyorum. \u00d6zetle, her da\u011f\u0131t\u0131mdan sonra k\u00fc\u00e7\u00fck bir bahar temizli\u011fi.<\/p>\n<p>Bir not da network i\u00e7in: rsync baz\u0131 ortamlarda SSH \u00fczerinden bekledi\u011finizden yava\u015f olabilir. Bu durumda s\u0131k\u0131\u015ft\u0131rma seviyesini d\u00fc\u015f\u00fcrmek, gereksiz dosyalar\u0131 paket d\u0131\u015f\u0131 b\u0131rakmak ve m\u00fcmk\u00fcnse build \u00e7\u0131kt\u0131lar\u0131n\u0131 minimal hale getirmek etkili. Kimi projelerde \u201cdist\u201d klas\u00f6r\u00fcn\u00fc tek ar\u015five al\u0131p rsync yerine \u201cscp\u201d ile g\u00f6nderdikten sonra sunucuda a\u00e7mak bile daha h\u0131zl\u0131 sonu\u00e7 verebiliyor. Ama rsync\u2019in <strong>delta<\/strong> aktar\u0131m kabiliyeti de\u011fi\u015fmeyen dosyalarda b\u00fcy\u00fck kazan\u00e7 sa\u011fl\u0131yor; bence varsay\u0131lan denemeye de\u011fer.<\/p>\n<h2 id=\"section-9\"><span id=\"CICDyi_Takvime_Baglamak_Oto_Dagitim_mi_Elle_Onay_mi\">CI\/CD\u2019yi Takvime Ba\u011flamak: Oto Da\u011f\u0131t\u0131m m\u0131, Elle Onay m\u0131?<\/span><\/h2>\n<p>Bir ba\u015fka tatl\u0131 karar noktas\u0131 \u015fu: her \u201cmain\u201d push\u2019unda otomatik da\u011f\u0131t\u0131m m\u0131 olsun, yoksa bir onay ad\u0131m\u0131 m\u0131 girsin? K\u00fc\u00e7\u00fck ekiplerde otomatik ak\u0131\u015f i\u015fi h\u0131zland\u0131r\u0131yor. B\u00fcy\u00fck ekiplerde ya da yo\u011fun trafi\u011fin oldu\u011fu projelerde, \u201cmanual\u201d onay veya \u201cscheduled\u201d da\u011f\u0131t\u0131mlar daha huzurlu. GitHub Actions\u2019ta \u201cworkflow_dispatch\u201d ile elle tetikleme, GitLab\u2019ta \u201cwhen: manual\u201d ve \u201cenvironments\u201d \u00f6zellikleri tatl\u0131 bir denge kuruyor. Tart\u0131, ekibin ritmine g\u00f6re de\u011fi\u015fiyor.<\/p>\n<p>Canl\u0131ya \u00e7\u0131kmadan \u00f6nce staging ortam\u0131 kurmak ve ayn\u0131 d\u00fczeni orada da uygulamak ayr\u0131 bir ferahl\u0131k. Bir iki ger\u00e7ek kullan\u0131c\u0131 davran\u0131\u015f\u0131n\u0131 taklit eden test, g\u00f6zden ka\u00e7an ufak k\u00f6\u015feleri ortaya \u00e7\u0131kar\u0131r. Bazen tek bir \u201ccache-control\u201d ba\u015fl\u0131\u011f\u0131 ya da \u201cgzip\/brotli\u201d ayar\u0131 bile etkileyici fark yarat\u0131yor; bu konuda web katman\u0131n\u0131 incelerken ele ald\u0131\u011f\u0131m\u0131z rehberler keyifli vakit ge\u00e7irtiyor.<\/p>\n<h2 id=\"section-10\"><span id=\"Kapanis_Sessiz_Dagitimlarin_Rahat_Uykusu\">Kapan\u0131\u015f: Sessiz Da\u011f\u0131t\u0131mlar\u0131n Rahat Uykusu<\/span><\/h2>\n<p>Toparlayal\u0131m. S\u0131f\u0131r kesinti da\u011f\u0131t\u0131m, sihirli bir kutu de\u011fil; birka\u00e7 iyi fikrin k\u00fc\u00e7\u00fck, g\u00fcvenilir ad\u0131mlarla birle\u015fmi\u015f h\u00e2li. <strong>releases\/current\/shared<\/strong> d\u00fczeni dosya taraf\u0131n\u0131 sadele\u015ftiriyor. <strong>rsync<\/strong> ile dosyalar\u0131 g\u00fcvenli, h\u0131zl\u0131 ve tekrarlanabilir bi\u00e7imde ta\u015f\u0131yorsunuz. <strong>systemd<\/strong> servisleriyle nazik bir reload ya da kontroll\u00fc bir restart, yeni s\u00fcr\u00fcme \u0131\u015f\u0131k h\u0131z\u0131nda ge\u00e7i\u015f sa\u011fl\u0131yor. Geri alma bir komut, izleme birka\u00e7 grafik, yedekleme ise i\u00e7 huzur.<\/p>\n<p>Buradan sonras\u0131 pratik ve ritim. K\u00fc\u00e7\u00fck ba\u015flay\u0131n, \u00f6nce staging\u2019de deneyin, sonra canl\u0131ya ta\u015f\u0131y\u0131n. Betikleri ufalt\u0131n, tekrar eden i\u015fleri sunucuya yerle\u015ftirin, CI dosyas\u0131n\u0131 basit tutun. Ba\u011f\u0131ml\u0131l\u0131klar\u0131 build a\u015famas\u0131nda \u00e7\u00f6z\u00fcn, canl\u0131da sadece \u00e7al\u0131\u015ft\u0131r\u0131n. Sorun oldu\u011funda geri d\u00f6nmekten \u00e7ekinmeyin; her geri alma asl\u0131nda ileri do\u011fru bir \u00e7entik b\u0131rak\u0131r. Dilerseniz bu ak\u0131\u015f\u0131 g\u00fc\u00e7lendirmek i\u00e7in <a href=\"https:\/\/docs.github.com\/actions\" rel=\"nofollow noopener\" target=\"_blank\">GitHub Actions\u2019\u0131n<\/a> ayr\u0131nt\u0131lar\u0131n\u0131 ve <a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/\" rel=\"nofollow noopener\" target=\"_blank\">GitLab CI\u2019nin<\/a> ortam y\u00f6netimi \u00f6zelliklerini kurcalay\u0131n; k\u00fc\u00e7\u00fck detaylar b\u00fcy\u00fck konfor getiriyor.<\/p>\n<p>Umar\u0131m bu yolculuk size cesaret vermi\u015ftir. Bir ak\u015fam bir g\u00fcncelleme daha atarken, kahveniz so\u011fumadan da\u011f\u0131t\u0131m\u0131n bitti\u011fini g\u00f6rmek kadar keyifli az \u015fey var. Sorular\u0131n\u0131z olursa yaz\u0131n, birlikte bakar\u0131z. Bir dahaki yaz\u0131da belki Nginx katman\u0131nda ba\u015fka ufak h\u0131z hilelerini konu\u015furuz; o zamana kadar temiz da\u011f\u0131t\u0131mlar, sessiz ge\u00e7i\u015fler, huzurlu geceler.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>\u0130&ccedil;indekiler1 Giri\u015f: Bir Gecenin Sessizli\u011finde Da\u011f\u0131t\u0131m Panikleri2 Neden S\u0131f\u0131r Kesinti? Hani \u015eu Parmak \u0130zi Gibi Da\u011f\u0131t\u0131mlar3 Sembolik S\u00fcr\u00fcm D\u00fczeni: releases, current ve shared\u2019\u0131n Ufak S\u0131rr\u01314 CI Taraf\u0131: GitHub Actions \/ GitLab CI, rsync ve Minik Bir Dans5 systemd ile Nazik Ge\u00e7i\u015fler: Reload, Health Check ve Atomik Anahtar6 Rollback: Bir Komutla D\u00fcnk\u00fc Huzura D\u00f6nmek7 G\u00fcvenlik, \u0130zinler [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1481,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1480","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/1480","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/comments?post=1480"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/1480\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media\/1481"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media?parent=1480"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/categories?post=1480"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/tags?post=1480"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}