This sample demonstrates a Python Flask single-page web application called Vacation Planner hosted on an Azure Web App. The app runs on an Azure App Service Plan and stores activity data in the activities collection of the sampledb MongoDB database on an Azure CosmosDB for MongoDB account.
The following diagram illustrates the architecture of the solution:
The web app enables users to plan and manage vacation activities, with all data persisted in a CosmosDB-backed MongoDB collection. The solution is composed of the following Azure resources:
- Azure Resource Group: A logical container scoping all resources in this sample.
- Azure Virtual Network: Hosts two subnets:
- app-subnet: Dedicated to regional VNet integration with the Function App.
- pe-subnet: Used for hosting Azure Private Endpoints.
- Azure Private DNS Zone: Handles DNS resolution for the CosmosDB for MongoDB Private Endpoint within the virtual network.
- Azure Private Endpoint: Secures network access to the CosmosDB for MongoDB account via a private IP within the VNet.
- Azure NAT Gateway: Provides deterministic outbound connectivity for the Web App. Included for completeness; the sample app does not call any external services.
- Azure Network Security Group: Enforces inbound and outbound traffic rules across the virtual network's subnets.
- Azure Log Analytics Workspace: Centralizes diagnostic logs and metrics from all resources in the solution.
- Azure Cosmos DB for MongoDB: A globally distributed database account optimized for MongoDB workloads, with multi-region failover enabled.
- MongoDB Database: The
sampledbdatabase that holds all application data. - MongoDB Collection: The
activitiescollection withinsampledb, used to store vacation activity records. - Azure App Service Plan: The underlying compute tier that hosts the web application.
- Azure Web App: Runs the Python Flask single-page application (Vacation Planner), connected to CosmosDB for MongoDB via VNet integration.
- App Service Source Control: (Optional) Configures continuous deployment from a public GitHub repository.
- Azure Subscription
- Azure CLI
- Python 3.11+
- Flask
- pymongo
- Bicep extension, if you plan to install the sample via Bicep.
- Terraform, if you plan to install the sample via Terraform.
Set up the Azure emulator using the LocalStack for Azure Docker image. Before starting, ensure you have a valid LOCALSTACK_AUTH_TOKEN to access the Azure emulator. Refer to the Auth Token guide to obtain your Auth Token and set it in the LOCALSTACK_AUTH_TOKEN environment variable. The Azure Docker image is available on the LocalStack Docker Hub. To pull the image, execute:
docker pull localstack/localstack-azure-alphaStart the LocalStack Azure emulator by running:
# Set the authentication token
export LOCALSTACK_AUTH_TOKEN=<your_auth_token>
# Start the LocalStack Azure emulator
IMAGE_NAME=localstack/localstack-azure-alpha localstack start -d
localstack wait -t 60
# Route all Azure CLI calls to the LocalStack Azure emulator
azlocal start-interceptionDeploy the application to LocalStack for Azure using one of these methods:
All deployment methods have been fully tested against Azure and the LocalStack for Azure local emulator.
Note
When you deploy the application to LocalStack for Azure for the first time, the initialization process involves downloading and building Docker images. This is a one-time operation—subsequent deployments will be significantly faster. Depending on your internet connection and system resources, this initial setup may take several minutes.
- Retrieve the port published and mapped to port 80 by the Docker container hosting the emulated Web App.
- Open a web browser and navigate to
http://localhost:<published-port>. - If the deployment was successful, you will see the following user interface for adding and removing activities:
You can use the call-web-app.sh Bash script below to call the web app. The script demonstrates three methods for calling web apps:
- Through the LocalStack for Azure emulator: Call the web app via the emulator using its default host name. The emulator acts as a proxy to the web app.
- Via localhost and host port mapped to the container's port: Use
127.0.0.1with the host port mapped to the container's port80. - Via container IP address: Use the app container's IP address on port
80. This technique is only available when accessing the web app from the Docker host machine. - Via the default hostname: Call the web app via the default hostname
<web-app-name>.azurewebsites.azure.localhost.localstack.cloud:4566.
You can utilize MongoDB Compass to explore and manage your MongoDB databases and collections. Ensure you connect using mongodb://localhost:port connection string, where port corresponds to the port published by the MongoDB container on the host and mapped to the internal MongoDB port 27017.
Alternatively, you can use the MongoDB Shell to interact with and administer your MongoDB instance, as shown in the following table:
~$ mongosh mongodb://localhost:32770
Current Mongosh Log ID: 6914588406320f60899dc29c
Connecting to: mongodb://localhost:32770/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.5.9
Using MongoDB: 8.0.15
Using Mongosh: 2.5.9
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
------
The server generated these startup warnings when booting
2025-11-12T09:28:07.726+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
2025-11-12T09:28:07.892+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
2025-11-12T09:28:07.892+00:00: For customers running the current memory allocator, we suggest changing the contents of the following sysfsFile
2025-11-12T09:28:07.892+00:00: We suggest setting the contents of sysfsFile to 0.
2025-11-12T09:28:07.892+00:00: vm.max_map_count is too low
2025-11-12T09:28:07.892+00:00: We suggest setting swappiness to 0 or 1, as swapping can cause performance problems.
------
test> show dbs
admin 100.00 KiB
config 108.00 KiB
local 40.00 KiB
sampledb 180.00 KiB
test> use sampledb
switched to db sampledb
sampledb> show collections
activities
sampledb> db.activities.find().pretty()
[
{
_id: '39ab62c2aaa0015ed5309876053e4146',
username: 'Paolo',
activity: 'Go to Paris',
timestamp: '2025-11-12T09:31:43.338268'
},
{
_id: '4fb8f53442d3ebe9167245f9555bac51',
username: 'Paolo',
activity: 'Go to Madrid',
timestamp: '2025-11-12T09:31:50.109456'
},
{
_id: '84646160cb1db21a7083b4c5b6e2d9d0',
username: 'Paolo',
activity: 'Go to Rome',
timestamp: '2025-11-12T09:32:21.781936'
}
]

