{"id":15430350,"url":"https://github.com/davidjenni/ghost-azure-cd","last_synced_at":"2026-05-13T21:35:42.149Z","repository":{"id":151388485,"uuid":"137848908","full_name":"davidjenni/ghost-azure-CD","owner":"davidjenni","description":"Ghost CMS hosted on an Azure WebApp, enabled for automated and continuous deployment.","archived":false,"fork":false,"pushed_at":"2019-11-10T06:14:55.000Z","size":60,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2024-10-18T05:57:46.817Z","etag":null,"topics":["azure","azure-webapp","continuous-deployment","ghost-blog","ghost-cms"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davidjenni.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-19T06:23:11.000Z","updated_at":"2023-09-06T15:36:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"4e376808-d7ae-42f5-ba9d-c04a922cbe13","html_url":"https://github.com/davidjenni/ghost-azure-CD","commit_stats":{"total_commits":31,"total_committers":1,"mean_commits":31.0,"dds":0.0,"last_synced_commit":"96d085b75662bc82045be3fed7d66dd832542f94"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/davidjenni/ghost-azure-CD","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidjenni%2Fghost-azure-CD","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidjenni%2Fghost-azure-CD/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidjenni%2Fghost-azure-CD/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidjenni%2Fghost-azure-CD/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davidjenni","download_url":"https://codeload.github.com/davidjenni/ghost-azure-CD/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidjenni%2Fghost-azure-CD/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33001284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","azure-webapp","continuous-deployment","ghost-blog","ghost-cms"],"created_at":"2024-10-01T18:15:27.966Z","updated_at":"2026-05-13T21:35:42.134Z","avatar_url":"https://github.com/davidjenni.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ghost CMS running as Azure Web App\n\nAutomation for initial and continuous deployment of ghost CMS within a Azure WebApp (aka AppService).\n\n## Motivation\n\nWhy yet another \"ghost on Azure\" repo? Most of the existing examples are pretty good to get a\nghost blob up and running. But they all suffer from shortcomings by being too manual and hard to update.\nThis implementation tries to improve on that:\n\n- Once the WebApp is setup for [Continuous Deployment (CD)](https://docs.microsoft.com/en-us/azure/app-service/app-service-continuous-deployment),\npushing to the repo will trigger the initial deployment from this repo.\n- Site specific content is kept in a separate folder next to the ghost app itself.\nThis makes updates to newer ghost releases safer.\n- The deployment script doesn't depend on a ghost release checked in to this repo.\nInstead, it pulls the ghost zip file from ghost's official drop point on their github\n- Re-deployments are idempotent, i.e. the existing blog/site specific files and database are not clobbered.\n\n## Installation\n\n- clone this repo\n- create an Azure WebApp with a Windows VM AppService plan (a free F1 or ~$10 p/m D1 size will do for smaller sites) **TODO**: to be automated soon\n- in the Azure portal, setup [Continuous Deployment](https://docs.microsoft.com/en-us/azure/app-service/app-service-continuous-deployment) **TODO**: to be automated soon\n- site is deployed and a ghost DB is initialized\n- navigate to your new blog: https://mynewblog.azurewebsites.com\n- configure your blog at the admin pages:  https://mynewblog.azurewebsites.com/ghost\n- make any configuration changes in your repo, and push to origin -\u003e triggers a re-deployment\n\n## Why not ghost-cli?\n\nSince ghost v1.x, the officially recommended deployment is [Ghost CLI](https://docs.ghost.org/docs/ghost-cli).\nIt does nicely address the re-deployment and separation concerns mentioned above.\nBut the Ghost CLI (although runnable on Windows), does not play well on Windows since it is currently built with\nseveral Linux/macOS assumptions (e.g. systemd as nodejs runner).\n\nThis repo is using a similar structure, separating the site-specific content (images, database, themes) from the actual\nghost server code. This makes updating to newer ghost release straightforward and safe.\n\n## General design and approach\n\nScripts and flows need to be idempotent: are used to initialize with no resources up,\nbut can also be used to run ghost updates or roll secrets. In the latter scenario,\nghost bits under app are swapped out, but the site-specific content under mycontent\nwill remain untouched.\n\n### deploy script called inside WebApp node\n\n- call yarn to determine latest release ghost package: yarn info ghost dist-tags.latest\n- download release zip from ghost's github:\n    https://github.com/TryGhost/Ghost/releases/download/$latestVersion/Ghost-$latestVersion.zip\n- unzip it into 'app' folder\n- install ghost's dependencies with: yarn install --prod --non-interactive --no-progress --cwd app\n- populate 'mycontent' folder with its data, images, logs, settings, themes subfolders required by ghost\n- copy over default theme 'casper' to mycontent/themes\n- finalize config.production.json settings, e.g. abs path for contentPath or port; inject secrets from KeyVault\n- ensure/create sqlite3 ghost db\n- install ghost storage extension for azure blob storage\n\n### Azure resources (**TODO**)\n\nUsing ARM template files:\n\n- create resources like storage account, server farm (AppServicePlan)\n- create KeyVault for mailgun api key/secrets and blob storage keys/SAS token\n- create Web App with AppInsights\n- create CDN with custom domain in front of web app url, add TLS termination\n- create WebJobs to run DB backups and blob storage backups\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidjenni%2Fghost-azure-cd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavidjenni%2Fghost-azure-cd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidjenni%2Fghost-azure-cd/lists"}