Help us shape the future of Go! Take the 2026 Go Developer Survey

caddylambdalicious

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

README

caddy-lambda-licious logo

caddy-lambda-licious

Caddy v2 plugin for dispatching requests to AWS Lambda.

Installation

Use the standard xcaddy tool to build a custom caddy binary that includes the plugin.

xcaddy build --with github.com/danmoz/caddy-lambda-licious

Usage

Minimal configuration

The Lambda function name is required, and an AWS region must be available either through the region setting or the AWS SDK's environment/shared configuration. By default, the plugin will forward events using the api_gateway_v2 event format.

:8080 {
  handle /services/* {
    lambda {
      function MyLambdaFunction
      region us-east-1
    }
  }
}
Full configuration
:8080 {
  handle /services/* {
    lambda {
      function MyLambdaFunction
      qualifier prod
      region us-east-1
      event_format api_gateway_v2
      timeout 10s
      max_body_size 1MB
      header_upstream X-Forwarded-Host {http.request.host}

      # Recommended for production: assume a dedicated IAM role
      role_arn arn:aws:iam::123456789012:role/LambdaInvoker
      external_id example-external-id
      session_name caddy-lambda-licious

      # Useful for local testing:
      # endpoint http://127.0.0.1:3001
    }
  }
}
Setting Description Default
function Lambda function name or ARN to invoke. (required)
region AWS region used for the Lambda client. (required if no SDK)
qualifier Lambda version number or alias to invoke. Unqualified function
event_format Lambda request and response contract. api_gateway_v2
timeout Max duration of a synchronous invocation. 10s
max_body_size Max request body size; Caddyfile accepts units. 4MB
header_upstream Header values added to the Lambda request. Not set
role_arn IAM role to assume before invoking Lambda. No role assumption
external_id External ID passed to STS AssumeRole. Not set
session_name Role session name passed to STS AssumeRole. AWS SDK default
endpoint Lambda API endpoint. AWS SDK endpoint

Configuration Tips

For production, prefer an IAM role attached to the Caddy runtime (EC2, ECS, etc.). Runtime roles provide short-lived, automatically rotated credentials without requiring long-lived secrets to be stored or managed.

If Caddy requires a separate permission set or needs to invoke Lambda functions in another AWS account, use role_arn to assume a dedicated role with only the required Lambda permissions.

For local development, the standard AWS SDK credential chain also supports environment variables and shared AWS configuration files. Avoid using these methods in production where a runtime role is available.

Lambda invocation uses Caddy's AWS identity. End-user authentication and authorization remain the application's responsibility; request headers such as Authorization are forwarded unchanged.

Lambda invocations are not automatically retried. If an invocation fails after AWS has accepted the request, Caddy will be unable to determine whether the Lambda function executed successfully. Retrying in this situation could result in duplicate invocations.

Be careful when increasing max_body_size. AWS Lambda limits synchronous invocation payloads to 6 MB, and this limit applies to the complete serialized event sent to Lambda, not just the HTTP request body. Binary request bodies are base64-encoded, increasing their size by approximately 33%, with headers and the event envelope adding further overhead.

The default 4 MiB limit leaves some headroom, but unusually large headers may reduce the maximum safe body size. If the serialized Lambda event exceeds the 6 MB limit, caddy-lambda-licious rejects the request with HTTP 413 Payload Too Large.

Response Codes

Status Meaning
413 Request body exceeds max_body_size (4 MiB by default).
500 Malformed Lambda responses, invalid response bodies, and other adapter errors.
502 Lambda invocation failed for a reason other than timeout or throttling, including a Lambda function error.
503 AWS rejected the invocation with TooManyRequestsException.
504 Lambda invocation exceeded the configured timeout.

If the client cancels the request during invocation, the handler returns without writing a response or invoking Caddy's error handlers.

The plugin does not generate application statuses such as 400, 401, 403, or 404; Lambda responses should supply those statuses when appropriate.

IAM permissions

Caddy invokes Lambda with SigV4 using credentials resolved from the AWS SDK credential chain or an assumed role. Grant the IAM principal represented by those credentials permission to invoke the target function or alias:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:MyLambdaFunction"
    }
  ]
}

Use the qualified function or alias ARN as Resource when invocation is restricted to a specific version or alias. If role_arn is configured, the source credentials also need sts:AssumeRole permission for that target role, and the target role needs the lambda:InvokeFunction permission above.

For cross-account access, choose one of these patterns:

  • Direct invocation: add the IAM principal represented by the configured credentials as a principal in the Lambda function's resource-based policy, and grant that principal lambda:InvokeFunction on the function.
  • Assumed role: grant the source credentials sts:AssumeRole on the target role, trust the source principal in the target role's trust policy, and grant the target role lambda:InvokeFunction on the function. In this pattern, the Lambda resource policy is not required because the assumed role belongs to the target account.

Event formats

The event_format setting selects both the request event and response format.

Value Status Contract
httpjson Available HTTPJSON-REQ and HTTPJSON-REP envelopes.
api_gateway_v2 Default API Gateway HTTP API payload version 2.0.
api_gateway_v1 Available API Gateway REST/proxy payload version 1.0.
alb Planned Application Load Balancer Lambda event.
function_url Planned Lambda Function URL event.
lambda_at_edge Planned CloudFront Lambda@Edge event.
HTTPJSON

The httpjson format sends a JSON object with a type of HTTPJSON-REQ, request metadata in meta, and the request body in body. Binary request bodies use base64 encoding and set bodyEncoding to base64. The Lambda function should return a JSON object with a type of HTTPJSON-REP, optional response metadata in meta, and the response body in body. Response metadata can set the HTTP status and headers; bodyEncoding can be set to base64 for binary response bodies.

API Gateway v1

Set event_format api_gateway_v1 for the API Gateway REST API Lambda proxy contract. Requests include httpMethod, the decoded path, headers, multiValueHeaders, queryStringParameters, and multiValueQueryStringParameters. The single-value maps contain the last value; the multi-value maps preserve repeated values. Cookies stay in the headers.

The adapter uses a /{proxy+} resource with a proxy path parameter (or / for the root), stage $default, and no stage variables. The request context includes the method, path, protocol, domain, request ID, timestamps, and client IP and user agent in identity. Paths are forwarded without trimming a base path. API Gateway account, authorization, and deployment metadata are not synthesized.

Responses use statusCode, headers, multiValueHeaders, body, and isBase64Encoded. Response headers are merged case-insensitively; a value present in both header maps is emitted once. Use multiValueHeaders for multiple Set-Cookie values. Binary bodies use base64 with isBase64Encoded: true; requests with no content type and a nonempty body also use base64, as in v2.

API Gateway v2

For API Gateway v2 events, request headers and duplicate query parameters use API Gateway's comma-joined representation, while cookies are provided through the cookies list. The original path and query string are preserved in rawPath and rawQueryString.

Binary request bodies are base64-encoded and set isBase64Encoded to true; empty and text bodies are not base64-encoded.

Responses use the standard statusCode, headers, cookies, body, and isBase64Encoded fields. Each response cookie is emitted as a separate Set-Cookie header.

The API Gateway v2 adapter maps Caddy's request path directly to rawPath; it does not trim a base path. AWS invocation errors (except client cancellations), Lambda function errors, timeouts, throttling, and malformed responses are returned as Caddy handler errors.

Every invocation has a request ID. If the incoming request includes an X-Request-ID header, its value is preserved; otherwise, caddy-lambda-licious generates a UUID matching the format used by AWS API Gateway. The request ID is used consistently in requestContext.requestId and structured logs, and is returned to the client in the X-Request-ID response header.

Logging

HTTP access logging remains Caddy's responsibility. This module does not log credentials, headers, or request/response bodies.

Successful Lambda invocations log their function name, duration, and request ID at DEBUG. Invocations canceled by the client are also logged at DEBUG and skip normal HTTP error handling. Throttling is logged at WARN; other invocation failures, including timeouts, are logged at ERROR. Failed invocations include the contextual error and are returned to Caddy for normal HTTP error handling, so Caddy may also log the resulting 5xx response.

Response body write failures are logged at WARN as "aborting with incomplete response" and abort the response with http.ErrAbortHandler.

Development

PRs and issues/bug reports are welcome!

Go 1.26 or newer is required.

If you'd like to develop locally, we use mise commands to lint, format, and test the code.

mise lint
mise format
mise test
mise e2e

Credits

This project is a fork of floj/caddy-awslambda, which is itself a port of coopernurse/caddy-awslambda, based on a fork of of abiosoft/caddy-exec.

Many thanks to those authors and other contributors for their great contributions to open source, without whom this project would not be possible.

License

Apache 2

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIGatewayV1Identity added in v1.0.2

type APIGatewayV1Identity struct {
	SourceIP  string `json:"sourceIp"`
	UserAgent string `json:"userAgent"`
}

type APIGatewayV1Request added in v1.0.2

type APIGatewayV1Request struct {
	Resource                        string                     `json:"resource"`
	Path                            string                     `json:"path"`
	HTTPMethod                      string                     `json:"httpMethod"`
	Headers                         map[string]string          `json:"headers"`
	MultiValueHeaders               map[string][]string        `json:"multiValueHeaders"`
	QueryStringParameters           map[string]string          `json:"queryStringParameters"`
	MultiValueQueryStringParameters map[string][]string        `json:"multiValueQueryStringParameters"`
	PathParameters                  map[string]string          `json:"pathParameters"`
	StageVariables                  map[string]string          `json:"stageVariables"`
	RequestContext                  APIGatewayV1RequestContext `json:"requestContext"`
	Body                            string                     `json:"body"`
	IsBase64Encoded                 bool                       `json:"isBase64Encoded"`
}

APIGatewayV1Request is the API Gateway REST API Lambda proxy event.

type APIGatewayV1RequestContext added in v1.0.2

type APIGatewayV1RequestContext struct {
	ResourcePath     string               `json:"resourcePath"`
	HTTPMethod       string               `json:"httpMethod"`
	Path             string               `json:"path"`
	Protocol         string               `json:"protocol"`
	RequestID        string               `json:"requestId"`
	RequestTime      string               `json:"requestTime"`
	RequestTimeEpoch int64                `json:"requestTimeEpoch"`
	DomainName       string               `json:"domainName"`
	Stage            string               `json:"stage"`
	Identity         APIGatewayV1Identity `json:"identity"`
}

type APIGatewayV1Response added in v1.0.2

type APIGatewayV1Response struct {
	StatusCode        int                 `json:"statusCode"`
	Headers           map[string]string   `json:"headers"`
	MultiValueHeaders map[string][]string `json:"multiValueHeaders"`
	Body              string              `json:"body"`
	IsBase64Encoded   bool                `json:"isBase64Encoded"`
}

APIGatewayV1Response is the API Gateway REST API Lambda proxy response.

type APIGatewayV2HTTPContext

type APIGatewayV2HTTPContext struct {
	Method    string `json:"method"`
	Path      string `json:"path"`
	Protocol  string `json:"protocol"`
	SourceIP  string `json:"sourceIp"`
	UserAgent string `json:"userAgent"`
}

type APIGatewayV2Request

type APIGatewayV2Request struct {
	Version               string                     `json:"version"`
	RouteKey              string                     `json:"routeKey"`
	RawPath               string                     `json:"rawPath"`
	RawQueryString        string                     `json:"rawQueryString"`
	Headers               map[string]string          `json:"headers"`
	Cookies               []string                   `json:"cookies,omitempty"`
	QueryStringParameters map[string]string          `json:"queryStringParameters,omitempty"`
	RequestContext        APIGatewayV2RequestContext `json:"requestContext"`
	Body                  string                     `json:"body,omitempty"`
	IsBase64Encoded       bool                       `json:"isBase64Encoded"`
}

APIGatewayV2Request is the HTTP API payload format consumed by Mangum.

type APIGatewayV2RequestContext

type APIGatewayV2RequestContext struct {
	RequestID  string                  `json:"requestId"`
	TimeEpoch  int64                   `json:"timeEpoch"`
	DomainName string                  `json:"domainName"`
	Stage      string                  `json:"stage"`
	HTTP       APIGatewayV2HTTPContext `json:"http"`
}

type APIGatewayV2Response

type APIGatewayV2Response struct {
	StatusCode      int               `json:"statusCode"`
	Headers         map[string]string `json:"headers"`
	Cookies         []string          `json:"cookies"`
	Body            string            `json:"body"`
	IsBase64Encoded bool              `json:"isBase64Encoded"`
}

APIGatewayV2Response is the response format emitted by Mangum.

type Lambda

type Lambda struct {
	FunctionName    string              `json:"function,omitempty"`
	Qualifier       string              `json:"qualifier,omitempty"`
	Endpoint        string              `json:"endpoint,omitempty"`
	Region          string              `json:"region,omitempty"`
	EventFormat     string              `json:"event_format,omitempty"`
	Timeout         caddy.Duration      `json:"timeout,omitempty"`
	MaxBodySize     int64               `json:"max_body_size,omitempty"`
	RoleARN         string              `json:"role_arn,omitempty"`
	ExternalID      string              `json:"external_id,omitempty"`
	SessionName     string              `json:"session_name,omitempty"`
	UpstreamHeaders map[string][]string `json:"header_upstream,omitempty"`
	// contains filtered or unexported fields
}

Lambda implements an HTTP handler that invokes a Lambda function.

func (*Lambda) CaddyModule

func (*Lambda) CaddyModule() caddy.ModuleInfo

CaddyModule returns the Caddy module information.

func (*Lambda) Provision

func (m *Lambda) Provision(ctx caddy.Context) error

Provision implements caddy.Provisioner.

func (*Lambda) ServeHTTP

func (m *Lambda) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error

ServeHTTP implements caddyhttp.MiddlewareHandler.

This is a terminal handler: it writes the response directly and never calls next, so subsequent handlers in a route chain are not executed.

func (*Lambda) UnmarshalCaddyfile

func (m *Lambda) UnmarshalCaddyfile(d *caddyfile.Dispenser) error

UnmarshalCaddyfile configures the global directive from Caddyfile. Syntax:

lambda [<matcher>] {
    function <function name>
    qualifier <version or alias>
    endpoint <url>
    region <region>
    event_format <api_gateway_v1|api_gateway_v2|httpjson>
    timeout  <duration>
    max_body_size <bytes>
    role_arn <role ARN>
    external_id <external ID>
    session_name <session name>
    header_upstream <header> <value>
}

func (*Lambda) Validate

func (m *Lambda) Validate() error

Validate implements caddy.Validator.

type Reply

type Reply struct {
	// Must be set to the constant "HTTPJSON-REP"
	Type string `json:"type"`
	// Reply metadata. If omitted, a default 200 status with empty headers will be used.
	Meta *ReplyMeta `json:"meta"`
	// Response body
	Body string `json:"body"`
	// Encoding of Body - Valid values: "", "base64"
	BodyEncoding string `json:"bodyEncoding"`
}

Reply encapsulates the response from a Lambda invocation. AWS Lambda functions should return a JSON object that matches this format.

type ReplyMeta

type ReplyMeta struct {
	// HTTP status code (e.g. 200 or 404)
	Status int `json:"status"`
	// HTTP response headers
	Headers map[string][]string `json:"headers"`
}

ReplyMeta encapsulates HTTP response metadata that the lambda function wishes Caddy to set on the HTTP response.

*NOTE* that header values must be encoded as string arrays

type Request

type Request struct {
	// Set to the constant "HTTPJSON-REQ"
	Type string `json:"type"`
	// Metadata about the HTTP request
	Meta *RequestMeta `json:"meta"`
	// HTTP request body (may be empty)
	Body string `json:"body"`
	// Encoding of Body - Valid values: "", "base64"
	BodyEncoding string `json:"bodyEncoding"`
}

Request represents a single HTTP request. It will be serialized as JSON and sent to the AWS Lambda function as the function payload.

type RequestMeta

type RequestMeta struct {
	// HTTP method used by client (e.g. GET or POST)
	Method string `json:"method"`

	// Path portion of URL without the query string
	Path string `json:"path"`

	// Query string (without '?')
	Query string `json:"query"`

	// Host field from net/http Request, which may be of the form host:port
	Host string `json:"host"`

	// Proto field from net/http Request, for example "HTTP/1.1"
	Proto string `json:"proto"`

	// HTTP request headers
	Headers map[string][]string `json:"headers"`
}

RequestMeta represents HTTP metadata present on the request

Directories

Path Synopsis
test
e2e/caddy command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL