Azure Container Apps¶
This guide shows how to deploy xlwings Lite to Azure Container Apps.
Deploying the Container¶
+ Create > + Container App
Select the desired Resource group (you may need to click on Create new resource group first)
Container app name: e.g.
xlwings-liteDeployment source: Container image
Select the desired Region
Select the desired Container Apps environment (you may need to click on Create new environment first)
Click on Next: Container
Image source: Docker Hub or other registries
Image type: Public
Registry login server:
docker.ioImage and tag:
xlwings/xlwings-lite:1.0.0.94CPU and memory:
0.5 CPU cores, 1 Gi memoryEnvironment variables:
XLWINGS_LICENSE_KEY:your-license-key(if you don’t have one, get a xlwings trial license key)
Click on Next: Ingress
Activate the checkbox for Ingress
Under Ingress traffic, select Accepting traffic from anywhere
Set Target port to
8000
Click on Next: Tags
Click on Next: Review + create
Click on Create
You can optionally restrict access under Networking > IP Restrictions.
Under Application > Scale (or Scale and replicas), set both Min replicas and Max replicas to
1to prevent cold starts. If desired, you could set a Scale rule to set Min replicas to0outside business hours.Go to your Application Url. You should see the version of xlwings Lite.
Connecting to Azure Artifacts (optional)¶
By default, xlwings Lite installs packages from the public PyPI. If your organization keeps its Python packages in an Azure Artifacts feed, you can point xlwings Lite at it instead by setting XLWINGS_PYPI_INDEX_URL. The container reverse-proxies the feed on the same origin (under /pypi/), so the browser never sees the feed’s credentials and there are no CORS or CSP exceptions to manage.
There are two ways to authenticate the container to the feed:
Managed identity (recommended): no secret is stored anywhere. The container fetches a short-lived Microsoft Entra token from the Azure platform at runtime. This is the cleaner option and the one documented in full below.
Personal Access Token (PAT): a token embedded in the index URL. Simpler to set up, but the token expires and must be rotated. See Alternative: Personal Access Token (PAT).
Note
This section assumes you already have a working deployment from the steps above. The feed URL is the same one you would pass to pip install --index-url, e.g. https://pkgs.dev.azure.com/<org>/<project>/_packaging/<feed>/pypi/simple/ (organization-scoped feeds omit the /<project> segment).
Managed identity¶
1. Enable a system-assigned managed identity¶
Go to your container app, then Settings > Security > Identity.
Note
In older portal layouts the Identity blade lives directly under Settings rather than under Security. If you can’t find it, use the search box at the top of the left-hand menu and type
Identity.On the System assigned tab, switch Status to On and click Save.
Note the Object (principal) ID that appears — you’ll need it in the next step.
2. Grant the identity access to the feed¶
The managed identity is a Microsoft Entra service principal. Before you can grant it feed permissions, it usually has to be added to the Azure DevOps organization first.
In Azure DevOps, go to Organization settings > Users > Add users.
Set the user type to Service Principal, search by the Object (principal) ID (or the identity’s Application/Client ID), and assign an access level (e.g. Basic or Stakeholder). Click Add.
Note
This step is easy to miss. A brand-new managed identity often does not show up by name in the feed’s permissions dialog until it has been added to the organization here.
Now open your feed > Feed settings (gear icon) > Permissions > Add users/groups, find the identity (search by name or by the Object ID), and assign the role Collaborator (shown as Feed and Upstream Reader (Collaborator)).
Warning
Use Collaborator, not Reader. Reader can only serve packages that are already cached in the feed. Installing a package that isn’t cached yet triggers an ingestion from the feed’s upstream source (e.g. public PyPI), which requires the Collaborator role or higher. With only Reader, uncached packages fail with a misleading
Cannot find the package ... in feed(PackageNotFound) error.
3. Configure the environment variables¶
Go to Application > Containers > Environment variables (Edit and deploy) and add:
XLWINGS_PYPI_INDEX_URL: your feed URL, e.g.https://pkgs.dev.azure.com/<org>/_packaging/<feed>/pypi/simple/(no token)XLWINGS_PYPI_AUTH_MODE:azure-managed-identity
Saving creates a new revision and restarts the container.
Note
Enable the managed identity (step 1) before setting these variables. The platform only injects the identity token endpoint into the container once an identity is assigned, and xlwings Lite reads it at startup. If you set the variables first, restart the revision after enabling the identity.
4. Verify¶
Open https://<your-app-url>/pypi/simple/<some-package>/ in a browser (or with curl). A 200 response listing the package’s files (as an HTML page of links, or as JSON if you request it with Accept: application/vnd.pypi.simple.v1+json) means the feed connection and authentication are working. You can then add the package to your requirements.txt in the add-in.
If you get a 401/403, check the identity’s feed permissions (step 2). If a never-installed package returns a 404 with PackageNotFound, the identity likely has Reader instead of Collaborator. The container logs (Monitoring > Log stream, or az containerapp logs show) report token-fetch failures explicitly.
Alternative: Personal Access Token (PAT)¶
If you can’t use a managed identity, embed a PAT in the feed URL instead. Create a PAT in Azure DevOps (User settings > Personal access tokens) with the Packaging: Read scope, then set a single environment variable:
XLWINGS_PYPI_INDEX_URL:https://<PAT>@pkgs.dev.azure.com/<org>/_packaging/<feed>/pypi/simple/
No XLWINGS_PYPI_AUTH_MODE is needed (it defaults to PAT/basic authentication). The proxy forwards the token to the feed and strips it from everything the browser sees.
Note
As with managed identity, installing an uncached package triggers upstream ingestion, so the PAT (or the account it belongs to) needs permission to save packages from upstream sources. Prefer a token from a dedicated service account over a personal one, and rotate it before it expires.
Register the add-in with Microsoft 365 admin center¶
In your browser, go to
https://<your-hostname>/manifest, which will downloadxlwings-lite-manifest.xml.Go to Microsoft 365 admin center
Click on
Show all>Settings>Integrated Apps.If you have xlwings Lite installed, uninstall it first.
Click on
Upload custom appsand selectOffice Add-in(App type).Select
Upload manifest file (.xml) from device. ClickChoose File, then select thexlwings-lite-manifest.xmlfrom the previous step.Click
Next, then assign the desired users.Click
Nextand accept permission requests.Click
NextandFinish deployment.
The users will get the add-in to show up automatically although it may take a few hours.
Note
If you want to remove the add-in again and run into issues (“Remove apps failed. No apps were successfully removed. Please try to remove them later.”), use this legacy URL: https://admin.microsoft.com/#/Settings/AddIns
Updating¶
To update xlwings Lite, point your container app at the new image tag.
Go to your container app, then Application > Containers.
Click Edit and deploy, select the container, and update the Image and tag to:
xlwings/xlwings-lite:1.0.0.94
Click Save to create a new revision and deploy it.
Note
Normally you don’t need to update the manifest after deploying a new version of the container. This would only be required, e.g., if the URL of your container changed. In that case, the Microsoft 365 admin center offers a link to Update Add-in.