zappa 0.61.4
Server-less Python Web Services for AWS Lambda and API Gateway
License: MIT License
Requires Python: >=3.9

<p align="center">
  <img src="http://i.imgur.com/oePnHJn.jpg" alt="Zappa Rocks!"/>
</p>

## Zappa - Serverless Python

[![CI](https://github.com/zappa/Zappa/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/zappa/Zappa/actions/workflows/ci.yml)
[![Coverage](https://img.shields.io/coveralls/zappa/Zappa.svg)](https://coveralls.io/github/zappa/Zappa)
[![PyPI](https://img.shields.io/pypi/v/Zappa.svg)](https://pypi.python.org/pypi/zappa)
[![Slack](https://img.shields.io/badge/chat-slack-ff69b4.svg)](https://zappateam.slack.com/)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [About](#about)
- [Installation and Configuration](#installation-and-configuration)
  - [Running the Initial Setup / Settings](#running-the-initial-setup--settings)
  - [Alternative: Generating Settings via CLI](#alternative-generating-settings-via-cli)
    - [Nested JSON Configurations](#nested-json-configurations)
- [Basic Usage](#basic-usage)
  - [Initial Deployments](#initial-deployments)
  - [Updates](#updates)
    - [Docker Workflows](#docker-workflows)
  - [Rollback](#rollback)
  - [Scheduling](#scheduling)
    - [Advanced Scheduling](#advanced-scheduling)
      - [Multiple Expressions](#multiple-expressions)
      - [Disabled Event](#disabled-event)
  - [Undeploy](#undeploy)
  - [Package](#package)
    - [How Zappa Makes Packages](#how-zappa-makes-packages)
  - [Template](#template)
  - [Status](#status)
  - [Tailing Logs](#tailing-logs)
  - [Remote Function Invocation](#remote-function-invocation)
  - [Django Management Commands](#django-management-commands)
  - [SSL Certification](#ssl-certification)
    - [Deploying to a Domain With AWS Certificate Manager](#deploying-to-a-domain-with-aws-certificate-manager)
    - [Deploying to a Domain With a Let's Encrypt Certificate (DNS Auth)](#deploying-to-a-domain-with-a-lets-encrypt-certificate-dns-auth)
    - [Deploying to a Domain With a Let's Encrypt Certificate (HTTP Auth)](#deploying-to-a-domain-with-a-lets-encrypt-certificate-http-auth)
    - [Deploying to a Domain With Your Own SSL Certs](#deploying-to-a-domain-with-your-own-ssl-certs)
- [Executing in Response to AWS Events](#executing-in-response-to-aws-events)
- [Asynchronous Task Execution](#asynchronous-task-execution)
  - [Catching Exceptions](#catching-exceptions)
  - [Task Sources](#task-sources)
  - [Direct Invocation](#direct-invocation)
  - [Remote Invocations](#remote-invocations)
  - [Restrictions](#restrictions)
  - [Running Tasks in a VPC](#running-tasks-in-a-vpc)
  - [Responses](#responses)
- [Advanced Settings](#advanced-settings)
    - [YAML Settings](#yaml-settings)
- [Advanced Usage](#advanced-usage)
  - [Keeping The Server Warm](#keeping-the-server-warm)
    - [Serving Static Files / Binary Uploads](#serving-static-files--binary-uploads)
  - [Enabling CORS](#enabling-cors)
  - [Large Projects](#large-projects)
  - [Enabling Bash Completion](#enabling-bash-completion)
  - [Enabling Secure Endpoints on API Gateway](#enabling-secure-endpoints-on-api-gateway)
    - [API Key](#api-key)
    - [IAM Policy](#iam-policy)
    - [API Gateway Lambda Authorizers](#api-gateway-lambda-authorizers)
    - [Cognito User Pool Authorizer](#cognito-user-pool-authorizer)
    - [API Gateway Resource Policy](#api-gateway-resource-policy)
  - [Setting Environment Variables](#setting-environment-variables)
    - [Local Environment Variables](#local-environment-variables)
    - [Remote AWS Environment Variables](#remote-aws-environment-variables)
    - [Remote Environment Variables](#remote-environment-variables)
    - [Remote Environment Variables (via an S3 file)](#remote-environment-variables-via-an-s3-file)
  - [API Gateway Context Variables](#api-gateway-context-variables)
  - [Catching Unhandled Exceptions](#catching-unhandled-exceptions)
  - [Using Custom AWS IAM Roles and Policies](#using-custom-aws-iam-roles-and-policies)
    - [Custom AWS IAM Roles and Policies for Deployment](#custom-aws-iam-roles-and-policies-for-deployment)
    - [Custom AWS IAM Roles and Policies for Execution](#custom-aws-iam-roles-and-policies-for-execution)
  - [AWS X-Ray](#aws-x-ray)
  - [Globally Available Server-less Architectures](#globally-available-server-less-architectures)
  - [Raising AWS Service Limits](#raising-aws-service-limits)
  - [Dead Letter Queues](#dead-letter-queues)
  - [Elastic File System (EFS)](#elastic-file-system-efs)
    - [Basic Configuration](#basic-configuration)
    - [Configuration Options](#configuration-options)
    - [Security Group Configuration](#security-group-configuration)
    - [Accessing EFS in Your Code](#accessing-efs-in-your-code)
    - [Notes](#notes)
  - [Unique Package ID](#unique-package-id)
  - [Application Load Balancer Event Source](#application-load-balancer-event-source)
  - [Endpoint Configuration](#endpoint-configuration)
    - [Example Private API Gateway configuration](#example-private-api-gateway-configuration)
  - [Cold Starts (Experimental)](#cold-starts-experimental)
  - [Lambda Test Console Usage](#lambda-test-console-usage)
    - [`raw_command`](#raw_command)
    - [`manage`](#manage)
- [Zappa Guides](#zappa-guides)
- [Zappa in the Press](#zappa-in-the-press)
- [Sites Using Zappa](#sites-using-zappa)
- [Related Projects](#related-projects)
- [Hacks](#hacks)
- [Contributing](#contributing)
    - [Using a Local Repo](#using-a-local-repo)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## About

<p align="center">
  <a href="https://htmlpreview.github.io/?https://raw.githubusercontent.com/Miserlou/Talks/master/serverless-sf/big.quickstart.html"><img src="http://i.imgur.com/c23kDNT.png?1" alt="Zappa Slides"/></a>
</p>
<p align="center">
  <i>In a hurry? Click to see <a href="https://htmlpreview.github.io/?https://raw.githubusercontent.com/Miserlou/Talks/master/serverless-sf/big.quickstart.html">(now slightly out-dated) slides from Serverless SF</a>!</i>
</p>

**Zappa** makes it super easy to build and deploy server-less, event-driven Python applications (including, but not limited to, WSGI web apps) on AWS Lambda + API Gateway. Think of it as "serverless" web hosting for your Python apps. That means **infinite scaling**, **zero downtime**, **zero maintenance** - and at a fraction of the cost of your current deployments!

If you've got a Python web app (including Django and Flask apps), it's as easy as:

```
$ pip install zappa
$ zappa init
$ zappa deploy
```

and now you're server-less! _Wow!_

> What do you mean "serverless"?

Okay, so there still is a server - but it only has a _40 millisecond_ life cycle! Serverless in this case means **"without any permanent infrastructure."**

With a traditional HTTP server, the server is online 24/7, processing requests one by one as they come in. If the queue of incoming requests grows too large, some requests will time out. With Zappa, **each request is given its own virtual HTTP "server"** by Amazon API Gateway. AWS handles the horizontal scaling automatically, so no requests ever time out. Each request then calls your application from a memory cache in AWS Lambda and returns the response via Python's WSGI interface. After your app returns, the "server" dies.

Better still, with Zappa you only pay for the milliseconds of server time that you use, so it's many **orders of magnitude cheaper** than VPS/PaaS hosts like Linode or Heroku - and in most cases, it's completely free. Plus, there's no need to worry about load balancing or keeping servers online ever again.

It's great for deploying serverless microservices with frameworks like Flask and Bottle, and for hosting larger web apps and CMSes with Django. Or, you can use any WSGI-compatible app you like! You **probably don't need to change your existing applications** to use it, and you're not locked into using it.

Zappa also lets you build hybrid event-driven applications that can scale to **trillions of events** a year with **no additional effort** on your part! You also get **free SSL certificates**, **global app deployment**, **API access management**, **automatic security policy generation**, **precompiled C-extensions**, **auto keep-warms**, **oversized Lambda packages**, and **many other exclusive features**!

And finally, Zappa is **super easy to use**. You can deploy your application with a single command out of the box!

**Awesome!**

<p align="center">
  <img src="http://i.imgur.com/f1PJxCQ.gif" alt="Zappa Demo Gif"/>
</p>

## Installation and Configuration

_Before you begin, make sure you are running Python 3.9/3.10/3.11/3.12/3.13/3.14 and you have a valid AWS account and your [AWS credentials file](https://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs) is properly installed._

**Zappa** can easily be installed through pip, like so:

    $ pip install zappa

Please note that Zappa _**must**_ be installed into your project's [virtual environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/). The virtual environment name should not be the same as the Zappa project name, as this may cause errors.

_(If you use [pyenv](https://github.com/yyuu/pyenv) and love to manage virtualenvs with **pyenv-virtualenv**, you just have to call `pyenv local [your_venv_name]` and it's ready. [Conda](http://conda.pydata.org/docs/) users should comment [here](https://github.com/Miserlou/Zappa/pull/108).)_

Next, you'll need to define your local and server-side settings.

### Running the Initial Setup / Settings

**Zappa** can automatically set up your deployment settings for you with the `init` command:

    $ zappa init

This will automatically detect your application type (Flask/Django - Pyramid users [see here](https://github.com/Miserlou/Zappa/issues/278#issuecomment-241917956)) and help you define your deployment configuration settings. Once you finish initialization, you'll have a file named _zappa_settings.json_ in your project directory defining your basic deployment settings. It will probably look something like this for most WSGI apps:

```javascript
{
    // The name of your stage
    "dev": {
        // The name of your S3 bucket
        "s3_bucket": "lambda",

        // The modular python path to your WSGI application function.
        // In Flask and Bottle, this is your 'app' object.
        // Flask (your_module.py):
        // app = Flask()
        // Bottle (your_module.py):
        // app = bottle.default_app()
        "app_function": "your_module.app"
    }
}
```

or for Django:

```javascript
{
    "dev": { // The name of your stage
       "s3_bucket": "lambda", // The name of your S3 bucket
       "django_settings": "your_project.settings" // The python path to your Django settings.
    }
}
```

_Psst: If you're deploying a Django application with Zappa for the first time, you might want to read Edgar Roman's [Django Zappa Guide](https://edgarroman.github.io/zappa-django-guide/)._

You can define as many stages as your like - we recommend having _dev_, _staging_, and _production_.

### Alternative: Generating Settings via CLI

Instead of using the interactive `init` command, you can also generate your `zappa_settings.json` programmatically using the `settings` command with environment variables and command-line arguments:

    $ zappa settings --stage dev

This generates a basic settings file with defaults. You can customize it using `--config` arguments or `ZAPPA_` environment variables:

> Using command-line arguments

```bash
$ zappa settings --stage production \
    --config project_name=myapp \
    --config memory_size=1024 \
    --config timeout_seconds=60
```

> Using environment variables

```bash
$ export ZAPPA_PROJECT_NAME=myapp
$ export ZAPPA_MEMORY_SIZE=1024
$ zappa settings --stage production
```

> Command-line arguments override environment variables

```bash
$ export ZAPPA_MEMORY_SIZE=512
$ zappa settings --config memory_size=2048  # Uses 2048, not 512
```

#### Nested JSON Configurations

The `settings` command supports complex nested JSON structures for advanced configurations like CORS options, VPC settings, and environment variables:

> Configure CORS with nested JSON

```bash
$ zappa settings --stage production \
    --config 'cors_options={"allowedOrigins":["*"],"allowedMethods":["GET","POST","PUT"]}'
```

> Configure VPC settings

```bash
$ zappa settings --stage production \
    --config 'vpc_config={"SubnetIds":["subnet-123","subnet-456"],"SecurityGroupIds":["sg-789"]}'
```

> Configure environment variables

```bash
$ zappa settings --stage production \
    --config 'environment_variables={"DATABASE_URL":"postgres://...","API_KEY":"secret"}'
```

> Configure Lambda layers

```bash
$ zappa settings --stage production \
    --config 'layers=["arn:aws:lambda:us-east-1:123:layer:mylayer:1","arn:aws:lambda:us-east-1:123:layer:another:2"]'
```

You can mix primitive values with complex nested structures:

```bash
$ zappa settings --stage production \
    --config project_name=myapp \
    --config memory_size=1024 \
    --config binary_support=true \
    --config 'cors_options={"allowedOrigins":["https://example.com"]}' \
    --config 'environment_variables={"DB_HOST":"localhost","DB_PORT":"5432"}'
```

The same nested JSON syntax works with environment variables:

```bash
$ export ZAPPA_CORS_OPTIONS='{"allowedOrigins":["*"],"allowedMethods":["GET","POST"]}'
$ export ZAPPA_VPC_CONFIG='{"SubnetIds":["subnet-1","subnet-2"],"SecurityGroupIds":["sg-1"]}'
$ zappa settings --stage production
```

Now, you're ready to deploy!

## Basic Usage

### Initial Deployments

Once your settings are configured, you can package and deploy your application to a stage called "production" with a single command:

    $ zappa deploy production
    Deploying..
    Your application is now live at: https://7k6anj0k99.execute-api.us-east-1.amazonaws.com/production

And now your app is **live!** How cool is that?!

To explain what's going on, when you call `deploy`, Zappa will automatically package up your application and local virtual environment into a Lambda-compatible archive, replace any dependencies with versions with wheels compatible with lambda, set up the function handler and necessary WSGI Middleware, upload the archive to S3, create and manage the necessary Amazon IAM policies and roles, register it as a new Lambda function, create a new API Gateway resource, create WSGI-compatible routes for it, link it to the new Lambda function, and finally delete the archive from your S3 bucket. Handy!

Be aware that the default IAM role and policy created for executing Lambda applies a liberal set of permissions.
These are most likely not appropriate for production deployment of important applications. See the section
[Custom AWS IAM Roles and Policies for Execution](#custom-aws-iam-roles-and-policies-for-execution) for more detail.

### Updates

If your application has already been deployed and you only need to upload new Python code, but not touch the underlying routes, you can simply:

    $ zappa update production
    Updating..
    Your application is now live at: https://7k6anj0k99.execute-api.us-east-1.amazonaws.com/production

This creates a new archive, uploads it to S3 and updates the Lambda function to use the new code, but doesn't touch the API Gateway routes.

#### Docker Workflows

In [version 0.53.0](https://github.com/zappa/Zappa/blob/master/CHANGELOG.md), support was added to deploy & update Lambda functions using Docker.

You can specify an ECR image using the `--docker-image-uri` option to the zappa command on `deploy` and `update`.
Zappa expects that the image is built and pushed to a Amazon ECR repository.

Deploy Example:

    $ zappa deploy --docker-image-uri {AWS ACCOUNT ID}.dkr.ecr.{REGION}.amazonaws.com/{REPOSITORY NAME}:latest

Update Example:

    $ zappa update --docker-image-uri {AWS ACCOUNT ID}.dkr.ecr.{REGION}.amazonaws.com/{REPOSITORY NAME}:latest

Refer to [the blog post](https://ianwhitestone.work/zappa-serverless-docker/) for more details about how to leverage this functionality, and when you may want to.

If you are using a custom Docker image for your Lambda runtime (e.g. if you want to use a newer version of Python that is not yet supported by Lambda out of the box) and you would like to bypass the Python version check, you can set an environment variable to do so:

    $ export ZAPPA_RUNNING_IN_DOCKER=True

You can also add this to your Dockerfile like this:

```
ENV ZAPPA_RUNNING_IN_DOCKER=True
```

### Rollback

You can also `rollback` the deployed code to a previous version by supplying the number of revisions to return to. For instance, to rollback to the version deployed 3 versions ago:

    $ zappa rollback production -n 3

### Scheduling

Zappa can be used to easily schedule functions to occur on regular intervals. This provides a much nicer, maintenance-free alternative to Celery!
These functions will be packaged and deployed along with your `app_function` and called from the handler automatically.
Just list your functions and the expression to schedule them using [cron or rate syntax](http://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html) in your _zappa_settings.json_ file:

**Note:** `function` path cannot exceed 64 characters.

```javascript
{
    "production": {
       ...
       "events": [{
           "function": "your_module.your_function", // The function to execute
           "expression": "rate(1 minute)" // When to execute it (in cron or rate format)
       }],
       ...
    }
}
```

And then:

    $ zappa schedule production

And now your function will execute every minute!

If you want to cancel these, you can simply use the `unschedule` command:

    $ zappa unschedule production

And now your scheduled event rules are deleted.

See the [example](example/) for more details.

#### Advanced Scheduling

##### Multiple Expressions

Sometimes a function needs multiple expressions to describe its schedule. To set multiple expressions, simply list your functions, and the list of expressions to schedule them using [cron or rate syntax](http://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html) in your _zappa_settings.json_ file:

```javascript
{
    "production": {
       ...
       "events": [{
           "function": "your_module.your_function", // The function to execute
           "expressions": ["cron(0 20-23 ? * SUN-THU *)", "cron(0 0-8 ? * MON-FRI *)"] // When to execute it (in cron or rate format)
       }],
       ...
    }
}
```

This can be used to deal with issues arising from the UTC timezone crossing midnight during business hours in your local timezone.

It should be noted that overlapping expressions will not throw a warning, and should be checked for, to prevent duplicate triggering of functions.

##### Disabled Event

Sometimes an event should be scheduled, yet disabled.
For example, perhaps an event should only run in your production environment, but not sandbox.
You may still want to deploy it to sandbox to ensure there is no issue with your expression(s) before deploying to production.

In this case, you can disable it from running by setting `enabled` to `false` in the event definition:

```javascript
{
    "sandbox": {
       ...
       "events": [{
           "function": "your_module.your_function", // The function to execute
           "expression": "rate(1 minute)", // When to execute it (in cron or rate format)
           "enabled": false
       }],
       ...
    }
}
```

### Undeploy

If you need to remove the API Gateway and Lambda function that you have previously published, you can simply:

    $ zappa undeploy production

You will be asked for confirmation before it executes.

If you enabled CloudWatch Logs for your API Gateway service and you don't
want to keep those logs, you can specify the `--remove-logs` argument to purge the logs for your API Gateway and your Lambda function:

    $ zappa undeploy production --remove-logs

### Package

If you want to build your application package without actually uploading and registering it as a Lambda function, you can use the `package` command:

    $ zappa package production

If you have a `zip` callback in your `callbacks` setting, this will also be invoked.

```javascript
{
    "production": { // The name of your stage
        "callbacks": {
            "zip": "my_app.zip_callback"// After creating the package
        }
    }
}
```

You can also specify the output filename of the package with `-o`:

    $ zappa package production -o my_awesome_package.zip

#### How Zappa Makes Packages

Zappa will automatically package your active virtual environment into a package which runs smoothly on AWS Lambda.

During this process, it will replace any local dependencies with AWS Lambda compatible versions. Dependencies are included in this order:

- Lambda-compatible `manylinux` wheels from a local cache
- Lambda-compatible `manylinux` wheels from PyPI
- Packages from the active virtual environment
- Packages from the local project directory

It also skips certain unnecessary files, and ignores any .py files if .pyc files are available.

In addition, Zappa will also automatically set the correct execution permissions, configure package settings, and create a unique, auditable package manifest file.

To further reduce the final package file size, you can:

- Set `slim_handler` to `True` to upload a small handler to Lambda and the rest of the package to S3. For more details, see the [merged pull request](https://github.com/Miserlou/Zappa/pull/548) and the [discussion in the original issue](https://github.com/Miserlou/Zappa/issues/510). See also: [Large Projects](#large-projects).
- Use the `exclude` or `exclude_glob` setting and provide a list of patterns to exclude from the archive. By default, Zappa will exclude Boto, because [it's already available in the Lambda execution environment](http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html).

### Template

Similarly to `package`, if you only want the API Gateway CloudFormation template, use the `template` command:

    $ zappa template production --l your-lambda-arn -r your-role-arn

Note that you must supply your own Lambda ARN and Role ARNs in this case, as they may not have been created for you.

You can get the JSON output directly with `--json`, and specify the output file with `--output`.

### Status

If you need to see the status of your deployment and event schedules, simply use the `status` command.

    $ zappa status production

### Tailing Logs

You can watch the logs of a deployment by calling the `tail` management command.

    $ zappa tail production

By default, this will show all log items. In addition to HTTP and other events, anything `print`ed to `stdout` or `stderr` will be shown in the logs.

You can use the argument `--http` to filter for HTTP requests, which will be in the Apache Common Log Format.

    $ zappa tail production --http

Similarly, you can do the inverse and only show non-HTTP events and log messages:

    $ zappa tail production --non-http

If you don't like the default log colors, you can turn them off with `--no-color`.

You can also limit the length of the tail with `--since`, which accepts a simple duration string:

    $ zappa tail production --since 4h # 4 hours
    $ zappa tail production --since 1m # 1 minute
    $ zappa tail production --since 1mm # 1 month

You can filter out the contents of the logs with `--filter`, like so:

    $ zappa tail production --http --filter "POST" # Only show POST HTTP requests

Note that this uses the [CloudWatch Logs filter syntax](http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html).

To tail logs without following (to exit immediately after displaying the end of the requested logs), pass `--disable-keep-open`:

    $ zappa tail production --since 1h --disable-keep-open

### Remote Function Invocation

You can execute any function in your application directly at any time by using the `invoke` command.

For instance, suppose you have a basic application in a file called "my_app.py", and you want to invoke a function in it called "my_function". Once your application is deployed, you can invoke that function at any time by calling:

    $ zappa invoke production my_app.my_function

Any remote print statements made and the value the function returned will then be printed to your local console. **Nifty!**

You can also invoke interpretable Python 3.9/3.10/3.11/3.12/3.13/3.14 strings directly by using `--raw`, like so:

    $ zappa invoke production "print(1 + 2 + 3)" --raw

For instance, it can come in handy if you want to create your first `superuser` on a RDS database running in a VPC (like Serverless Aurora):

    $ zappa invoke staging "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('username', 'email', 'password')" --raw

If you need to invoke a specific version of your function, you can use the --qualifier option to specify it.

    $ zappa invoke production my_app.my_function --qualifier 123

[Function aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) are also supported as qualifiers.

### Django Management Commands

As a convenience, Zappa can also invoke remote Django 'manage.py' commands with the `manage` command. For instance, to perform the basic Django status check:

    $ zappa manage production showmigrations admin

Obviously, this only works for Django projects which have their settings properly defined.

For commands which have their own arguments, you can also pass the command in as a string, like so:

    $ zappa manage production "shell --version"

As with `invoke`, a qualifier can be added to specify the version of your function that's used to execute the command.
This can be particularly important when running certain commands such as `migrate` directly after a new deployment:

    $ zappa manage production migrate admin --qualifier 123

Commands which require direct user input, such as `createsuperuser`, should be [replaced by commands](http://stackoverflow.com/a/26091252) which use `zappa invoke <env> --raw`.

For more Django integration, take a look at the [zappa-django-utils](https://github.com/Miserlou/zappa-django-utils) project.

### SSL Certification

Zappa can be deployed to custom domain names and subdomains with custom SSL certificates, Let's Encrypt certificates, and [AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) (ACM) certificates.

Currently, the easiest of these to use are the AWS Certificate Manager certificates, as they are free, self-renewing, and require the least amount of work.

Once configured as described below, all of these methods use the same command:

    $ zappa certify

When deploying from a CI/CD system, you can use:

    $ zappa certify --yes

to skip the confirmation prompt.

#### Deploying to a Domain With AWS Certificate Manager

Amazon provides their own free alternative to Let's Encrypt called [AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) (ACM). To use this service with Zappa:

1. Verify your domain in the AWS Certificate Manager console.
2. In the console, select the N. Virginia (us-east-1) region and request a certificate for your domain or subdomain (`sub.yourdomain.tld`), or request a wildcard domain (`*.yourdomain.tld`).
3. Copy the entire ARN of that certificate and place it in the Zappa setting `certificate_arn`.
4. Set your desired domain in the `domain` setting.
5. Call `$ zappa certify` to create and associate the API Gateway distribution using that certificate.

#### Deploying to a Domain With a Let's Encrypt Certificate (DNS Auth)

If you want to use Zappa on a domain with a free Let's Encrypt certificate using automatic Route 53 based DNS Authentication, you can follow [this handy guide](https://github.com/zappa/Zappa/blob/master/docs/domain_with_free_ssl_dns.md).

#### Deploying to a Domain With a Let's Encrypt Certificate (HTTP Auth)

If you want to use Zappa on a domain with a free Let's Encrypt certificate using HTTP Authentication, you can follow [this guide](https://github.com/zappa/Zappa/blob/master/docs/domain_with_free_ssl_http.md).

However, it's now far easier to use Route 53-based DNS authentication, which will allow you to use a Let's Encrypt certificate with a single `$ zappa certify` command.

#### Deploying to a Domain With Your Own SSL Certs

1. The first step is to create a custom domain and obtain your SSL cert / key / bundle.
2. Ensure you have set the `domain` setting within your Zappa settings JSON - this will avoid problems with the Base Path mapping between the Custom Domain and the API invoke URL, which gets the Stage Name appended in the URI
3. Add the paths to your SSL cert / key / bundle to the `certificate`, `certificate_key`, and `certificate_chain` settings, respectively, in your Zappa settings JSON
4. Set `route53_enabled` to `false` if you plan on using your own DNS provider, and not an AWS Route53 Hosted zone.
5. Deploy or update your app using Zappa
6. Run `$ zappa certify` to upload your certificates and register the custom domain name with your API gateway.

## Executing in Response to AWS Events

Similarly, you can have your functions execute in response to events that happen in the AWS ecosystem, such as S3 uploads, DynamoDB entries, Kinesis streams, SNS messages, and SQS queues.

In your _zappa_settings.json_ file, define your [event sources](http://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html) and the function you wish to execute. For instance, this will execute `your_module.process_upload_function` in response to new objects in your `my-bucket` S3 bucket. Note that `process_upload_function` must accept `event` and `context` parameters.

```javascript
{
    "production": {
       ...
       "events": [{
            "function": "your_module.process_upload_function",
            "event_source": {
                  "arn":  "arn:aws:s3:::my-bucket",
                  "events": [
                    "s3:ObjectCreated:*" // Supported event types: http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#supported-notification-event-types
                  ],
                  "key_filters": [{ // optional
                    "type": "suffix",
                    "value": "yourfile.json"
                  },
                  {
                    "type": "prefix",
                    "value": "prefix/for/your/object"
                  }]
               }
            }],
       ...
    }
}
```

And then:

    $ zappa schedule production

And now your function will execute every time a new upload appears in your bucket!

To access the key's information in your application context, you'll want `process_upload_function` to look something like this:

```python
import boto3
s3_client = boto3.client('s3')

def process_upload_function(event, context):
    """
    Process a file upload.
    """

    # Get the uploaded file's information
    bucket = event['Records'][0]['s3']['bucket']['name'] # Will be `my-bucket`
    key = event['Records'][0]['s3']['object']['key'] # Will be the file path of whatever file was uploaded.

    # Get the bytes from S3
    s3_client.download_file(bucket, key, '/tmp/' + key) # Download this file to writable tmp space.
    file_bytes = open('/tmp/' + key).read()
```

Similarly, for a [Simple Notification Service](https://aws.amazon.com/sns/) event:

```javascript
        "events": [
            {
                "function": "your_module.your_function",
                "event_source": {
                    "arn":  "arn:aws:sns:::your-event-topic-arn",
                    "events": [
                        "sns:Publish"
                    ]
                }
            }
        ]
```

Optionally you can add [SNS message filters](http://docs.aws.amazon.com/sns/latest/dg/message-filtering.html):

```javascript
        "events": [
            {
                "function": "your_module.your_function",
                "event_source": {
                    "arn":  "arn:aws:sns:::your-event-topic-arn",
                    "filters": {
                        "interests": ["python", "aws", "zappa"],
                        "version": ["1.0"]
                    },
                    ...
                }
            }
        ]
```

[DynamoDB](http://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) and [Kinesis](http://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html) are slightly different as it is not event based but pulling from a stream:

```javascript
       "events": [
           {
               "function": "replication.replicate_records",
               "event_source": {
                    "arn":  "arn:aws:dynamodb:us-east-1:1234554:table/YourTable/stream/2016-05-11T00:00:00.000",
                    "starting_position": "TRIM_HORIZON", // Supported values: TRIM_HORIZON, LATEST
                    "batch_size": 50, // Max: 1000
                    "enabled": true // Default is false
               }
           }
       ]
```

[SQS](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html) is also pulling messages from a stream. 
Read the [AWS Documentation](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html) carefully since Lambda calls the SQS DeleteMessage API on your behalf once your function completes successfully. 
By default, if your function encounters an error while processing a batch, all messages in that batch become visible in the queue again.

```javascript
       "events": [
           {
               "function": "your_module.process_messages",
               "event_source": {
                    "arn":  "arn:aws:sqs:us-east-1:12341234:your-queue-name-arn",
                    "batch_size": 10, // Maximum: 10 for FIFO and 10,000 for Standard. Use 1 to trigger immediate processing
                    "enabled": true // Default is false
               }
           }
       ]
```

For configuring Lex Bot's intent triggered events:

```javascript
    "bot_events": [
        {
            "function": "lexbot.handlers.book_appointment.handler",
            "event_source": {
                "arn": "arn:aws:lex:us-east-1:01234123123:intent:TestLexEventNames:$LATEST", // optional. In future it will be used to configure the intent
                "intent":"intentName", // name of the bot event configured
                "invocation_source":"DialogCodeHook", // either FulfillmentCodeHook or DialogCodeHook
            }
        }
    ]

```

Events can also take keyword arguments:

```javascript
       "events": [
            {
                "function": "your_module.your_recurring_function", // The function to execute
                "kwargs": {"key": "val", "key2": "val2"},  // Keyword arguments to pass. These are available in the event
                "expression": "rate(1 minute)" // When to execute it (in cron or rate format)
            }
       ]
```

To get the keyword arguments you will need to look inside the event dictionary:

```python
def your_recurring_function(event, context):
    my_kwargs = event.get("kwargs")  # dict of kwargs given in zappa_settings file

```

You can find more [example event sources here](http://docs.aws.amazon.com/lambda/latest/dg/eventsources.html).

## Asynchronous Task Execution

Zappa also now offers the ability to seamlessly execute functions asynchronously in a completely separate AWS Lambda instance!

For example, if you have a Flask API for ordering a pie, you can call your `bake` function seamlessly in a completely separate Lambda instance by using the `zappa.asynchronous.task` decorator like so:

```python
from flask import Flask
from zappa.asynchronous import task
app = Flask(__name__)

@task
def make_pie():
    """ This takes a long time! """
    ingredients = get_ingredients()
    pie = bake(ingredients)
    deliver(pie)

@app.route('/api/order/pie')
def order_pie():
    """ This returns immediately! """
    make_pie()
    return "Your pie is being made!"

```

And that's it! Your API response will return immediately, while the `make_pie` function executes in a completely different Lambda instance.

When calls to @task decorated functions or the zappa.asynchronous.run command occur outside of Lambda, such as your local dev environment,
the functions will execute immediately and locally. The zappa asynchronous functionality only works
when in the Lambda environment or when specifying [Remote Invocations](https://github.com/zappa/zappa#remote-invocations).

### Catching Exceptions

Putting a try..except block on an asynchronous task like this:

```python
@task
def make_pie():
    try:
        ingredients = get_ingredients()
        pie = bake(ingredients)
        deliver(pie)
    except Fault as error:
        """send an email"""
    ...
    return Response('Web services down', status=503)
```

will cause an email to be sent twice for the same error. See [asynchronous retries at AWS](https://docs.aws.amazon.com/lambda/latest/dg/retries-on-errors.html). To work around this side-effect, and have the fault handler execute only once, change the return value to:

```python
@task
def make_pie():
    try:
        """code block"""
    except Fault as error:
        """send an email"""
    ...
    return {} #or return True
```

### Task Sources

By default, this feature uses direct AWS Lambda invocation. You can instead use AWS Simple Notification Service as the task event source by using the `task_sns` decorator, like so:

```python
from zappa.asynchronous import task_sns
@task_sns
```

Using SNS also requires setting the following settings in your `zappa_settings`:

```javascript
{
  "dev": {
    ..
      "async_source": "sns", // Source of async tasks. Defaults to "lambda"
      "async_resources": true, // Create the SNS topic to use. Defaults to true.
    ..
    }
}
```

This will automatically create and subscribe to the SNS topic the code will use when you call the `zappa schedule` command.

Using SNS will also return a message ID in case you need to track your invocations.

### Direct Invocation

You can also use this functionality without a decorator by passing your function to `zappa.asynchronous.run`, like so:

```python
from zappa.asynchronous import run

run(your_function, args, kwargs) # Using Lambda
run(your_function, args, kwargs, service='sns') # Using SNS
```

### Remote Invocations

By default, Zappa will use lambda's current function name and current AWS region. If you wish to invoke a lambda with
a different function name/region or invoke your lambda from outside of lambda, you must specify the
`remote_aws_lambda_function_name` and `remote_aws_region` arguments so that the application knows which function and
region to use. For example, if some part of our pizza making application had to live on an EC2 instance, but we
wished to call the make_pie() function on its own Lambda instance, we would do it as follows:

```python
@task(remote_aws_lambda_function_name='pizza-pie-prod', remote_aws_region='us-east-1')
def make_pie():
   """ This takes a long time! """
   ingredients = get_ingredients()
   pie = bake(ingredients)
   deliver(pie)

```

If those task() parameters were not used, then EC2 would execute the function locally. These same
`remote_aws_lambda_function_name` and `remote_aws_region` arguments can be used on the zappa.asynchronous.run() function as well.

### Restrictions

The following restrictions to this feature apply:

- Functions must have a clean import path -- i.e. no closures, lambdas, or methods.
- `args` and `kwargs` must be JSON-serializable.
- The JSON-serialized arguments must be within the size limits for Lambda (256K) or SNS (256K) events.

All of this code is still backwards-compatible with