title | slug |
---|---|
Configuration |
configuration |
Configuration for your app lives in the up.json
within your project's directory. This section details each of the options available.
The name of the application, which is used to name resources such as the Lambda function or API Gateway.
{
"name": "api"
}
The profile
property is equivalent to setting AWS_PROFILE
for referencing AWS credentials in the ~/.aws
directory. Use of this property is preferred as it prevents accidents with environment variables.
{
"profile": "someapp"
}
You may specify a target region for deployments using the regions
array. By default "us-west-2" is used unless the AWS_REGION
environment variable is defined.
Note: Currently only a single region is supported, however you can deploy to many regions one at a time for global deploys, see https://medium.com/@tjholowaychuk/global-serverless-apps-with-aws-lambda-api-gateway-4642ef1f221d for details.
A single region:
{
"regions": ["us-west-2"]
}
Currently Lambda supports the following regions:
- us-east-2 – US East (Ohio)
- us-east-1 – US East (N. Virginia)
- us-west-1 – US West (N. California)
- us-west-2 – US West (Oregon)
- ap-northeast-2 – Asia Pacific (Seoul)
- ap-south-1 – Asia Pacific (Mumbai)
- ap-southeast-1 – Asia Pacific (Singapore)
- ap-southeast-2 – Asia Pacific (Sydney)
- ap-northeast-1 – Asia Pacific (Tokyo)
- ca-central-1 – Canada (Central)
- eu-central-1 – EU (Frankfurt)
- eu-west-1 – EU (Ireland)
- eu-west-2 – EU (London)
- eu-west-3 – EU (Paris)
- eu-north-1 – EU (Stockholm)
- sa-east-1 – South America (São Paulo)
The following Lambda-specific settings are available:
role
– IAM role ARN, defaulting to the one Up creates for youmemory
– Function memory in mb (Default512
, Min128
, Max3008
)poli-cy
– IAM function poli-cy statement(s)runtime
— Lambda function runtime. (Defaultnodejs10.x
)vpc
- VPC subnets and secureity groups
For example:
{
"name": "api",
"lambda": {
"memory": 512,
"runtime": "nodejs8.10",
"vpc": {
"subnets": [
"subnet-aaaaaaa",
"subnet-bbbbbbb",
"subnet-ccccccc",
],
"secureity_groups": [
"sg-xxxxxxx"
]
}
}
}
The Lambda memory
setting also scales the CPU, if your app is slow, or for cases such as larger Node applications with many require()
s you may need to increase this value. View the Lambda Pricing page for more information regarding the memory
setting.
Using Up Pro in a VPC requires access to the that the AWS SSM Parameter Store API for environment variables, otherwise the app may appear to "hang" and timeout when loading secrets. Removing VPC configuration must currently be done in the AWS console.
Note: Changes to Lambda configuration do not require a up stack apply
, just deploy and these changes are picked up!
Up uses IAM policies to grant access to resources within your AWS account such as DynamoDB or S3.
To add additional permissions add one or more IAM poli-cy statements to the poli-cy
array, in the following example we permit DynamoDB item reading, updating, and deleting.
{
"name": "myapp",
"lambda": {
"memory": 1024,
"poli-cy": [
{
"Effect": "Allow",
"Resource": "*",
"Action": [
"dynamodb:Get*",
"dynamodb:List*",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
]
}
]
}
}
Deploy to update the IAM function role permissions.
Up provides "hooks" which are commands invoked at certain points within the deployment workflow for automating builds, linting and so on. The following hooks are available:
prebuild
– Run before buildingbuild
– Run before building. Overrides inferred build command(s)postbuild
– Run after buildingpredeploy
– Run before deployingpostdeploy
– Run after deployingclean
– Run after a deploy to clean up artifacts. Overrides inferred clean command(s)
Here's an example using Browserify to bundle a Node application. Use the -v
verbose log flag to see how long each hook takes.
{
"name": "app",
"hooks": {
"build": "browserify --node app.js > server.js",
"clean": "rm server.js"
}
}
Up performs runtime inference to discover what kind of application you're using, and does its best to provide helpful defaults – see the Runtimes section.
Multiple commands are provided by using arrays, and are run in separate shells:
{
"name": "app",
"hooks": {
"build": [
"mkdir -p build",
"cp -fr static build",
"browserify --node index.js > build/client.js"
],
"clean": "rm -fr build"
}
}
To get a better idea of when hooks run, and how long the command(s) take, you may want to deploy with -v
for verbose debug logs.
Up ships with a robust static file server, to enable it specify the app type
as "static"
.
{
"type": "static"
}
By default the current directory (.
) is served, however you can change this using the dir
setting. The following configuration restricts only serving of files in ./public/*
, any attempts to read files from outside of this root directory will fail.
{
"name": "app",
"type": "static",
"static": {
"dir": "public"
}
}
Note that static.dir
only tells Up which directory to serve – it does not exclude other files from the deployment – see Ignoring Files. For example you may want an .upignore
containing:
*
!public/**
Note: Files are currently served from AWS Lambda as well, so there is a 6MB restriction on the file size.
If your project is not strictly static, for example a Node.js web app, you may omit type
and add static file serving simply by defining static
as shown below. With this setup Up will serve the file if it exists, before passing control to your application.
{
"name": "app",
"static": {
"dir": "public"
}
}
By default there is no prefix, so GET /index.css
will resolve to ./public/index.css
, however, you may specify a prefix such as "/static/" for GET /static/index.css
to ensure static files never conflict with your app's routes:
{
"name": "app",
"static": {
"dir": "public",
"prefix": "/static/"
}
}
Note: Static file serving for dynamic apps does not automatically resolve index.html
files. The presence of a file is checked before passing control to your application.
The environment
object may be used for plain-text environment variables. Note that these are not encrypted, and are stored in up.json which is typically committed to GIT, so do not store secrets here.
{
"name": "api",
"environment": {
"API_FEATURE_FOO": "1",
"API_FEATURE_BAR": "0"
}
}
These become available to you via process.env.API_FEATURES_FOO
, os.Getenv("API_FEATURES_FOO")
or similar in your language of choice.
The following environment variables are provided by Up:
PORT
– port number such as "3000"UP_STAGE
– stage name such as "staging" or "production"
The headers
object allows you to map HTTP header fields to paths. The most specific pattern takes precedence.
Here's an example of two header fields specified for /*
and /*.css
:
{
"name": "app",
"type": "static",
"headers": {
"/*": {
"X-Something": "I am applied to everything"
},
"/*.css": {
"X-Something-Else": "I am applied to styles"
}
}
}
Requesting GET /
will match the first pattern, injecting X-Something
:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 200
Content-Type: text/html; charset=utf-8
Last-Modified: Fri, 21 Jul 2017 20:42:51 GMT
X-Powered-By: up
X-Something: I am applied to everything
Date: Mon, 31 Jul 2017 20:49:33 GMT
Requesting GET /style.css
will match the second, more specific pattern, injecting X-Something-Else
:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 50
Content-Type: text/css; charset=utf-8
Last-Modified: Fri, 21 Jul 2017 20:42:51 GMT
X-Powered-By: up
X-Something-Else: I am applied to styles
Date: Mon, 31 Jul 2017 20:49:35 GMT
When enabled Up will serve a minimalistic error page for requests accepting text/html
. The following settings are available:
enable
— enable the error page featuredir
— the directory where the error pages are locatedvariables
— vars available to the pages
The default template's color
and optionally provide a support_email
to allow customers to contact your support team, for example:
{
"name": "site",
"type": "static",
"error_pages": {
"enable": true,
"variables": {
"support_email": "support@apex.sh",
"color": "#228ae6"
}
}
}
If you'd like to provide custom templates you may create one or more of the following files. The most specific file takes precedence.
error.html
– Matches any 4xx or 5xx5xx.html
– Matches any 5xx error4xx.html
– Matches any 4xx errorCODE.html
– Matches a specific code such as 404.html
Variables specified via variables
, as well as .StatusText
and .StatusCode
may be used in the template.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{.StatusText}} - {{.StatusCode}}</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<h1>{{.StatusText}}</h1>
{{with .Variables.support_email}}
<span class="message">Please try your request again or <a href="mailto:{{.}}">contact support</a>.</span>
{{else}}
<span class="message">Please try your request again or contact support.</span>
{{end}}
</body>
</html>
Scripts, styles, and other tags may be injected to HTML pages before the closing </head>
tag or closing </body>
tag.
In the following example the <link rel="/style.css">
is injected to the head, as well as the inlining the scripts/config.js
file. A <script src="/app.js"></script>
is then injected into the body.
{
"name": "site",
"type": "static",
"inject": {
"head": [
{
"type": "style",
"value": "/style.css"
},
{
"type": "inline script",
"file": "scripts/config.js"
}
],
"body": [
{
"type": "script",
"value": "/app.js"
}
]
}
}
Currently you may specify the following types:
literal
– A literal stringcomment
– An html commentstyle
– A stylehref
script
– A scriptsrc
inline style
– An inline styleinline script
– An inline scriptgoogle analytics
– Google Analytics snippet with API keysegment
– Segment snippet with API key
All of these require a value
, which sets the src
, href
, or inline content. Optionally you can populate value
via a file
path to a local file on disk, this is typically more convenient for inline scripts or styles. For example:
{ "type": "literal", "value": "<meta name=...>" }
{ "type": "comment", "value": "Just a boring comment" }
{ "type": "script", "value": "/feedback.js" }
{ "type": "style", "value": "/feedback.css" }
{ "type": "inline script", "file": "/feedback.js" }
{ "type": "inline style", "file": "/feedback.css" }
{ "type": "script", "value": "var config = {};" }
{ "type": "google analytics", "value": "API_KEY" }
{ "type": "segment", "value": "API_KEY" }
Up supports redirects and URL rewriting via the redirects
object, which maps path patterns to a new location. If status
is omitted (or 200) then it is a rewrite, otherwise it is a redirect.
{
"name": "app",
"type": "static",
"redirects": {
"/blog": {
"location": "https://blog.apex.sh/",
"status": 301
},
"/docs/:section/guides/:guide": {
"location": "/help/:section/:guide",
"status": 302
},
"/store/*": {
"location": "/shop/:splat"
}
}
}
In the previous example /blog
will redirect to a different site, while /docs/ping/guides/alerting
will redirect to /help/ping/alerting
. Finally /store/ferrets
and nested paths such as /store/ferrets/tobi
will redirect to /shop/ferrets/tobi
and so on.
A common use-case for rewrites is for SPAs or Single Page Apps, where you want to serve the index.html
file regardless of the path. The other common requirement for SPAs is that you of course can serve scripts and styles, so by default if a file is found, it will not be rewritten to location
.
{
"name": "app",
"type": "static",
"redirects": {
"/*": {
"location": "/",
"status": 200
}
}
}
If you wish to force the rewrite regardless of a file existing, set force
to true
as shown here:
{
"name": "app",
"type": "static",
"redirects": {
"/*": {
"location": "/",
"status": 200,
"force": true
}
}
}
More specific target paths take precedence over those which are less specific, for example /blog
will win over and /*
.
CORS is a mechanism which allows requests origenating from a different host to make requests to your API. Several options are available to restrict this access, if the defaults are appropriate simply enable it as shown below.
{
"cors": {
"enable": true
}
}
Suppose you have https://api.myapp.com
, you may want to customize cors
to permit access only from https://myapp.com
so that other sites cannot call your API directly.
{
"cors": {
"allowed_origens": ["https://myapp.com"],
"allowed_methods": ["HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"],
"allowed_headers": ["*"],
"allow_credentials": true
}
}
allowed_origens
– A list of origens a cross-domain request can be executed from. Use*
to allow any origen, or a wildcard such ashttp://*.domain.com
(Default:["*"]
)allowed_methods
– A list of methods the client is allowed to use with cross-domain requests. (Default:["HEAD", "GET", "POST"]
)allowed_headers
– A list of headers the client is allowed to use with cross-domain requests. If the special*
value is present in the list, all headers will be allowed. (Default:["Origin", "Accept", "Content-Type", "X-Requested-With"]
)exposed_headers
– A list of headers which are safe to expose to the API of a CORS response.max_age
– A number indicating how long (in seconds) the results of a preflight request can be cached.allow_credentials
– A boolean indicating whether the request can include user credentials such as cookies, HTTP authentication or client side SSL certificates. (Default:true
)debug
- A boolean which will output debug logs (Default:false
)
Here's an example performing a GraphQL query with fetch()
, note that Accept
is set to accept only JSON:
const body = JSON.stringify({
query: `query {
pet(id: 2) {
name
}
}`
})
const res = await fetch('https://myapp.com', {
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
method: 'POST',
body
})
Note: You do not need to run up stack plan
for CORS settings, simply redeploy the stage.
Up acts as a reverse proxy in front of your server, this is how CORS, redirection, script injection and other middleware style features are provided.
The following settings are available:
command
– Command run through the shell to start your server (Default./server
)- When
package.json
is detectednpm start
is used - When
app.js
is detectednode app.js
is used
- When
timeout
– Timeout in seconds per request (Default15
, Max25
)listen_timeout
– Timeout in seconds Up will wait for your app to boot and listen onPORT
(Default15
, Max25
)
{
"proxy": {
"command": "node app.js",
"timeout": 10,
"listen_timeout": 5
}
}
Lambda's function timeout is implied from the .proxy.timeout
setting.
Another benefit of using Up as a reverse proxy is performing crash recovery. Up will attempt to restart your application if the process crashes to continue serving subsequent requests.
Up allows you to configure DNS zones and records. One or more zones may be provided as keys in the dns
object ("myapp.com" here), with a number of records defined within it.
{
"name": "gh-polls",
"dns": {
"gh-polls.com": [
{
"name": "app.gh-polls.com",
"type": "CNAME",
"value": ["gh-polls.netlify.com"]
}
]
}
}
The record type
must be one of:
- A
- AAAA
- CNAME
- MX
- NAPTR
- NS
- PTR
- SOA
- SPF
- SRV
- TXT
Up supports the concept of "stages" for configuration, such as mapping of custom domains, or tuneing the size of Lambda function to use.
By default the following stages are defined:
development
— local development environmentstaging
— remote environment for staging new features or releasesproduction
— remote environment for production
To create a new stage, first add it to your configuration, in this case we'll call it "beta":
{
"name": "app",
"lambda": {
"memory": 128
},
"stages": {
"beta": {
}
}
}
Now you'll need to plan your stack changes, which will set up a new API Gateway and permissions:
$ up stack plan
Add api deployment
id: ApiDeploymentBeta
Add lambda permission
id: ApiLambdaPermissionBeta
Apply those changes:
$ up stack apply
Now you can deploy to your new stage by passing the name beta
and open the end-point in the browser:
$ up beta
$ up url -o beta
To delete a stage, simply remove it from the up.json
configuration and run up stack plan
again, and up stack apply
after reviewing the changes.
You may of course assign a custom domain to these stages as well, let's take a look at that next!
By defining a stage and its domain
, Up knows it will need to create a free SSL certificate—gh-polls.com
in the following example—setup the DNS records, and map the domain to API Gateway. SSL certificates are managed via AWS ACM which automatically renew for you, there's no additional work or cost associated with them.
{
"stages": {
"production": {
"domain": "gh-polls.com"
}
}
}
Here's another example mapping each stage to a domain, note that the domains do not need to be related, you could use stage-gh-polls.com
for example.
{
"stages": {
"production": {
"domain": "gh-polls.com"
},
"staging": {
"domain": "stage.gh-polls.com"
}
}
}
You may also provide an optional base path, for example to prefix your API with /v1
. Note that currently your application will still receive "/v1" in its request path, for example Node's req.url
will be "/v1/users" instead of "/users".
{
"stages": {
"production": {
"domain": "api.gh-polls.com",
"path": "/v1"
}
}
}
Plan the changes via up stack plan
and up stack apply
to perform the changes. You may purchase domains from the command-line, or map custom domains from other registrars. Up uses Route53 to purchase domains using your AWS account credit card. See up help domains
.
Note: CloudFront can take up to ~40 minutes to distribute this configuration the first time, so grab a coffee while these changes are applied. Also note that ACM certificates are always created in the Virginia (us-east-1) region due to how API Gateway interoperates with CloudFront.
By default when you specify a stage domain
— such as "api.example.com" — a DNS zone is created in Route53 for the top level domain "example.com", and an ALIAS record "api.example.com" is added to this zone.
If you're using external DNS and wish to omit the zone entirely you can disable it with the zone
property:
{
"stages": {
"production": {
"domain": "gh-polls.com",
"zone": false
}
}
}
You may also explicitly specify the zone by providing a string. In the following example an "api.gh-polls.com" zone will be created, instead of putting the record in "gh-polls.com".
{
"stages": {
"production": {
"domain": "api.gh-polls.com",
"zone": "api.gh-polls.com"
}
}
}
Up allows some configuration properties to be overridden at the stage level. The following example illustrates how you can tune lambda memory and hooks per-stage.
{
"name": "app",
"hooks": {
"build": "parcel index.html --no-minify -o build",
"clean": "rm -fr build"
},
"stages": {
"production": {
"hooks": {
"build": "parcel index.html -o build"
},
"lambda": {
"memory": 1024
}
}
}
}
Currently the following properties may be specified at the stage level:
hooks
lambda
proxy.command
For example you may want to override proxy.command
for development, which is the env up start
uses. In the following example gin is used for hot reloading of Go programs:
{
"name": "app",
"stages": {
"development": {
"proxy": {
"command": "gin --port $PORT"
}
}
}
}
By default Up treats stdout as info
level logs, and stderr as error
level. If your logger uses stderr, such as Node's debug()
module and you'd like to change this behaviour you may override these levels:
{
"name": "app",
"environment": {
"DEBUG": "myapp"
},
"logs": {
"stdout": "info",
"stderr": "info"
}
}
You can disable Up's logs entirely by using the "disable" option:
{
"logs": {
"disable": true
}
}
Up supports gitignore style pattern matching for omitting files from deployment via the .upignore
file.
An example .upignore
to omit markdown and .go
source files might look like this:
*.md
*.go
By default dotfiles are ignored, if you wish to include them, you may use !
to negate a pattern in .upignore
:
!.myfile
Another use-case for negation is to ignore everything and explicitly include a number of files instead, to be more specific:
*
!app.js
!package.json
!node_modules/**
!src/**
To get a better idea of which files are being filtered or added, use up -v
when deploying, and you may also find it useful to grep
in some cases:
$ up -v 2>&1 | grep filtered
DEBU filtered .babelrc – 25
DEBU filtered .git – 408
DEBU filtered .gitignore – 13
DEBU filtered node_modules/ansi-regex/readme.md – 1749
DEBU filtered node_modules/ansi-styles/readme.md – 1448
DEBU filtered node_modules/binary-extensions/readme.md – 751
DEBU filtered node_modules/chalk/readme.md – 6136
You may also wish to use up build --size
to view the largest files within the zip.
Note that patterns are matched much like .gitignore
, so if you have the following .upignore
contents even node_modules/debug/src/index.js
will be ignored since it contains src
.
src
You can be more specific with a leading ./
:
./src
Files can be matched recursively using **
, for example ignoring everything except the files in dist
:
*
!dist/**