{"id":201,"date":"2022-07-11T20:00:00","date_gmt":"2022-07-11T18:00:00","guid":{"rendered":"https:\/\/niwadev.com\/?p=201"},"modified":"2025-01-27T14:21:26","modified_gmt":"2025-01-27T13:21:26","slug":"how-to-deploy-a-productive-strapi-instance-on-azure-fast","status":"publish","type":"post","link":"https:\/\/niwadev.com\/fr\/blog\/how-to-deploy-a-productive-strapi-instance-on-azure-fast\/","title":{"rendered":"How to deploy a productive Strapi instance on Azure (fast)"},"content":{"rendered":"<p>Vous cherchez un moyen performant d'h\u00e9berger votre site web avec un CMS ? Vous tomberez rapidement sur Strapi. Si la documentation est encore correcte pendant le d\u00e9veloppement, elle pourrait \u00eatre meilleure pour l'impl\u00e9mentation productive. Dans cet article, je d\u00e9crirai les \u00e9tapes \u00e0 suivre pour que votre instance de Strapi soit op\u00e9rationnelle dans Azure.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Prerequests<\/h2>\n\n\n\n<p>To fully understand the article I recommend to get to know the basics of Docker, Strapi and Azure Web Apps.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setup environment<\/h2>\n\n\n\n<p>The Strapi documentation already provides a description of what resources are required. Basically, you need a database, a storage for assets like images, an App Service plan and an App Service where Strapi will be executed. Unfortunately, Strapi has no support for MS SQL databases. Therefore, you can&#8217;t use an Azure SQL Database which would save you some money.<\/p>\n\n\n\n<p>Microsoft offers a tool called &#8220;<a href=\"https:\/\/azure.microsoft.com\/en-us\/pricing\/calculator\/\">Pricing Calculator<\/a>&#8221; where you can figure out the estimated costs of your desired configuration before deploying resources.<br>I played a little bit around to find a solution that fits my needs and does not cost that much. The Pricing Calculator only provides an estimation of the costs. If you scale up your environment, it could be more.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-1024x579.png\" alt=\"Screenshot Pricing Calculator Microsoft Azure containing Azure Database for MySQL, Storage Accounts and App Service for $ 63.52\/month\" class=\"wp-image-202\" srcset=\"https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-1024x579.png 1024w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-300x170.png 300w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-768x434.png 768w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-1536x868.png 1536w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-2048x1158.png 2048w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Screenshot_Pricing_Calculator_Microsoft_Azure-18x10.png 18w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>There are many ways to set up resources in Azure. If you only set up a single environment I&#8217;d suggest to create the resource in the Azure web portal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setup database<\/h3>\n\n\n\n<p>You have two options you can choose from:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Azure Database for MySQL<\/li>\n\n\n\n<li>Azure Database for PostgreSQL<\/li>\n<\/ul>\n\n\n\n<p>I used the MySQL version. Microsoft recommends to use the &#8220;Flexible Server&#8221; approach. It offers a fully managed database service and saves a bunch of costs. You can also start small and scale it up later.<\/p>\n\n\n\n<p>After choosing <code>Create a resource &gt; Azure Database for MySQL &gt; Flexible Server<\/code> you can configure the resource (i. e. choose resource group, server name etc.).<br>The &#8220;Workload type&#8221; section could be misleading. The decision you make here influences the &#8220;Compute + storage&#8221; section. I wouldn&#8217;t give it too much attention and start with Standard_B1ms compute tier for small websites. According to the Strapi documentation it should be adequate for many Strapi workloads.<\/p>\n\n\n\n<p>In the &#8220;Networking&#8221; configuration you should choose &#8220;Allow public access from any Azure service within Azure to this server&#8221; to allow your Web App to access the database later on.<\/p>\n\n\n\n<p>To see how to setup the Strapi database user, see <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/mysql\/single-server\/how-to-create-users?tabs=single-server&amp;WT.mc_id=javascript-37811-aapowell\">Microsoft docs<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setup storage account<\/h3>\n\n\n\n<p>Setting up a storage account is pretty straightforward. Strapi only needs a standard storage account. The most important setting you have to check is &#8220;Enable blob public access&#8221; in the advanced configuration. Without it, it&#8217;s not possible to access the assets from an external source like your website.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Azure Service Plan &amp; App Service<\/h3>\n\n\n\n<p>The final component is responsible for the execution of Strapi. In the &#8220;Compute&#8221; category, you find the service &#8220;Web App&#8221;. When you create a new instance I&#8217;d suggest to use &#8220;Docker Container&#8221; as publish option. The <code>node_modules<\/code> folder contains thousands of small files that lead to a long deployment duration. In the context of Docker it makes sense to use Linux as operating system. It&#8217;s less expensive too.<\/p>\n\n\n\n<p>In the &#8220;Basics&#8221; section you also see an area to configure an App Service Plan. This is the foundation for all App Services. It defines a set of compute resources for a web app to run on. You can compare it to a server farm in conventional web hosting. Multiple App Services can be executed within one App Service Plan. If you want to host the website itself in Azure too, you can create another Web Service in this Service Plan to save some costs.<\/p>\n\n\n\n<p>Next, you see options to configure your Docker environment. For Strapi, it&#8217;s fine to use &#8220;Single Container&#8221;, because all other required resources (database and storage) are located in separate services. As the image source select the desired registry. If you use something else than provides (i. e. GitHub Container Registry) you can configure it by selecting &#8220;Private Registry&#8221;.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prepare Strapi to run in Docker<\/h2>\n\n\n\n<p>Now that we have configured all our resources to host Strapi on Azure we need to create a Docker image for Strapi. If you have already set up your Dockerfile you can skip this section.<\/p>\n\n\n\n<p>Unfortunately, Strapi already needs some space. To reduce the image size to a minimum I use the distroless node image from Google as a base. I also recommend to only copy the directories you explicitly need into the image. The distroless images come with reduced functionality. Therefore, I don&#8217;t use them to build the application. Here you can see the configuration I created to build the image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM node:gallium-buster-slim as build_base\nENV NODE_ENV production\n\nFROM gcr.io\/distroless\/nodejs:16 as base\nENV HOST 0.0.0.0\nENV PORT 1337\nENV NODE_ENV production\n\nFROM build_base as build\n\nRUN mkdir -p \/usr\/src\/app\nWORKDIR \/usr\/src\/app\n\nCOPY . .\nRUN yarn\nRUN yarn build\n\nFROM base as strapi\n\nWORKDIR \/app\n\nCOPY --from=build \/usr\/src\/app\/build .\/build\nCOPY --from=build \/usr\/src\/app\/config .\/config\nCOPY --from=build \/usr\/src\/app\/database .\/database\nCOPY --from=build \/usr\/src\/app\/public .\/public\nCOPY --from=build \/usr\/src\/app\/src .\/src\nCOPY --from=build \/usr\/src\/app\/node_modules .\/node_modules\nCOPY --from=build \/usr\/src\/app\/package.json .\/package.json\nCOPY --from=build \/usr\/src\/app\/favicon.ico .\/favicon.ico\nCOPY --from=build \/usr\/src\/app\/server.js .\/server.js\n\nEXPOSE 1337\n\nCMD &#91;\"server.js\"]<\/code><\/pre>\n\n\n\n<p>Maybe, you already noticed I have a JS file called &#8220;server.js&#8221;. This is the entry point of the app. You need to create this file on the root directory of your project by your own. It&#8217;s not provided by default. It&#8217;s needed, because the distroless image can not execute npm or yarn commands.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const strapi = require('@strapi\/strapi');\nstrapi().start();<\/code><\/pre>\n\n\n\n<p>Strapi is now ready to run in a Docker container. Personally, I prefer working with (almost) the same environment locally as in production. That&#8217;s the point where Docker Compose comes in. I only use it for my local development and <strong>not<\/strong> to deploy it on Azure. Fortunately, all services Strapi depends on are available as Docker image.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: '3.9'\n\nservices:\n  strapicms:\n    build: .\/\n    ports:\n      - \"1337:1337\"\n    environment:\n      DATABASE_NAME: strapi\n      DATABASE_USERNAME: ${DATABASE_USERNAME}\n      DATABASE_PASSWORD: ${DATABASE_PASSWORD}\n      DATABASE_HOST: mysqldb\n      JWT_SECRET: ${JWT_SECRET}\n      API_TOKEN_SALT: ${API_TOKEN_SALT}\n      APP_KEYS: ${APP_KEYS}\n      STORAGE_ACCOUNT: ${STORAGE_ACCOUNT}\n      STORAGE_ACCOUNT_KEY: ${STORAGE_ACCOUNT_KEY}\n      STORAGE_CONTAINER_NAME: ${STORAGE_CONTAINER_NAME}\n      STORAGE_URL: ${STORAGE_URL}\n    depends_on:\n      - mysqldb\n      - azurite-v3\n\n  mysqldb:\n    image: mysql:5-debian\n    command: mysqld --default-authentication-plugin=mysql_native_password\n    ports:\n      - \"3306:3306\"\n    volumes:\n      - mysql:\/var\/lib\/mysql\n    environment:\n      MYSQL_DATABASE: strapi\n      MYSQL_USER: ${DATABASE_USERNAME}\n      MYSQL_PASSWORD: ${DATABASE_PASSWORD}\n      MYSQL_ROOT_PASSWORD: justapassword\n\n  azurite-v3:\n    image: mcr.microsoft.com\/azure-storage\/azurite\n\nvolumes:\n  mysql:<\/code><\/pre>\n\n\n\n<p>The placeholders (marked with ${}) are variables that will be filled with the content out of an environment file (.env) automatically when starting the compose file with <code>docker compose up -d<\/code>. The env file has to be placed in the same directory as the docker-compose.yml. After filling the environment file start the Docker Compose and check if everything is running well.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Putting everything together<\/h2>\n\n\n\n<p>Now, we have everything ready to deploy Strapi as Docker container on Azure! But if we try out to deploy and run it now it will fail. Before the application can be executed successfully the environment variables have to be configured in the Web App. This was the point which wasn&#8217;t mentioned in the Azure deployment guide of Strapi and I had to search a little while what Strapi needed to run correctly.<\/p>\n\n\n\n<p>In the Azure Web App under <code>Settings &gt; Configuration<\/code> you can configure the application settings. These are the settings that replace the .env file in the cloud environment.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"931\" height=\"870\" src=\"http:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Microsoft_Azure_Portal_configure_env_variables.png\" alt=\"Configuration screen showing environment variables set up under application settings.\" class=\"wp-image-203\" srcset=\"https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Microsoft_Azure_Portal_configure_env_variables.png 931w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Microsoft_Azure_Portal_configure_env_variables-300x280.png 300w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Microsoft_Azure_Portal_configure_env_variables-768x718.png 768w, https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/Microsoft_Azure_Portal_configure_env_variables-13x12.png 13w\" sizes=\"(max-width: 931px) 100vw, 931px\" \/><\/figure>\n\n\n\n<p>Basically, you need to define all the variables as you did in the local development environment.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>API_TOKEN_SALT: random string of numbers and letters\nAPP_KEYS: &#91;\"DATABASE_URL\", \"NODE_ENV\"]\nDATABASE_HOST: host name of your  mysql database (in Azure &lt;name&gt;.mysql.database.azure.com)\nDATABASE_NAME: e. g. strapi\nDATABASE_PASSWORD: password of the database user used by Strapi\nDATABASE_SSL: true\nDATABASE_USERNAME: username of the database user used by Strapi\nJWT_SECRET: random string of numbers and letters\nNODE_ENV: production\nPORT: 443 (to run Strapi on the default HTTPS port)\nSTORAGE_ACCOUNT: Name of the storage account that was assigned in Azure\nSTORAGE_ACCOUNT_KEY: Password to the storage account (created by Azure)\nSTORAGE_CONTAINER_NAME: Name of the storage container already created\nSTORAGE_URL: URL to Azure Blob Storage (https:\/\/&lt;name&gt;.blob.core.windows.net\/)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Logging and fetching errors<\/h2>\n\n\n\n<p>There are several ways to fetch the logs of an application. The easiest way is to just enable the file system logging. Then, you can see them in the Diagnose menu. To enable file system logging, open <code>Monitoring &gt; App Service logs<\/code> in your Web App and set application logging to &#8220;File System&#8221;. To access the file system logs in the portal, open <code>Diagnose and solve problems &gt; Application Logs<\/code> in the Web App. There you can see the output of Strapi and identify errors if it won&#8217;t start.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>By getting Strapi hosted on Azure I learnt a lot about Docker and troubleshooting an Azure Web App. Docker is a requirement to transfer your latest changes fast and don&#8217;t have to deal with issues of different environments (Linux, Mac, Windows; local or remote etc.).<br>Hopefully, I could help you setting up your Strapi instance on a production environment.<\/p>","protected":false},"excerpt":{"rendered":"<p>Vous cherchez un moyen performant d'h\u00e9berger votre site web avec un CMS ? Vous tomberez rapidement sur Strapi. Si la documentation est encore correcte pendant le d\u00e9veloppement, elle pourrait \u00eatre meilleure pour l'impl\u00e9mentation productive. Dans cet article, je d\u00e9crirai les \u00e9tapes \u00e0 suivre pour que votre instance de Strapi soit op\u00e9rationnelle dans Azure.<\/p>","protected":false},"author":2,"featured_media":205,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","footnotes":""},"categories":[1],"tags":[18,21,20,17,19],"class_list":["post-201","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-azure","tag-cloud","tag-devops","tag-docker","tag-nodejs"],"aioseo_notices":[],"uagb_featured_image_src":{"full":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container.webp",1200,400,false],"thumbnail":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container-150x150.webp",150,150,true],"medium":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container-300x100.webp",300,100,true],"medium_large":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container-768x256.webp",768,256,true],"large":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container-1024x341.webp",1024,341,true],"1536x1536":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container.webp",1200,400,false],"2048x2048":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container.webp",1200,400,false],"trp-custom-language-flag":["https:\/\/niwadev.com\/wp-content\/uploads\/2023\/09\/deploy-docker-container-18x6.webp",18,6,true]},"uagb_author_info":{"display_name":"Nicolas Wazulek","author_link":"https:\/\/niwadev.com\/fr\/blog\/author\/u_auth_niwa\/"},"uagb_comment_info":0,"uagb_excerpt":"You&#8217;re looking for a performant way to host your website with a CMS? You will quickly come across Strapi. Where the documentation is still ok during development, it could be better for the productive implementation. In this article I want to describe the steps to get your Strapi instance up and running in Azure.","_links":{"self":[{"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/posts\/201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/comments?post=201"}],"version-history":[{"count":1,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/posts\/201\/revisions"}],"predecessor-version":[{"id":960,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/posts\/201\/revisions\/960"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/media\/205"}],"wp:attachment":[{"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/media?parent=201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/categories?post=201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/niwadev.com\/fr\/wp-json\/wp\/v2\/tags?post=201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}