{"id":397355,"date":"2022-01-21T21:17:46","date_gmt":"2022-01-21T18:17:46","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/"},"modified":"2022-01-21T21:17:46","modified_gmt":"2022-01-21T18:17:46","slug":"how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/","title":{"rendered":"#How to Deploy a Ghost Blog With Docker \u2013 CloudSavvy IT"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a2dae421d82b\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #dd3333;color:#dd3333\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #dd3333;color:#dd3333\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a2dae421d82b\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Starting_a_Ghost_Container\" >Starting a Ghost Container<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Configuring_Ghost\" >Configuring Ghost<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Using_an_External_Database\" >Using an External Database<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Proxying_Traffic_to_Your_Container\" >Proxying Traffic to Your Container<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Managing_Ghost_Updates\" >Managing Ghost Updates<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Using_ghost-cli\" >Using ghost-cli<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-deploy-a-ghost-blog-with-docker-cloudsavvy-it\/#Summary\" >Summary<\/a><\/li><\/ul><\/nav><\/div>\n<p><strong>&#8220;#How to Deploy a Ghost Blog With Docker \u2013 CloudSavvy IT&#8221;<\/strong><\/p>\n<div id=\"article-content-area\">\n<img loading=\"lazy\" decoding=\"async\" class=\"type:primaryImage aligncenter size-full wp-image-15270\" data-pagespeed-lazy-srcset=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/4d531b9d.jpg?width=398&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1 400w, https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/4d531b9d.jpg?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1 1200w\" sizes=\"auto, 400w, 1200w\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/4d531b9d.jpg?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"Logo of the Ghost content creation platform\" width=\"1202\" height=\"677\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p><a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\">Ghost<\/a> is a popular content creation platform that\u2019s written in Java<a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">Script<\/a> with Node.js. The open-source software comes with everything you need to author, theme, publish, and maintain your own blog.<\/p>\n<p>Ghost is open-source software supported by the official Ghost(Pro) hosted service. You can install it on your own server by adding Node.js and <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/github.com\/tryghost\/ghost#quickstart-install\">using the Ghost CLI<\/a> to set up your stack. Ghost is also available as a <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/hub.docker.com\/_\/ghost\">Docker image<\/a> which bundles all the dependencies for you.<\/p>\n<p>In this guide, we\u2019ll use Docker to quickly get a new Ghost blog operational. Install Docker and Docker Compose on your host before proceeding any further. While you can deploy Ghost using Docker alone, Compose makes it simpler to supply and manage the config values your site will need to get started.<\/p>\n<h2 id=\"starting-a-ghost-container\"><span class=\"ez-toc-section\" id=\"Starting_a_Ghost_Container\"><\/span>Starting a Ghost Container<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>You can start a basic Ghost site with a single Docker command:<\/p>\n<pre>docker run -d -p 2368:2368 --name simple-ghost ghost:4<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-15276\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/6ff8a65b.png?trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"1280\" height=\"648\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>This will bring up Ghost on its default port of 2368. Visit <code>http:\/\/localhost:2368<\/code> to view your site or <code>http:\/\/localhost:2368\/ghost<\/code> to access the Ghost admin panel. You\u2019ll need to supply some first-run settings to finalize your Ghost installation and create an initial user account.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-15277\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/5d8ee29c.png?trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"1280\" height=\"648\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>This approach is great for quick experimentation if you\u2019re just trying out Ghost. However, we haven\u2019t set up persistent storage yet so your data will be lost when the container stops.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-15278\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/715a9ea7.png?trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"1280\" height=\"648\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>Here\u2019s a more complete example that uses Docker Compose to set up Ghost with a Docker volume. Mount a volume to the <code>\/var\/lib\/ghost\/content<\/code> directory to store Ghost\u2019s data outside the container.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"yaml\">\n<pre class=\"de1\"><span class=\"co3\">version<\/span><span class=\"sy2\">: <\/span><span class=\"st0\">\"3\"<\/span><span class=\"co4\">\nservices<\/span>:<span class=\"co4\">\n  ghost<\/span>:<span class=\"co3\">\n    image<\/span><span class=\"sy2\">: <\/span>ghost:4<span class=\"co4\">\n    ports<\/span><span class=\"sy2\">:\n<\/span>      - 8080:2368<span class=\"co4\">\n    environment<\/span>:<span class=\"co3\">\n      url<\/span><span class=\"sy2\">: <\/span>https:\/\/ghost.example.com<span class=\"co4\">\n    volumes<\/span><span class=\"sy2\">:\n<\/span>      - ghost:\/var\/lib\/ghost\/content<span class=\"co3\">\n    restart<\/span><span class=\"sy2\">: <\/span>unless-stopped<span class=\"co4\">\nvolumes<\/span><span class=\"sy2\">:\n<\/span>  ghost:<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>This Compose file exhibits a few other changes to the container\u2019s configuration. Port 2368 that\u2019s exposed by the container is mapped to port 8080 on your host, letting you use <code>localhost:8080<\/code> to access Ghost. The restart policy is changed to <code>unless-stopped<\/code> to ensure your site comes up automatically after your host reboots.<\/p>\n<p>Now use Compose to bring up your site:<\/p>\n<pre>docker-compose up -d<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-15279\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/a5df345f.png?trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"765\" height=\"157\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<h3 id=\"configuring-ghost\"><span class=\"ez-toc-section\" id=\"Configuring_Ghost\"><\/span>Configuring Ghost<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Ghost supports <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/config\/#running-ghost-with-config-env-variables\">several configuration parameters<\/a> to customize its operation and set up your site. When you\u2019re using Docker, you can supply these values as environment variables.<\/p>\n<p>Ghost\u2019s config files use nested JSON objects to store values. You can convert JSON keys to their environment variable counterparts by replacing each tree level with <code>__<\/code> (double underscore) characters:<\/p>\n<pre># in a JSON config file&#13;\n{&#13;\n    \"mail\": {&#13;\n        \"transport\": \"SMTP\"&#13;\n    }&#13;\n}&#13;\n&#13;\n# as an environment variable&#13;\nmail__transport=SMTP<\/pre>\n<p>Use the <code>environment<\/code> field in your <code>docker-compose.yml<\/code> file to supply these parameters to your Ghost container:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"yaml\">\n<pre class=\"de1\"><span class=\"co3\">version<\/span><span class=\"sy2\">: <\/span><span class=\"st0\">\"3\"<\/span><span class=\"co4\">\nservices<\/span>:<span class=\"co4\">\n  ghost<\/span>:<span class=\"co4\">\n    environment<\/span>:<span class=\"co3\">\n      mail__transport<\/span><span class=\"sy2\">: <\/span>SMTP<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Refer to the <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/config\">Ghost documentation<\/a> for an exhaustive list of supported options. You can set up a mail system, use a <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/config\/#admin-url\">separate URL<\/a> to access the admin panel, <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/config\/#paths\">override directory paths<\/a> and toggle <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/config\/#privacy\">privacy options<\/a> via the available environment variables.<\/p>\n<p>The <code>url<\/code> option is particularly important as it\u2019s required for live production sites. This defines the URL which external visitors will use to access your site. Set this to your site\u2019s domain name in your <code>docker-compose.yml<\/code>:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"yaml\">\n<pre class=\"de1\"><span class=\"co4\">environment<\/span>:<span class=\"co3\">\n  url<\/span><span class=\"sy2\">: <\/span>https:\/\/ghost.example.com<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h2 id=\"using-an-external-database\"><span class=\"ez-toc-section\" id=\"Using_an_External_Database\"><\/span>Using an External Database<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Ghost defaults to using a SQLite database that\u2019s stored as a file in your site\u2019s content directory. It\u2019ll be persisted as part of the Docker volume created above. You can <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/config\/#database\">use an external<\/a> MySQL database instead by supplying connection details via <code>database<\/code>-prefixed environment variables:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"yaml\">\n<pre class=\"de1\"><span class=\"co4\">services<\/span>:<span class=\"co4\">\n  ghost<\/span><span class=\"sy2\">:\n<\/span>    <span class=\"co1\"># ...<\/span><span class=\"co4\">\n    environment<\/span>:<span class=\"co3\">\n      database__client<\/span><span class=\"sy2\">: <\/span>mysql<span class=\"co3\">\n      database__connection__host<\/span><span class=\"sy2\">: <\/span>ghost_mysql<span class=\"co3\">\n      database__connection__user<\/span><span class=\"sy2\">: <\/span>root<span class=\"co3\">\n      database__connection__password<\/span><span class=\"sy2\">: <\/span>databasePw<span class=\"co3\">\n      database__connection__database<\/span><span class=\"sy2\">: <\/span>ghost\n<span class=\"co4\">\n  ghost_mysql<\/span>:<span class=\"co3\">\n    image<\/span><span class=\"sy2\">: <\/span>mysql:5.7<span class=\"co4\">\n    expose<\/span><span class=\"sy2\">:\n<\/span>      - 3306<span class=\"co4\">\n    environment<\/span>:<span class=\"co3\">\n      MYSQL_DATABASE<\/span><span class=\"sy2\">: <\/span>ghost<span class=\"co3\">\n      MYSQL_ROOT_PASSWORD<\/span><span class=\"sy2\">: <\/span>databasePw<span class=\"co4\">\n    volumes<\/span><span class=\"sy2\">:\n<\/span>      - mysql:\/var\/lib\/mysql<span class=\"co3\">\n    restart<\/span><span class=\"sy2\">: <\/span>unless-stopped\n<span class=\"co4\">\nvolumes<\/span><span class=\"sy2\">:\n<\/span>  mysql:<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>This Compose file includes another service that runs MySQL in an additional container. Environment variables are set on the Ghost service to supply the MySQL connection details. A separate <code>mysql<\/code> volume is created to persist the database storage files.<\/p>\n<p>Compose automatically links services into a Docker network. Ghost can reach the <code>ghost_mysql<\/code> container by using the service name as a hostname. If you want to use an existing non-Dockerized MySQL database, you can remove the <code>ghost_mysql<\/code> service definition and supply your MySQL server\u2019s IP address, database schema name, and user credentials instead.<\/p>\n<h2 id=\"proxying-traffic-to-your-container\"><span class=\"ez-toc-section\" id=\"Proxying_Traffic_to_Your_Container\"><\/span>Proxying Traffic to Your Container<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Now your Ghost site should be operational but it\u2019s still exposed on port 8080. If you won\u2019t be running anything else on your host, you could bind port 80 or 443 instead to make it directly accessible via your server\u2019s domain name. In other situations, use a reverse proxy such as NGINX to forward traffic from the web to your Ghost container.<\/p>\n<p>Add NGINX to your host:<\/p>\n<pre>sudo apt update&#13;\nsudo apt install nginx&#13;\n&#13;\n# Allow HTTP\/HTTPS traffic through the firewall&#13;\nsudo ufw allow 80&#13;\nsudo ufw allow 443<\/pre>\n<p>Define an NGINX host for your site in <code>\/etc\/nginx\/sites-available\/ghost.example.com<\/code>:<\/p>\n<pre>server {&#13;\n    &#13;\n    server_name ghost.example.com;&#13;\n    index index.html;&#13;\n&#13;\n    access_log \/var\/log\/nginx\/ghost_access.log&#13;\n    error_log \/var\/log\/nginx\/ghost_error.log error;&#13;\n&#13;\n    location \/ {&#13;\n        proxy_pass http:\/\/127.0.0.1:8080;&#13;\n        proxy_redirect off;&#13;\n        proxy_set_header Host $http_host;&#13;\n        proxy_set_header X-Original-IP $remote_addr;&#13;\n    }&#13;\n&#13;\n}<\/pre>\n<p>This file configures NGINX to forward traffic to <code>ghost.example.com<\/code> through to port 8080 on <code>localhost<\/code>, which was previously bound to your Ghost container. Enable the new config file by linking it into NGINX\u2019s <code>sites-enabled<\/code> directory:<\/p>\n<pre>sudo ln -s \/etc\/nginx\/sites-available\/ghost.example.com \/etc\/nginx\/sites-enabled\/ghost.example.com<\/pre>\n<p>Restart NGINX to apply your changes:<\/p>\n<pre>sudo service nginx restart<\/pre>\n<p>Now you can set up SSL with the free Let\u2019s Encrypt service. Add Let\u2019s Encrypt\u2019s Certbot to automate certificate issuance and renewal:<\/p>\n<pre>sudo apt install certbot<\/pre>\n<p>Use Certbot to obtain certificates for your NGINX site:<\/p>\n<pre>sudo certbot --nginx<\/pre>\n<p>Certbot will read your NGINX sites and generate certificates for their <code>server_name<\/code> config fields. It\u2019ll automatically reconfigure NGINX to serve the certificate with your site. You should now be able to access your Ghost blog by visiting your domain name over HTTPS.<\/p>\n<p>While we\u2019ve focused on NGINX in this article, there are other options for proxying web traffic through to your Ghost container. Traefik is a leading contender that\u2019s got first-class support for Docker. Deploying a Traefik instance would let you configure routing and automatic SSL via Docker labels you\u2019d set on your Ghost container.<\/p>\n<h2 id=\"managing-ghost-updates\"><span class=\"ez-toc-section\" id=\"Managing_Ghost_Updates\"><\/span>Managing Ghost Updates<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>You can update Ghost by replacing your site\u2019s Docker container with a new one running an updated version of the Ghost image. As your site\u2019s content is safely stored in a separate Docker volume, it\u2019ll be retained when the volume is reattached to the new container.<\/p>\n<p>If you\u2019re tagging a major image version in your <code>docker-compose.yml<\/code>, such as <code>ghost:4<\/code>, you can update to the latest minor release by running <code>docker-compose up<\/code> with the <code>--pull<\/code> flag:<\/p>\n<pre>docker-compose up -d --pull<\/pre>\n<p>This instructs Compose to check for changes in the image tag and pull an updated version when available. It\u2019ll replace your containers with new instances using the latest image version that matches the tag.<\/p>\n<p>When you want to change the tag you\u2019re using, update the <code>image<\/code> reference in your <code>docker-compose.yml<\/code> file. Repeat <code>docker-compose up -d<\/code> to pull the image and start new containers. As an example, if Ghost v5 releases in the future, you could change your <code>docker-compose.yml<\/code> to <code>image: ghost:5<\/code> to move to the new major version.<\/p>\n<p>Docker makes it easy to obtain Ghost updates by pulling the latest image and replacing your containers. Nonetheless you should still pay attention to the changes you\u2019re applying. Consult the <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/changelog\">Ghost changelog<\/a> before taking a major upgrade in case you need to take extra steps to complete the migration.<\/p>\n<h2 id=\"using-ghost-cli\"><span class=\"ez-toc-section\" id=\"Using_ghost-cli\"><\/span>Using ghost-cli<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/ghost-cli\"><code>ghost-cli<\/code><\/a> is available within the Ghost Docker image. This utility is used to set up and maintain Ghost when it\u2019s installed in traditional non-containerized environments.<\/p>\n<p>You can access <code>ghost-cli<\/code> through Docker by using the <code>ghost<\/code> command with <code>docker exec<\/code>. Here\u2019s an example that uses the <code>version<\/code> sub-command to reveal the Ghost release you\u2019re using:<\/p>\n<pre>docker exec -it my-ghost-container ghost version<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-15281\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/3aee92ee.png?trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"966\" height=\"92\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>Although many <code>ghost-cli<\/code> components will work, some <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/github.com\/docker-library\/ghost\/issues\/156#issuecomment-428159861\">are unsupported<\/a> in Dockerized environments. Commands such as <code>install<\/code>, <code>setup<\/code>, <code>update<\/code>, and <code>uninstall<\/code> are either broken, meaningless, or contrary to best practices when used with Ghost\u2019s Docker image. Ghost and all its dependencies are built into the image and don\u2019t need to be \u201cinstalled;\u201d updates should be applied by starting a new container, as shown above.<\/p>\n<h2 id=\"summary\"><span class=\"ez-toc-section\" id=\"Summary\"><\/span>Summary<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Ghost is a modern blogging platform that offers a clean dashboard, rich content creation capabilities, and advanced theming and customization support. Using Docker to host Ghost simplifies the setup procedure, reduces the number of OS packages you need, and helps make your site more portable across environments.<\/p>\n<p>Once your Dockerized blog is operational, use the standard <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/hosting\">Ghost development documentation<\/a> to manage your site and its content. You can set up <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/members\">memberships<\/a>, <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/newsletters\">newsletters<\/a>, <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/themes\">custom themes<\/a>, and <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/ghost.org\/docs\/content-api\">API integrations<\/a> using the platform\u2019s built-in features.\n<\/div>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.cloudsavvyit.com\/15269\/how-to-deploy-a-ghost-blog-with-docker\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;#How to Deploy a Ghost Blog With Docker \u2013 CloudSavvy IT&#8221; Ghost is a popular content creation platform that\u2019s written in JavaScript with Node.js. The open-source software comes with everything you need to author, theme, publish, and maintain your own blog. Ghost is open-source software supported by the official Ghost(Pro) hosted service. You can install&#8230;<\/p>\n","protected":false},"author":1,"featured_media":397356,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2022\/01\/4d531b9d.jpg","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-397355","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/397355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=397355"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/397355\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/397356"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=397355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=397355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=397355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}