<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Edi Wang</title><subtitle>Microsoft MVP for Azure</subtitle><rights>© 2009 - 2026 edi.wang</rights><updated>2026-04-19T04:37:17Z</updated><generator uri="https://edi.wang">Moonglade v15.13.2</generator><entry><id>535F439F-A6A2-4062-AAD1-05395E504A17</id><title>Deploy Open WebUI on Azure Container Apps with PostgreSQL</title><updated>2026-04-13T02:14:58Z</updated><published>2026-04-13T02:14:58Z</published><link href="https://edi.wang/post/2026/4/13/deploy-open-webui-on-azure-container-apps-with-postgresql" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="AI" /><category term="Microsoft Azure" /><content>In my previous blog posts, I covered two different ways to deploy Open WebUI on Azure. However, both approaches came with problems. I ran into serious performance issues as well as functional bugs, so I spent some time testing different options and came up with a better deployment architecture that solves all the issues I have seen so far. In this post, I’ll walk through those issues and explain what I currently consider the best architecture for deploying Open WebUI on Azure, so it can run with much better performance, reliability, and security.</content></entry><entry><id>9C2D6CA5-03C9-4522-AC56-9D19F601803F</id><title>Hot Reloading a File in Azure Container Apps with Zero Down Time</title><updated>2026-03-03T09:37:30Z</updated><published>2026-03-03T09:37:30Z</published><link href="https://edi.wang/post/2026/3/3/hot-reloading-a-file-in-azure-container-apps-with-zero-down-time" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term=".NET" /><category term="Microsoft Azure" /><content>Recently, I developed an ASP.NET Core application that can query a local data file for IP address information. The application is deployed to Azure Container Apps, and the data file is mounted in Azure File Share as a volume for the container. There is another job that will update the data file every day on schedule. The application would not read the entire data file on each request for performance concerns, it would load the data into memory on start up. The blog post will explain how to reload the data on the fly without downtime.</content></entry><entry><id>2BD9D033-62CF-4B4C-8AE2-59D73FC1FA19</id><title>Update Files in Azure File Share on Schedule with Azure Container App Jobs</title><updated>2026-02-23T10:54:25Z</updated><published>2026-02-23T10:54:25Z</published><link href="https://edi.wang/post/2026/2/23/update-files-in-azure-file-share-on-schedule-with-azure-container-app-jobs" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="DevOps" /><category term="Microsoft Azure" /><content>I have a containerized app that relies on a data file mounted at runtime, an IP lookup API that reads qqwry.dat file. I deploy the App on Azure Container Apps, and use Azure File Share to mount the data directory for the app to use. One problem remains: How to keep the file updated automatically? e.g., to check for updates daily without manual replacing the file on Azure Storage Account. In this post, I will introduce how to use Azure Container Apps Jobs to run a small "updater container" on a schedule. The updater downloads the latest file and writes it into the mounted file share, while the main API container reads the file from the same mount path.</content></entry><entry><id>FD664CCB-339F-4DB8-8A67-656F6D591AAB</id><title>Modernizing My Azure Deployment Script with PowerShell and Bicep</title><updated>2026-02-08T07:34:39Z</updated><published>2026-02-08T07:34:39Z</published><link href="https://edi.wang/post/2026/2/8/modernizing-my-azure-deployment-script-with-powershell-and-bicep" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="DevOps" /><category term="Microsoft Azure" /><content>I refactored Moonglade's Azure deployment from a single, all‑in‑one PowerShell script to a PowerShell + Bicep setup. PowerShell now handles orchestration and user input, while Bicep declaratively defines the App Service Plan, Web App, SQL Server, database, firewall rule, and storage account. This keeps the same one-click experience, but makes the infrastructure easier to maintain, review, and reuse.</content></entry><entry><id>EE9EE084-E170-4A5B-BFA5-16772F7AEC53</id><title>Migrating this Blog to Docker on Linux with Azure App Service</title><updated>2026-02-05T05:09:58Z</updated><published>2026-02-05T05:09:58Z</published><link href="https://edi.wang/post/2026/2/5/migrating-this-blog-to-docker-on-linux-with-azure-app-service" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term=".NET" /><category term="Microsoft Azure" /><content>This blog runs on my open-source project Moonglade, a blogging platform built with ASP.NET Core and hosted on Azure. Recently, I migrated it from a Windows Server environment to Docker on Linux, still running on Azure App Service. It’s been running smoothly in production for about two months now. In this post, I’ll walk through that migration journey: what I changed, a few tips and tricks along the way, and some lessons learned that might help you if you’re considering a similar move.</content></entry><entry><id>6628087E-941A-44BB-80F5-B88012A9AA81</id><title>Deploying a Remote Chrome Browser with Azure Container Instance</title><updated>2026-01-05T01:26:02Z</updated><published>2026-01-05T01:26:02Z</published><link href="https://edi.wang/post/2026/1/5/deploying-a-remote-chrome-browser-with-azure-container-instance" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Microsoft Azure" /><content>Running a full desktop browser in the cloud and accessing it remotely can be surprisingly useful. You might want a disposable browser for testing and automation, a sandboxed environment isolated from your local machine
or a remote browser you can get to from any device with a decent network connection. In this post, I'll walk through how I deployed a remote Chrome browser running in a Docker container on Azure Container Instances, and how I access it from a regular web browser.</content></entry><entry><id>2C6A3E51-DD85-4CBD-BBBF-AC26DF02B6F5</id><title>Deploy Open WebUI with Azure App Service and PostgreSQL</title><updated>2025-12-16T02:28:19Z</updated><published>2025-12-16T02:28:19Z</published><link href="https://edi.wang/post/2025/12/16/deploy-open-webui-with-azure-app-service-and-postgresql" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="AI" /><category term="Microsoft Azure" /><content>In my previous post, I showed how to deploy Open WebUI with Azure OpenAI on Azure Container Apps using the default SQLite database. That setup works well for quick experiments and low-traffic scenarios. But once multiple users started using the application at the same time, things went downhill quickly. Requests became noticeably slower, the UI felt laggy and the whole app started to feel fragile under concurrent load. This blog post will explain how to move the setup to Azure App Service (Linux, Docker) for hosting the Open WebUI container and use Azure Database for PostgreSQL for a proper, scalable relational database.</content></entry><entry><id>F987AFEF-6221-4C2B-BB73-6058457677A1</id><title>About the Gzip Compression Behavior on Azure App Service</title><updated>2025-11-26T02:08:23Z</updated><published>2025-11-26T02:08:23Z</published><link href="https://edi.wang/post/2025/11/26/about-the-gzip-compression-behavior-on-azure-app-service" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Microsoft Azure" /><content>When we deploy our web applications to Azure App Service, the Gzip compression header is sometimes enabled by default and sometimes missing. I wanted to run a few tests to better understand this behavior. My goal is to identify under what conditions the Gzip compression header is automatically added by Azure App Service, and determine whether we can manually change the default behavior to enable or disable Gzip on Azure App Service.</content></entry><entry><id>6C14D27C-E781-45A6-8F8B-A0399753524D</id><title>How to Take Memory Dump on Azure App Service</title><updated>2025-10-14T07:09:28Z</updated><published>2025-10-14T07:09:28Z</published><link href="https://edi.wang/post/2025/10/14/how-to-take-memory-dump-on-azure-app-service" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Microsoft Azure" /><content>Sometimes, web applications run smoothly during development and testing, but mysterious issues only surface in the production environment. Debugging these production problems can be challenging, especially when you don’t have direct access to the server. For example, when deploying on a traditional VM, it’s straightforward for developers to capture memory dumps for in-depth analysis. But what happens when your application is hosted on a PaaS solution like Azure App Service, where you can’t access the underlying VM? Let's check out.</content></entry><entry><id>1EE6FBD2-3469-4CD9-9862-43A197EF3A55</id><title>How to Automatically Restart Azure Container Apps on Schedule</title><updated>2025-10-10T02:37:27Z</updated><published>2025-10-10T02:37:27Z</published><link href="https://edi.wang/post/2025/10/10/how-to-automatically-restart-azure-container-apps-on-schedule" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Microsoft Azure" /><content>In certain scenarios, you may need to restart your Azure Container Apps on schedule. Like I always joke about, a restart fixes 95% problems. However, if you do it manually, it will make you work 996. We need an automated way to complete this task. Azure Functions are perfect for this kind of "do something on a schedule" task. In this post, I will introduce how to use Azure Function timed trigger to automate this process.</content></entry><entry><id>FE8579AC-7BB8-4B4C-8D4E-04E0D557FFD9</id><title>PowerShell Script to Check Azure App Service SSL Certificate Expiration</title><updated>2025-08-18T04:48:11Z</updated><published>2025-08-18T04:48:11Z</published><link href="https://edi.wang/post/2025/8/18/powershell-script-to-check-azure-app-service-ssl-certificate-expiration" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="DevOps" /><category term="Microsoft Azure" /><content>When you have a lot of App Service instances running in your Azure subscription, managing their SSL certificate status could be a problem. Azure portal itself does have certain monitoring and advising feature to visualize the certificate status and warn you before a certificate expires. However, in some cases, we prefer this to be done in command line environment. That's why I put together this handy PowerShell script that uses Azure CLI to keep tabs on all your App Service SSL certificates.</content></entry><entry><id>246E20F4-9547-47D8-94BA-7ADD8AE73424</id><title>Deploy Sdcb Chats on Azure Container Apps</title><updated>2025-07-25T01:00:43Z</updated><published>2025-07-25T01:00:43Z</published><link href="https://edi.wang/post/2025/7/25/deploy-sdcb-chats-on-azure-container-apps" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="AI" /><category term="Microsoft Azure" /><content>Sdcb Chats is a powerful and flexible frontend for large language models that supports various features and platforms. Whether you want to manage multiple model interfaces or need a simple deployment process, Sdcb Chats can meet your needs. In this post, I will show you how to deploy Sdcb Chats on Azure Container Apps, the goal is to run it on full PaaS environment, without creating and managing a VM.</content></entry><entry><id>B6CCE0D3-EF73-4428-85E3-FE89F607B311</id><title>Automating Deployment of Open WebUI on Azure Container Apps with Bicep</title><updated>2025-07-24T05:20:05Z</updated><published>2025-07-24T05:20:05Z</published><link href="https://edi.wang/post/2025/7/24/automating-deployment-of-open-webui-on-azure-container-apps-with-bicep" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="AI" /><category term="DevOps" /><category term="Microsoft Azure" /><content>In my previous blog post, I introduced how to deploy Open WebUI with Azure OpenAI on Azure Container Apps in Azure Portal manually. However, manual deployment usually makes people work 996. In this post, I will show you how to automate everything using Bicep. If you’re new to Bicep, think of it as a friendlier way to define Azure resources as code compared to raw ARM templates. I’ll walk you through my Bicep file, explaining how each block helps set up a scalable, persistent, and easy-to-manage Open Web UI deployment.</content></entry><entry><id>72CDA426-67DA-453E-B271-8B1F06D7D152</id><title>Deploy Open WebUI with Azure OpenAI on Azure Container Apps</title><updated>2025-07-17T05:50:30Z</updated><published>2025-07-17T05:50:30Z</published><link href="https://edi.wang/post/2025/7/17/deploy-open-webui-with-azure-openai-on-azure-container-apps" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="AI" /><category term="Microsoft Azure" /><content>A few years ago, I shared step-by-step guides on deploying NextChat (ChatGPT Next Web) and BigAGI to Azure using managed PaaS services such as App Service—eliminating the hassle of configuring and maintaining virtual machines. Now, a new UI called Open WebUI has been generating a lot of buzz for its user-friendly interface and open approach. In this post, I’ll walk you through how to easily deploy Open WebUI to Azure using Azure Container Apps. I’ll also show you how to connect it directly to your Azure OpenAI endpoint, all without the need for any additional proxy services like LiteLLM.</content></entry><entry><id>6EC95F94-EFAC-4F44-B28C-7D6B46F93B36</id><title>Auto Generating Incremental Resource Names in Azure Bicep</title><updated>2025-05-19T04:41:45Z</updated><published>2025-05-19T04:41:45Z</published><link href="https://edi.wang/post/2025/5/19/auto-generating-incremental-resource-names-in-azure-bicep" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="DevOps" /><category term="Microsoft Azure" /><content>Bicep's syntax is already pretty clean, but sometimes you run into situations like needing to concatenate strings or format names repeatedly, doing small calculations based on input parameters, or having long, messy expressions inside resource definitions. Let’s say you want to automatically generate a series of VM names like web-01, web-02, and so on. Without functions, you’d have to write 'web-${padLeft(string(i+1), 2, '0')}' every time, makes you work 996. Let’s see how to make this easier.</content></entry><entry><id>6DAF2659-5CF5-4339-923A-1A791C85F807</id><title>Adding Azure Bicep Language Support for highlight.js</title><updated>2025-05-18T12:36:49Z</updated><published>2025-05-18T12:36:49Z</published><link href="https://edi.wang/post/2025/5/18/adding-azure-bicep-language-support-for-highlightjs" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Web Development" /><category term="Microsoft Azure" /><content>I am using highlight.js to render code snippets on this blog system. However, the official pack of highlight.js does not have Bicep as one of the languages. To add support for the Bicep language in highlight.js, you need to implement a Bicep language definition module. Below are the detailed steps and code examples.</content></entry><entry><id>0C38DF90-40EF-40CB-9CA0-7ABC97C2CC40</id><title>Deploying Azure App Service and SQL Server with Bicep</title><updated>2025-05-18T01:18:46Z</updated><published>2025-05-18T01:18:46Z</published><link href="https://edi.wang/post/2025/5/18/deploying-azure-app-service-and-sql-server-with-bicep" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="DevOps" /><category term="Microsoft Azure" /><content>Last week at Microsoft Reactor Shanghai, I addressed a speech "Automating Infrastructure as Code (IaC) Deployment with Azure Bicep". One of the demo was how to use Bicep to deploy a complete Azure web app environment, including an App Service and an Azure SQL Database. I know we didn’t have time to walk through the whole script, so I wanted to break it down here in a blog post. Let’s walk through this Bicep file together, and see what each part does!</content></entry><entry><id>8DC15969-2016-487E-AD7B-06FCBBE13E00</id><title>How to Organize Azure Resource Group Efficiently</title><updated>2025-02-11T05:55:57Z</updated><published>2025-02-11T05:55:57Z</published><link href="https://edi.wang/post/2025/2/11/how-to-organize-azure-resource-group-efficiently" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Microsoft Azure" /><content>In Azure, Resource Groups are a key concept for managing resources. They provide a logical way to group related resources, making it easier to manage and control access. However, as your cloud environment git bigger, organizing Resource Groups becomes more difficult. This blog post explains common practices for using Azure Resource Groups. These tips will help you manage and organize your resources more effectively! Key features of Resource Group are: Group related resources together for easier management. Deleting a resource group also deletes all resources inside it. Assign roles and permissions at the resource group level (IAM).</content></entry><entry><id>96CBBDF1-367C-4065-AF2D-A4BF46946434</id><title>Secure Your Azure OpenAI API for Azure App Service with VNet Integration</title><updated>2024-12-18T12:28:11Z</updated><published>2024-12-18T12:28:11Z</published><link href="https://edi.wang/post/2024/12/18/secure-your-azure-openai-api-for-azure-app-service-with-vnet-integration" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="AI" /><category term="Microsoft Azure" /><content>When deploying Azure OpenAI resources, prioritizing security is essential. One critical step is to restrict access to your API endpoint, ensuring only your applications can connect. By implementing such measures, even if your API key is leaked, unauthorized users will be unable to exploit it—protecting you from unexpected charges. Follow the steps outlined in this blog post to implement network restrictions and safeguard your resources.</content></entry><entry><id>B3B44BF5-0D2C-48AC-A615-309385690F28</id><title>Migrating Moonglade.Email to Azure Communication Service</title><updated>2024-11-25T02:58:17Z</updated><published>2024-11-25T02:58:17Z</published><link href="https://edi.wang/post/2024/11/25/migrating-moongladeemail-to-azure-communication-service" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term=".NET" /><category term="Microsoft Azure" /><content>Moonglade.Email, is an Azure Function that originally relied on SMTP for sending emails. Microsoft implemented a change that prevents connections to both personal and enterprise Office 365 Outlook mailboxes. To ensure the email service continues functioning, I decided to integrate Azure Communication Services. In this blog post, I will explain how I implemented support for Azure Communication Services in the Moonglade.Email Azure Function.</content></entry></feed>