Azure Container Apps

This guide shows how to deploy xlwings Lite to Azure Container Apps.

Deploying the Container

  1. Go to Container Apps in the Azure portal.

  2. + 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-lite

    • Deployment source: Container image

    • Select the desired Region

    • Select the desired Container Apps environment (you may need to click on Create new environment first)

  3. Click on Next: Container

    • Image source: Docker Hub or other registries

    • Image type: Public

    • Registry login server: docker.io

    • Image and tag: xlwings/xlwings-lite:1.0.0.94

    • CPU and memory: 0.5 CPU cores, 1 Gi memory

    • Environment variables: XLWINGS_LICENSE_KEY: your-license-key (if you don’t have one, get a xlwings trial license key)

  4. 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

  5. You can optionally restrict access under Networking > IP Restrictions.

  6. Under Application > Scale (or Scale and replicas), set both Min replicas and Max replicas to 1 to prevent cold starts. If desired, you could set a Scale rule to set Min replicas to 0 outside business hours.

  7. 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

  1. 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.

  2. On the System assigned tab, switch Status to On and click Save.

  3. 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.

  1. In Azure DevOps, go to Organization settings > Users > Add users.

  2. 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.

  3. 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

  1. In your browser, go to https://<your-hostname>/manifest, which will download xlwings-lite-manifest.xml.

  2. 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 apps and select Office Add-in (App type).

    • Select Upload manifest file (.xml) from device. Click Choose File, then select the xlwings-lite-manifest.xml from the previous step.

    • Click Next, then assign the desired users.

    • Click Next and accept permission requests.

    • Click Next and Finish 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.

  1. Go to your container app, then Application > Containers.

  2. Click Edit and deploy, select the container, and update the Image and tag to:

    xlwings/xlwings-lite:1.0.0.94
    
  3. 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.