Skill 137 · AWS Lambda Web Functions
Subchapter 137.5
references/getting-started.mdMarkdown6 KBView on GitHub
aws lambda-web help # not recognised? update the AWS CLI (see deployment.md)
node --version # match the runtime; confirm supported runtimes with `aws lambda-web help` or the AWS docsCreate S3 bucket with versioning and Lambda access:
aws s3 mb s3://{bucket} --region {region}
aws s3api put-bucket-versioning --bucket {bucket} \
--versioning-configuration Status=Enabled --region {region}
aws s3api put-bucket-policy --bucket {bucket} --policy '{
"Version": "2012-10-17",
"Statement": [{"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": ["s3:GetObject", "s3:GetObjectVersion"],
"Resource": "arn:aws:s3:::{bucket}/*",
"Condition": {
"StringEquals": {"aws:SourceAccount": "{account-id}"},
"ArnLike": {"aws:SourceArn": "arn:aws:lambda:{region}:{account-id}:web-function/*"}}},
{"Effect": "Deny", "Principal": "*", "Action": "s3:*",
"Resource": ["arn:aws:s3:::{bucket}", "arn:aws:s3:::{bucket}/*"],
"Condition": {"Bool": {"aws:SecureTransport": "false"}}}]
}'S3 encrypts every new object at rest with SSE-S3 by default, so the code artifact is encrypted without an extra step. To encrypt the code artifact and environment variables with a customer-managed key instead, set revisionConfig.kmsKeyArn — see deployment.md (opens in a new tab).
Create execution role:
aws iam create-role --role-name {name}-web-role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"}]
}'
# Logs only — this is all a basic web function needs at runtime:
aws iam attach-role-policy --role-name {name}-web-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Add LEAST-PRIVILEGE inline policies ONLY for the AWS services your app calls at runtime,
# scoped to specific resource ARNs. Example — read/write one DynamoDB table:
# aws iam put-role-policy --role-name {name}-web-role --policy-name app-access \
# --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow",
# "Action":["dynamodb:GetItem","dynamodb:PutItem"],
# "Resource":"arn:aws:dynamodb:{region}:{account}:table/{name}-items"}]}'mkdir my-app && cd my-app
npm init -y && npm pkg set type=module
npm install expressimport express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello from Web Functions'));
const [HOST, PORT] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT || '0.0.0.0:3000').split(':');
app.listen(PORT, HOST);This starter deploys with authType: ApplicationManaged — public to anyone with the URL.
It has no auth, which is fine for a hello-world. Before exposing anything non-public,
implement auth in the app (see iam-and-security.md (opens in a new tab)) or use
IamAuth.
node index.js
curl http://localhost:3000/npm ci --omit=dev
zip -r function.zip index.js package.json node_modules/
aws s3 cp function.zip s3://{bucket}/my-app/function.zip
aws lambda-web create-web-function \
--function-name my-app \
--revision-config '{"buildConfig":{"codeConfig":{"s3Object":{"bucket":"{bucket}","key":"my-app/function.zip"}},"runtimeConfig":{"runtime":"nodejs24.x"}},"serviceConfig":{"executionRoleArn":"arn:aws:iam::{account}:role/my-app-web-role"}}' \
--endpoint-config '{"endpointName":"default","endpointType":"HomeRegion","authType":"ApplicationManaged","autoDeploymentMode":"LatestRevision"}' \
--region {region}# Get endpoint URL (wait for state: Active, ~5 min first time)
aws lambda-web get-web-function-endpoint --function-name my-app --endpoint-name default --region {region}
# curl the domainName from the responseThe steps above get a function serving. Before it takes real traffic, set up
observability: confirm a CloudTrail trail is enabled in the account so control-plane
calls (CreateWebFunction, CreateWebFunctionRevision, UpdateWebFunctionEndpoint,
DeleteWebFunction) are audited, and add a CloudWatch alarm on endpoint error rate so
regressions surface before a traffic shift. See
observability.md (opens in a new tab) for log configuration, alarms and multi-region
log centralization.
deploy sets up the bucket, role and endpoint above for you. Choose endpoint auth first. deploy creates a public (ApplicationManaged) endpoint unless
you pass --auth-type IamAuth, and anyone with a public URL can call it. Ask the user which they
want before running either command below; see iam-and-security.md (opens in a new tab) for what a
public endpoint needs.
aws lambda-web help # not recognised? update the AWS CLI (see deployment.md)
aws lambda-web deploy --name my-app --hello-world --auth-type IamAuth --region {region} # internal (SigV4 callers only)
aws lambda-web deploy --name my-app --hello-world --region {region} # public, only if the user chose it--hello-world writes a zero-dependency TypeScript HTTP server into ./my-app (Node runs it
directly, with no build step), creates the function, a code bucket, an execution role and an
endpoint named dev, and prints the URL. Edit the code, then ship each change with:
cd my-app && aws lambda-web deploy --name my-app --code . --region {region}For an app you already have, install its dependencies and deploy the directory; see deployment.md (opens in a new tab) for every flag:
npm ci --omit=dev
aws lambda-web deploy --name my-app --code . --create --auth-type {auth-type} --region {region} # IamAuth or ApplicationManaged, as the user chose| Symptom | Fix |
|---|---|
aws lambda-web not found | Update to the latest AWS CLI version (see deployment.md) |
| Stuck in Pending | Trust policy must be lambda.amazonaws.com |
| ParamValidation | Use camelCase: buildConfig, codeConfig |
| AuthType error | Use ApplicationManaged (not NONE) |
| 500 no logs | Entry point must be index.js (not .mjs) |
| 500 with ECONNREFUSED 3000 | Bind the host and port from AWS_LAMBDA_HTTP_ENDPOINT |
| 500 on create-revision | Caller needs s3:GetObject on code bucket |