Up Deploy serverless apps in seconds

Introduction

Up deploys infinitely scalable serverless apps, APIs, and static websites in seconds, so you can get back to working on what makes your product unique.

Up focuses on deploying “vanilla” HTTP servers so there’s nothing new to learn, just develop with your favorite existing frameworks such as Express, Koa, Django, Golang net/http or others.

Up currently supports Node.js, Golang, Python, Java, Crystal, and static sites out of the box. Up is platform-agnostic, supporting AWS Lambda and API Gateway as the first targets — you can think of Up as self-hosted Heroku style user experience for a fraction of the price, with the security, flexibility, and scalability of AWS — just $ up and you’re done!

Installation

Up is distributed in a binary form and can be installed manually via the tarball releases or one of the options below.

The quickest way to get up is to run the following command, which installs to /usr/local/bin by default.

$ curl -sf https://up.apex.sh/install | sh

To install up to a specific directory, use BINDIR. Here’s an example installing to the current directory:

$ curl -sf https://up.apex.sh/install | BINDIR=. sh

Verify installation with:

$ up version

Later when you want to update up to the latest version use the following command:

$ up upgrade

If you hit permission issues, you may need to run the following, as up is installed to /usr/local/bin/up by default.

$ sudo chown -R $(whoami) /usr/local/bin/

AWS Credentials

Before using Up you need to first provide your AWS account credentials so that Up is allowed to create resources on your behalf.

AWS Credential Profiles

Most AWS tools support the ~/.aws/credentials file for storing credentials, allowing you to specify AWS_PROFILE environment variable so Up knows which one to reference. To read more on configuring these files view Configuring the AWS CLI.

Here’s an example of ~/.aws/credentials, where export AWS_PROFILE=myaccount would activate these settings.

[myaccount]
aws_access_key_id = xxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxx

Best Practices

You may store the profile name in the up.json file itself as shown in the following snippet:

{
  "name": "appname-api",
  "profile": "myaccount"
}

This is ideal as it ensures you will not accidentally deploy to a different AWS account.

IAM Policy for Up CLI

Below is a policy for AWS Identity and Access Management which provides Up access to manage your resources. Note that the policy may change as features are added to Up, so you may have to adjust the policy.

If you’re using Up for a production application it’s highly recommended to configure an IAM role and user(s) for your team, restricting the access to the account and its resources.

Show policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "acm:*",
                "cloudformation:Create*",
                "cloudformation:Delete*",
                "cloudformation:Describe*",
                "cloudformation:ExecuteChangeSet",
                "cloudformation:Update*",
                "cloudfront:*",
                "cloudwatch:*",
                "ec2:*",
                "ecs:*",
                "events:*",
                "iam:AttachRolePolicy",
                "iam:CreatePolicy",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:DeleteRolePolicy",
                "iam:GetRole",
                "iam:PassRole",
                "iam:PutRolePolicy",
                "lambda:AddPermission",
                "lambda:Create*",
                "lambda:Delete*",
                "lambda:Get*",
                "lambda:InvokeFunction",
                "lambda:List*",
                "lambda:RemovePermission",
                "lambda:Update*",
                "logs:Create*",
                "logs:Describe*",
                "logs:FilterLogEvents",
                "logs:Put*",
                "logs:Test*",
                "route53:*",
                "route53domains:*",
                "s3:*",
                "ssm:*",
                "sns:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "apigateway:*",
            "Resource": "arn:aws:apigateway:*::/*"
        }
    ]
}

Getting Started

The simplest Up application is a single file for the application itself, with zero dependencies, and an up.json file which requires only a name.

If the directory does not contain an up.json file, the first execution of up will prompt you to create it, or you can manually create an up.json with some preferences:

{
  "name": "appname-api",
  "profile": "companyname",
  "regions": ["us-west-2"]
}

Up runs “vanilla” HTTP servers listening on the PORT environment variable, which is passed to your program by Up. For example create a new directory with the following app.js file:

const http = require('http')
const { PORT = 3000 } = process.env

http.createServer((req, res) => {
  res.end('Hello World from Node.js\n')
}).listen(PORT)

Deploy it to the staging environment:

$ up

Open up the URL in your browser:

$ up url --open

Or test with curl:

$ curl `up url`

That’s it! You’ve deployed a basic Up application. To view further help for commands use:

$ up help
$ up help COMMAND
$ up help COMMAND SUBCOMMAND

If you’re not a Node.js developer here are some examples in additional languages.

For Python create app.py:

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import os

class myHandler(BaseHTTPRequestHandler):
  def do_GET(self):
      self.send_response(200)
      self.send_header('Content-type','text/html')
      self.end_headers()
      self.wfile.write("Hello World from Python\n")
      return

server = HTTPServer(('', int(os.environ['PORT'])), myHandler)
server.serve_forever()

For Golang create main.go:

package main

import (
  "os"
  "fmt"
  "log"
  "net/http"
)

func main() {
  addr := ":"+os.Getenv("PORT")
  http.HandleFunc("/", hello)
  log.Fatal(http.ListenAndServe(addr, nil))
}

func hello(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Hello World from Go")
}

Finally for Crystal create main.cr:

require "http/server"

port = ENV["PORT"].to_i

server = HTTP::Server.new(port) do |ctx|
  ctx.response.content_type = "text/plain"
  ctx.response.print "Hello world from Crystal"
end

server.listen

Configuration

Configuration for your app lives in the up.json within your project’s directory. This section details each of the options available.

Name

The name of the application, which is used to name resources such as the Lambda function or API Gateway.

{
  "name": "api"
}

Profile

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"
}

Regions

You may specify one or more target regions for deployment using the regions array. Glob style patterns may be used to match region ids. By default “us-west-2” is used unless the AWS_REGION environment variable is defined.

Currently only a single region is supported until the issue https://github.com/apex/up/issues/134 is closed.

A single region:

{
  "regions": ["us-west-2"]
}

Several regions:

{
  "regions": ["us-west-2", "us-east-1", "ca-central-1"]
}

USA and Canada only:

{
  "regions": ["us-*", "ca-*"]
}

Western USA only:

{
  "regions": ["us-west-*"]
}

All regions like a boss:

{
  "regions": ["*"]
}

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)
  • sa-east-1 – South America (São Paulo)

Lambda Settings

The following Lambda-specific settings are available:

  • role – IAM role ARN, defaulting to the one Up creates for you
  • memory – Function memory in mb (Default 512, Min 128, Max 3008)
  • policy – IAM function policy statement(s)
  • vpc - VPC subnets and security groups
  • accelerate – Enable S3 Transfer Acceleration (Default false)

For example:

{
  "name": "api",
  "lambda": {
    "memory": 512,
    "vpc": {
      "subnets": [
        "subnet-aaaaaaa",
        "subnet-bbbbbbb",
        "subnet-ccccccc",
      ],
      "security_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.

When a VPC is used make sure to use private subnets only, and ensure that you have a NAT for internet access, which will be required to access most AWS APIs.

Changes to Lambda configuration do not require a up stack apply, just deploy and these changes are picked up!

IAM Policy

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 policy statements to the policy array, in the following example we permit DynamoDB item reading, updating, and deleting.

{
  "name": "myapp",
  "lambda": {
    "memory": 1024,
    "policy": [
      {
        "Effect": "Allow",
        "Resource": "*",
        "Action": [
          "dynamodb:Get*",
          "dynamodb:List*",
          "dynamodb:PutItem",
          "dynamodb:DeleteItem"
        ]
      }
    ]
  }
}

Deploy to update the IAM function role permissions.

Active Warming

Up Pro supports active warming to mitigate cold starts. A “cold start” occurs in AWS Lambda when there are no idle containers available to serve a request—Lambda must fetch your code and create a new container, after this it is “warm” and remains in the Lambda cluster to serve subsequent requests for roughly an hour.

If a container does not receive any traffic within the hour, it is removed from the AWS Lambda cluster, and thus a new request may incur a cold start. Up Pro’s “active warming” feature mitigates this by periodically requesting against your app, at the specified concurrency. It tries to maintain at least warm_count idle containers.

For example when a user visits your web application, a cold start may occur for each resource, say you have one JavaScript file, CSS file, and the HTML itself, then this will be 3 concurrent containers. By default Up will warm 15 containers, however you may want to adjust warm_count this for your use-case.

Note that if your application receives steady traffic this may not be an issue at all in practice, as containers will already be warm and re-used.

  • warm – Enable active warming (Default: false)
  • warm_count – Number of concurrent containers to warm (Default: 15)
  • warm_rate – Rate at which to perform the warming (Default: "15m")

Here’s a example specifying 50 idle containers, for all remote stages (staging, production, and custom):

{
  "name": "app",
  "lambda": {
    "warm": true,
    "warm_count": 50,
    "warm_rate": "30m"
  }
}

Run up stack plan and up stack apply to make the changes to your stack! You may apply stage level changes as well, or enable warming for a specific stage only if desired, as shown here:

{
  "name": "app",
  "stages": {
    "production": {
      "lambda": {
        "warm": true,
        "warm_count": 50
      }
    }
  }
}

Another way to mitigate cold starts is to use an uptime monitoring tool, such as Apex Ping which also monitors global performance, so it’s a win-win! Use the “up” coupon for 15% off your first year.

Uptime Monitoring Tool

Hook Scripts

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 building
  • build – Run before building. Overrides inferred build command(s)
  • postbuild – Run after building
  • predeploy – Run before deploying
  • postdeploy – Run after deploying
  • clean – 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.

Static File Serving

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/**

Dynamic Apps

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/"
  }
}

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.

Environment Variables

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”

Up Pro offers encrypted environment variables via the up env sub-command which supports per-stage environment variable mapping.

Header Injection

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

Error Pages

By default Up will serve a minimalistic error page for requests accepting text/html. The following settings are available:

  • disable — remove the error page feature and default pages
  • dir — the directory where the error pages are located
  • variables — 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": {
    "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 5xx
  • 5xx.html – Matches any 5xx error
  • 4xx.html – Matches any 4xx error
  • CODE.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>

Script Injection

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 string
  • comment – An html comment
  • style – A style href
  • script – A script src
  • inline style – An inline style
  • inline script – An inline script
  • google analytics – Google Analytics snippet with API key
  • segment – 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" }

Redirects and Rewrites

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 /*.

Cross-Origin Resource Sharing

CORS is a mechanism which allows requests originating 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_origins": ["https://myapp.com"],
    "allowed_methods": ["HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"],
    "allowed_headers": ["*"],
    "allow_credentials": true
  }
}
  • allowed_origins – A list of origins a cross-domain request can be executed from. Use * to allow any origin, or a wildcard such as http://*.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
})

You do not need to run up stack plan for CORS settings, simply redeploy the stage.

Reverse Proxy

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 detected npm start is used
    • When app.js is detected node app.js is used
    • When app.py is detected python app.py is used
  • timeout – Timeout in seconds per request (Default 15, Max 25)
  • listen_timeout – Timeout in seconds Up will wait for your app to boot and listen on PORT (Default 15, Max 25)
{
  "proxy": {
    "command": "node app.js",
    "timeout": 10,
    "listen_timeout": 5
  }
}

Lambda’s function timeout is implied from the .proxy.timeout setting.

Crash Recovery

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.

DNS Zones & Records

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

Stages

Up supports the concept of “stages” for configuration, such as mapping of custom domains, or tuning the size of Lambda function to use.

By default the following stages are defined:

  • development — local development environment
  • staging — remote environment for staging new features or releases
  • production — 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!

Stages & Custom Domains

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.

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.

DNS Zones

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"
    }
  }
}

Stage Overrides

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"
      }
    }
  }
}

Logs

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"
  }
}

Ignoring Files

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

Negation

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/**

Inspecting

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.

Pattern matching

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/**

Alerting

Up Pro supports defining alerts which can notify your team when your service is failing, responding slowly, or receiving traffic spikes.

{
  "name": "app",
  "actions": [
    {
      "name": "email.backend",
      "type": "email",
      "emails": ["tj@apex.sh"]
    },
    {
      "name": "text.backend",
      "type": "sms",
      "numbers": ["+12508183100"]
    }
  ],
  "alerts": [
    {
      "metric": "http.count",
      "statistic": "sum",
      "threshold": 100,
      "action": "email.backend"
    },
    {
      "metric": "http.5xx",
      "statistic": "sum",
      "threshold": 1,
      "period": "1m",
      "action": "email.backend"
    },
    {
      "metric": "http.4xx",
      "statistic": "sum",
      "threshold": 50,
      "period": "5m",
      "action": "email.backend"
    },
    {
      "metric": "http.latency",
      "statistic": "avg",
      "threshold": 1000,
      "period": "5m",
      "action": "email.backend",
      "description": "Large traffic spike"
    }
  ]
}

Defining Actions

An action must be defined in order to notify your team of triggered and resolved alerts. The action requires a name, which can be any string such as backend, frontend_team, email.backend, email backend – whichever you prefer.

Email

The email action notifies your team via email.

{
  "name": "email.backend",
  "type": "email",
  "emails": ["tj@apex.sh"]
}

SMS

The sms action notifies your team via sms text message.

{
  "name": "text.backend",
  "type": "sms",
  "numbers": ["+12508183100"]
}

Slack

The slack action notifies your team via Slack message.

{
  "name": "slack.backend",
  "type": "slack",
  "url": "https://hooks.slack.com/services/T0YS6H6S5/..."
}

Optionally gifs can be enabled and a channel can be specified instead of using the default for the url.

{
  "name": "slack.backend",
  "type": "slack",
  "url": "https://hooks.slack.com/services/T0YS6H6S5/...",
  "channel": "alerts",
  "gifs": true
}

Defining Alerts

An alert requires a metric such as request count or latency, statistic such as sum or svg, threshold, and an action to perform when the alert is triggered. Here’s a simple example emailing the backend team when we encounter a spike of over 1000 requests.

{
  "metric": "http.count",
  "statistic": "sum",
  "threshold": 1000,
  "action": "email.backend"
}

Required settings

  • metric – Metric to alert against
    • http.count – Request count
    • http.latency – Request latency in milliseconds
    • http.4xx – HTTP 4xx client errors
    • http.5xx – HTTP 5xx server errors
  • statistic – Statistic name (“sum”, “min”, “max”, “avg”, “count”)
  • threshold – Threshold which is compared to operator
  • action – Name of the action to perform

Optional settings

  • period – Period is the alert query time-span (default: 1m)
  • evaluation_periods – Number of periods to evaluate over (default: 1)
  • operator – Operator is the comparison operator (default >)
  • namespace – Metric namespace (example: “AWS/ApiGateway”)
  • missing– How to treat missing data (default: notBreaching)
  • disable – Disable or mute the alert
  • description – Description of the alert

Runtimes

Up supports a number of interpreted languages, and virtually any language which can be compiled to a binary such as Golang. Up does its best to provide idiomatic and useful out-of-the-box experiences tailored to each language. Currently first-class support is provided for:

  • Python
  • Golang
  • Node.js
  • Crystal
  • Clojure
  • Java
  • Static sites

Node.js

When a package.json file is detected, Node.js is the assumed runtime. By default the latest version supported by Lambda is used (nodejs8.10), see Lambda Settings for details.

The build hook becomes:

$ npm run build

The server run by the proxy becomes:

$ npm start

Python

When requirements.txt is present the build command becomes:

$ mkdir -p .pypath/ && pip install -r requirements.txt -t .pypath/

The server run by the proxy becomes:

$ python app.py

Golang

When a main.go file is detected, Golang is the assumed runtime.

The build hook becomes:

$ GOOS=linux GOARCH=amd64 go build -o server *.go

The clean hook becomes:

$ rm server

Crystal

When a main.cr file is detected, Crystal is the assumed runtime. Note that this runtime requires Docker to be installed.

The build hook becomes:

$ docker run --rm -v $(pwd):/src -w /src tjholowaychuk/up-crystal crystal build --link-flags -static -o server main.cr

The clean hook becomes:

$ rm server

Java

When a build.gradle file is detected, Gradle is assumed, otherwise if pom.xml is found then Maven is used.

Static

When an index.html file is detected the project is assumed to be static.

Commands

Up provides the up command-line program, used to deploy the app, and manage associated resources such as domains and SSL certificates, as well as operational tasks like viewing logs.

To view details for a command at any time use up help, up help <command>, for example up help team members add.

Usage:

  up [<flags>] <command> [<args> ...]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --format="text"  Output formatter.
      --version        Show application version.

Commands:

  help                 Show help for a command.
  build                Build zip file.
  config               Show configuration after defaults and validation.
  deploy               Deploy the project.
  deploys              Show deployment history.
  docs                 Open documentation website in the browser.
  domains ls           List purchased domains.
  domains check        Check availability of a domain.
  domains buy          Purchase a domain.
  env add              Add variables.
  env get              Get a variable value.
  env ls               List variables.
  env rm               Remove variables.
  logs                 Show log output.
  metrics              Show project metrics.
  prune                Prune old S3 deployments of a stage.
  rollback             Rollback to a previous deployment.
  run                  Run a hook.
  stack plan           Plan configuration changes.
  stack apply          Apply configuration changes.
  stack delete         Delete configured resources.
  stack status         Show status of resources.
  start                Start development server.
  team status          Status of your account.
  team switch          Switch active team.
  team login           Sign in to your account.
  team logout          Sign out of your account.
  team members add     Add invites a team member.
  team members rm      Remove a member or invite.
  team members ls      List team members and invites.
  team subscribe       Subscribe to the Pro plan.
  team unsubscribe     Unsubscribe from the Pro plan.
  team card change     Change the default card.
  team ci              Credentials for CI.
  team add             Add a new team.
  upgrade              Install the latest or specified version of Up.
  url                  Show, open, or copy a stage endpoint.
  version              Show version.

Examples:

  Deploy the project to the staging environment.
  $ up

  Deploy the project to the production stage.
  $ up deploy production

  Show the staging endpoint url.
  $ up url

  Tail project logs.
  $ up logs -f

  Show error or fatal level logs.
  $ up logs 'error or fatal'

  Run build command manually.
  $ up run build

  Show help and examples for a command.
  $ up help team

  Show help and examples for a sub-command.
  $ up help team members

Deploy

Deploy the project, by default to the “staging” stage. Note that running up and up deploy are identical, as it is the default command.

Usage:

  up deploy [<stage>]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --format="text"  Output formatter.
      --version        Show application version.

Args:

  [<stage>]  Target stage name.

Examples

Deploy the project to the staging stage.

$ up

Deploy the project to the staging stage, this is the same as running up without arguments.

$ up deploy

Deploy the project to the production stage.

$ up deploy production

Note that since deploy is the default command the following is also valid:

$ up production

Rollback

Up Pro supports instant rollbacks to a previous deployment. A subsequent up rollback will revert the rollback, as it simply toggles the deployment versions. Note that rollbacks do not affect environment variables, as they are loaded at runtime.

Usage:

  up rollback [<flags>] [<version>]

Flags:

  -h, --help                Output usage information.
  -C, --chdir="."           Change working directory.
  -v, --verbose             Enable verbose log output.
      --format="text"       Output formatter.
      --version             Show application version.
  -s, --stage="staging"     Target stage name.

Args:

  [<version>]  Target version for rollback.

Examples

Rollback to the previous staging version.

$ up rollback

Rollback to a specific git commit

$ up rollback 15c46ba

Rollback to a specific git tag

$ up rollback v1.7.2

Rollback to the previous production version.

$ up rollback -s production

Rollback to a specific git commit

$ up rollback -s production 15c46ba

Rollback to a specific git tag

$ up rollback -s production v1.7.2

Config

Validate and output configuration with defaults applied.

$ up config
{
  "name": "app",
  "description": "",
  "type": "server",
  "headers": null,
  "redirects": null,
  "hooks": {
    "build": "GOOS=linux GOARCH=amd64 go build -o server *.go",
    "clean": "rm server"
  },
  "environment": null,
  "regions": [
    "us-west-2"
  ],
  "inject": null,
  "lambda": {
    "role": "arn:aws:iam::ACCOUNT:role/lambda_function",
    "memory": 128,
    "timeout": 5
  },
  "cors": null,
  "error_pages": {
    "dir": ".",
    "variables": null
  },
  "proxy": {
    "command": "./server",
    "backoff": {
      "min": 100,
      "max": 500,
      "factor": 2,
      "attempts": 3,
      "jitter": false
    }
  },
  "static": {
    "dir": "."
  },
  "logs": {
    "disable": false
  },
  "dns": {
    "zones": null
  }
}
...

Logs

Show or tail log output with optional query for filtering. When viewing or tailing logs, you are viewing them from all stages, see the examples below to filter on a stage name.

Usage:

  up logs [<flags>] [<query>]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --format="text"  Output formatter.
      --version        Show application version.
  -f, --follow         Follow or tail the live logs.
  -S, --since="1d"     Show logs since duration (30s, 5m, 2h, 1h30m, 3d, 1M).
  -e, --expand         Show expanded logs.

Args:

  [<query>]  Query pattern for filtering logs.

Expanded Output

Use the -e or --expand flag to expand log fields:

$ up -e 'path = "/static/*"'

1:36:34pm INFO request
           id: 8ff53267-c33a-11e7-9685-15d48d102ae9
           ip: 70.66.179.182
       method: GET
         path: /static/3.jpg
        stage: production
      version: 5

1:36:34pm INFO response
     duration: 1ms
           id: 8ff53267-c33a-11e7-9685-15d48d102ae9
           ip: 70.66.179.182
       method: GET
         path: /static/3.jpg
         size: 0 B
        stage: production
       status: 304
      version: 5

1:36:34pm INFO request
           id: 8ff4bd57-c33a-11e7-bf4b-4f0d97c427c5
           ip: 70.66.179.182
       method: GET
         path: /static/1.png
        stage: production
      version: 5

JSON Output

When stdout is not a terminal Up will output the logs as JSON, which can be useful for further processing with tools such as jq.

In this contrived example the last 5 hours of production errors are piped to jq to produce a CSV of HTTP methods to IP address.

$ up logs -s 5h 'production error' | jq -r '.|[.fields.method,.fields.ip]|@csv'

Yielding:

"GET","207.194.34.24"
"GET","207.194.34.24"
"GET","207.194.34.24"

Examples

Show logs from the past day.

$ up logs

Show logs from the past 45 minutes.

$ up -S 45m logs

Show logs from the past 12 hours.

$ up -S 12h logs

Show live log output.

$ up logs -f

Show live logs from production only.

$ up logs -f production

Show live error logs from production only.

$ up logs -f 'production error'

Show error logs, which include 5xx responses.

$ up logs error

Show error and warning logs, which include 4xx and 5xx responses.

$ up logs 'warn or error'

Show logs with a specific message.

$ up logs 'message = "user login" method = "GET"'

Show logs with a specific message with implicit =:

$ up logs '"user login" method = "GET"'

Show responses with latency above 15ms.

$ up logs 'duration > 15'

Show 4xx and 5xx responses in production

$ up logs 'production (warn or error)'

Show production 5xx responses with a POST, PUT, or DELETE method.

$ up logs 'production error method in ("POST", "PUT", "DELETE")

Show 200 responses with latency above 1500ms.

$ up logs 'status = 200 duration > 1.5s'

Show responses with bodies larger than 100kb.

$ up logs 'size > 100kb'

Show 4xx and 5xx responses.

$ up logs 'status >= 400'

Show emails containing @apex.sh.

$ up logs 'user.email contains "@apex.sh"'

Show emails ending with @apex.sh.

$ up logs 'user.email = "*@apex.sh"'

Show emails starting with tj@.

$ up logs 'user.email = "tj@*"'

Show logs with a more complex query.

$ up logs 'method in ("POST", "PUT") ip = "207.*" status = 200 duration >= 50'

URL

Show, open, or copy a stage endpoint.

Usage:

  up url [<flags>]

Flags:

  -h, --help             Output usage information.
  -C, --chdir="."        Change working directory.
  -v, --verbose          Enable verbose log output.
      --format="text"    Output formatter.
      --version          Show application version.
  -s, --stage="staging"  Target stage name.
  -o, --open             Open endpoint in the browser.
  -c, --copy             Copy endpoint to the clipboard.

Examples

Show the development endpoint.

$ up url

Open the development endpoint in the browser.

$ up url --open

Copy the development endpoint to the clipboard.

$ up url --copy

Show the production endpoint.

$ up url -s production

Open the production endpoint in the browser.

$ up url -o -s production

Copy the production endpoint to the clipboard.

$ up url -c -s production

Metrics

Show project metrics and estimated cost breakdown for requests, invocation count and the time spent for Lambda invocations.

Usage:

  up metrics [<flags>]

Flags:

  -h, --help             Output usage information.
  -C, --chdir="."        Change working directory.
  -v, --verbose          Enable verbose log output.
      --format="text"    Output formatter.
      --version          Show application version.
  -s, --stage="staging"  Target stage name.
  -S, --since="1M"       Show logs since duration (30s, 5m, 2h, 1h30m, 3d, 1M).

For example:

$ up metrics -s production -S 15d

  Requests: 13,653 ($0.01)
  Duration min: 0ms
  Duration avg: 48ms
  Duration max: 15329ms
  Duration sum: 3m6.611s ($0.00)
  Errors 4xx: 1,203
  Errors 5xx: 2
  Invocations: 12,787 ($0.00)
  Errors: 0
  Throttles: 0

Start

Start development server. The development server runs the same proxy that is used in production for serving, so you can test a static site or application locally with the same feature-set.

See Stage Overrides for an example of overriding the proxy command per-stage, especially useful in development.

Up Pro supports environment variables, and these will be loaded with up start, and variables mapped to the “development” stage will take precedence. For example:

$ up env set NAME Tobi
$ up start
# NAME is available as "Tobi"

$ up env set NAME Loki -s development
$ up start
# NAME is available as "Loki"

$ NAME=Jane up start
# NAME is available as "Jane"

The UP_STAGE and NODE_ENV environment variables will be set to “development” automatically.

Usage:

  up start [<flags>]

Flags:

  -h, --help             Output usage information.
  -C, --chdir="."        Change working directory.
  -v, --verbose          Enable verbose log output.
      --format="text"    Output formatter.
      --version          Show application version.
  -c, --command=COMMAND  Proxy command override
  -o, --open             Open endpoint in the browser.
      --address=":3000"  Address for server.

Examples

Start development server on port 3000.

$ up start

Start development server on port 5000.

$ up start --address :5000

Override proxy command. Note that the server created must listen on PORT, which is why --port $PORT is required for the gin example.

$ up start -c 'go run main.go'
$ up start -c 'gin --port $PORT'
$ up start -c 'node --some-flag app.js'
$ up start -c 'parcel'

Domains

Manage domain names, and purchase them from AWS Route53 as the registrar.

Usage:

  up domains <command> [<args> ...]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --version        Show application version.

Subcommands:

  domains list    List purchased domains.
  domains check   Check availability of a domain.
  domains buy     Purchase a domain.

Examples

List purchased domains.

$ up domains

Check availability of a domain.

$ up domains check example.com

Purchase a domain (with interactive form).

$ up domains buy

Stack

Stack resource management. The stack is essentially all of the resources powering your app, which is configured by Up on the first deploy.

At any time if you’d like to delete the application simply run $ up stack delete. To view the status and potential errors use $ up stack.

Usage:

  up stack <command> [<args> ...]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --version        Show application version.

Subcommands:

  stack plan      Plan configuration changes.
  stack apply     Apply configuration changes.
  stack delete    Delete configured resources.
  stack status    Show status of resources.

Examples

Show status of the stack resources and nameservers.

$ up stack

Show resource changes.

$ up stack plan

Apply resource changes.

$ up stack apply

Delete the stack resources.

$ up stack delete

Build

Build zip file, typically only helpful for inspecting its contents. If you’re interested in seeing what files are causing bloat, use the --size flag to list files by size descending.

Usage:

  up build [<flags>]

Flags:

  -h, --help             Output usage information.
  -C, --chdir="."        Change working directory.
  -v, --verbose          Enable verbose log output.
      --format="text"    Output formatter.
      --version          Show application version.
  -s, --stage="staging"  Target stage name.
      --size             Show zip contents size information.

Examples

Build archive and save to ./out.zip

$ up build

Build archive and output to file via stdout.

$ up build > /tmp/out.zip

Build archive list files by size.

$ up build --size

Build archive and list size without creating out.zip.

$ up build --size > /dev/null

Team

Manage team members, plans, and billing.

Usage:

  up team <command> [<args> ...]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --format="text"  Output formatter.
      --version        Show application version.

Subcommands:

  team status          Status of your account.
  team switch          Switch active team.
  team login           Sign in to your account.
  team logout          Sign out of your account.
  team members add     Add invites a team member.
  team members rm      Remove a member or invite.
  team members ls      List team members and invites.
  team subscribe       Subscribe to the Pro plan.
  team unsubscribe     Unsubscribe from the Pro plan.
  team card change     Change the default card.
  team ci              Credentials for CI.
  team add             Add a new team.

Examples

Show active team and subscription status.

$ up team

Switch teams interactively.

$ up team switch

Sign in or create account with interactive prompt.

$ up team login

Sign in to a team.

$ up team login --email tj@example.com --team apex-software

Add a new team and automatically switch to the team.

$ up team add "Apex Software"

Subscribe to the Pro plan.

$ up team subscribe

Invite a team member to your active team.

$ up team members add asya@example.com

Upgrade

Install the latest or specified version of Up. The OSS and Pro versions have independent semver, as bugfixes and features for one may not be relevant to the other.

If you’re an Up Pro subscriber, up upgrade will always install Up Pro, even when --target is specified, there is no need to specify that you want the Pro version.

Usage:

  up upgrade [<flags>]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --format="text"  Output formatter.
      --version        Show application version.
  -t, --target=TARGET  Target version for upgrade.

Examples

Upgrade to the latest version available.

$ up upgrade

Upgrade to the specified version.

$ up upgrade -t 0.4.4

Prune

Prune old S3 deployments of a stage.

Usage:

  up prune [<flags>]

Flags:

  -h, --help             Output usage information.
  -C, --chdir="."        Change working directory.
  -v, --verbose          Enable verbose log output.
      --format="text"    Output formatter.
      --version          Show application version.
  -s, --stage="staging"  Target stage name.
  -r, --retain=30        Number of versions to retain.

Examples

Prune and retain the most recent 30 staging versions.

$ up prune

Prune and retain the most recent 30 production versions.

$ up prune -s production

Prune and retain the most recent 15 production versions.

$ up prune -s production -r 15

Env

Manage encrypted environment variables. Environment variables are scoped to all stages by default, with stage-level overrides. The up env command is available in the Pro plan.

Usage:

  up env <command> [<args> ...]

Flags:

  -h, --help           Output usage information.
  -C, --chdir="."      Change working directory.
  -v, --verbose        Enable verbose log output.
      --format="text"  Output formatter.
      --version        Show application version.

Subcommands:

  env add              Add variables.
  env get              Get a variable value.
  env ls               List variables.
  env rm               Remove variables.

Here are some examples:

$ up env add DB_NAME users DB_USER sloth
$ up env add DB_NAME=users DB_USER=sloth
$ up env add DB_URL stage.mydb.hosted.com
$ up env add DB_PASS passforstage
$ up env add DB_CONN "host=localhost port=5432"

Overriding for a stage such as production can be specified with the -s, --stage flag. For example DB_NAME and DB_USER would likely remain the same in production, however the DB_URL and DB_PASS would not, so we should assign them as shown here:

$ up env add -s production DB_URL prod.mydb.hosted.com
$ up env add -s production DB_PASS passforprod

Environment variables may also be plain or “clear” text, using the -c, --clear flag, which may be viewed in the output.

$ up env add -c DB_NAME users
$ up env add -c DB_USER sloth
$ up env add DB_PASS amazingpass

Get environment variable values with:

$ up env get DB_NAME
$ up env get DB_NAME -s production

List the env vars with:

$ up env

all                                                   

DB_NAME  users  -  Modified 34 seconds ago by tobi
DB_PASS  -      -  Modified 22 seconds ago by tobi
DB_URL   -      -  Modified 24 seconds ago by tobi
DB_USER  sloth  -  Modified 30 seconds ago by tobi

production                                            

DB_PASS  -      -  Modified 2 seconds ago by tobi  
DB_URL   -      -  Modified 4 seconds ago by tobi  

Note that you can also assign descriptions with the -d, --desc flag. Note that -cd is equivalent to -c, -d marking the first two variables as cleartext.

$ up env set -cd 'MongoDB collection name' DB_NAME users
$ up env set -cd 'MongoDB name' DB_NAME users
$ up env set -d 'MongoDB address' DB_URL bar
$ up env set -d 'MongoDB password' DB_PASS foo

Check the output and you’ll see the descriptions:

$ up env

all                                                                         

DB_NAME  users  MongoDB collection name  Modified 2 minutes ago by tobi  
DB_PASS  -      MongoDB password         Modified 19 seconds ago by tobi
DB_URL   -      MongoDB address          Modified 1 second ago by tobi   
DB_USER  sloth  MongoDB username         Modified 2 minutes ago by tobi  

Note that while changes made to the variables are effective immediately, AWS Lambda may retain idle containers with the previous values. Currently you must perform a deploy in order to receive the new values. This can be used to your advantage, as it allows you to change for example both DB_USER and DB_PASS at the same time.

Variables defined via up env are also available to the build hooks, as well as up start. The UP_STAGE and NODE_ENV are defined to the target stage name automatically, unless specified manually. See the Env Static example to see how it works with build hooks.

Guides

Subscribing to Up Pro

Up Pro provides additional features which are not available in the open-source version, such as encrypted environment variables, alerting support and more.

First sign into the platform with the following command – you’ll receive an email for confirmation.

$ up team login

     email: tj@apex.sh
  ⠋ verify: Check your email for a confirmation link

Click the link in your email and you’re signed in! If you’re using Up Pro with one or more organizations, you should create a team to manage team members and subscriptions independently. If you plan on using Up Pro for personal use you may skip this step.

$ up team add "My Company"

Next you’ll need to subscribe! You’ll be asked for an optional coupon, credit card information – which never touches our servers, only Stripe via HTTPS – and finally a subscription confirmation.

$ up team subscribe

Now you and your team members may upgrade to the latest version of Up Pro, instead of the open-source distribution:

$ up upgrade

To view the status of your account at any time run the following:

$ up team

  team: apex
  subscription: Up Pro
  amount: $10.00/mo USD
  created: December 22, 2017

To switch to another team run the following and select the active team.

$ up team switch


   ❯ apex
     tj@apex.sh

At any time you can ensure you’re on Up Pro up version:

$ up version
0.1.1-pro

Note that AWS charges for your resource usage, and is not associated with Up Pro’s subscription. Most small to medium applications will fit within AWS’ free tier, however, you should consult AWS’ pricing documentation for details. The Serverless Calc is a useful tool for estimating the API Gateway and Lambda charges.

Inviting Team Members

To invite members use the following command:

$ up team members add tobi@apex.sh
$ up team members add loki@apex.sh
$ up team members add jane@apex.sh

At any time you can view invites and members:

$ up team members

team: apex

Members

 • tj@apex.sh
 • tobi@apex.sh
 • loki@apex.sh

Invites

 • jane@apex.sh

Your team members will receive an email with installation instructions, where they run the following to sign in – with your team id of course.

$ up team login --email tobi@apex.sh --team apex

Development to Production Workflow

This section guides you through taking a small application from development, to production, complete with purchasing and mapping a custom domain.

Deploying

First, create app.js in an empty directory with the following Node.js app. Note that it must listen on PORT which is passed by Up.

const http = require('http')
const { PORT = 3000 } = process.env

http.createServer((req, res) => {
  res.end('Hello World\n')
}).listen(PORT)

Next, you should give your application a name and start configuring. The profile name should correspond to the name in ~/.aws/credentials so that Up knows which AWS account to deploy to, and which credentials to use.

{
  "name": "up-example",
  "profile": "up-tobi"
}

Run up to deploy the application.

$ up

   build: 5 files, 3.9 MB (358ms)
  deploy: complete (14.376s)
   stack: complete (1m12.086s)

Test with curl to ensure everything is working:

$ curl `up url`
Hello World

Purchasing a Domain

Domains can be mapped from existing services, or purchased directly from AWS via Route53. First check if the domain you’d like is available:

$ up domains check up.com

  Domain up.com is unavailable

  Suggestions:

  theupwards.com          $12.00 USD
  upwardonline.com        $12.00 USD
  myupwards.com           $12.00 USD
  theastir.com            $12.00 USD
  astironline.com         $12.00 USD
  myastir.com             $12.00 USD
  myupward.net            $11.00 USD
  cleanup.tv              $32.00 USD
  myup.tv                 $32.00 USD
  itup.tv                 $32.00 USD
  newup.tv                $32.00 USD
  thedown.net             $11.00 USD
  theupward.net           $11.00 USD
  upwardsonline.net       $11.00 USD

Oh no up.com is taken! Try another:

$ up domains check up-example.com

  Domain up-example.com is available for $12.00 USD

Purchase it with the following command and fill out the details required by the registrar:

$ up domains buy

  Domain: up-example.com
  First name: TJ
  Last name: Holowaychuk
  Email: tj@apex.sh
  Phone: +1.2501007000
  Country code: CA
  City: Victoria
  State or province: BC
  Zip code: X9X 9X9
  Address: Some address here

It can take a few minutes for AWS to finalize the purchase after which you should receive an email. Then you’ll see it in the up domains output along with the automatic renewal time.

$ up domains

  gh-polls.com             renews Aug 28 17:17:58
  up-example.com           renews Sep 19 19:40:50

By default domains purchased with Up have privacy protection enabled, hiding your contact information from WHOIS.

Deploying to Stages

Before deploying to the staging and production stages, first tweak the application a little to include the UP_STAGE environment variable:

const http = require('http')
const { PORT = 3000, UP_STAGE } = process.env

http.createServer((req, res) => {
  res.end('Hello World from ' + UP_STAGE)
}).listen(PORT)

Now deploy to staging and production. Note that up is an alias of up deploy staging.

$ up
$ up deploy production

Open both in the browser:

$ up url -o
$ up url production -o

You should see “Hello World from production” and “Hello World from staging”.

Mapping Custom Domains to Stages

Now that you have an application deployed, you probably want a fancy custom domain for it right? You can map these using the stages and domain properties.

Here we let Up know that we want up-example.com for production and dev.up-example for staging.

{
  "name": "up-example",
  "profile": "up-tobi",
  "stages": {
    "staging": {
      "domain": "dev.up-example.com"
    },
    "production": {
      "domain": "up-example.com"
    }
  }
}

Note that you could map staging to a domain like staging-myapp.com, it does not have to be a sub-domain of your production domain.

Now when you run up stack plan to preview changes to your resources, it will prompt you to verify the Let’s Encrypt certificate emails that AWS sends.

$ up stack plan

       domains: Check your email for certificate approval
     ⠧ confirm: up-example.com

AWS requires email verification to prove you own the domain. AWS sends an email to the 3 contact addresses listed in WHOIS when you registered the domain, and to the following 5 common system addresses for your domain:

  • administrator@your_domain_name
  • hostmaster@your_domain_name
  • postmaster@your_domain_name
  • webmaster@your_domain_name
  • admin@your_domain_name

See Validate Domain Ownership for more information.

After clicking “I Approve” in one of the emails, the output will resume and you’ll see some new resources Up will be creating.

Add AWS::ApiGateway::DomainName
  id: ApiDomainDevelopment

Add AWS::ApiGateway::BasePathMapping
  id: ApiDomainDevelopmentPathMapping

Add AWS::ApiGateway::DomainName
  id: ApiDomainProduction

Add AWS::ApiGateway::BasePathMapping
  id: ApiDomainProductionPathMapping

Add AWS::Route53::RecordSet
  id: DnsZoneDevUpExampleComRecordDevUpExampleCom

Add AWS::Route53::RecordSet
  id: DnsZoneUpExampleComRecordUpExampleCom

If you’re curious, now that Up knows you want to map the domain(s), it will create:

  • Registers ACM free SSL certificate(s) for your domain(s)
  • CloudFront distribution for the API Gateway
  • API Gateway stage mapping
  • Route53 DNS zone and record(s) mapping to the CloudFront distribution

Now apply these changes:

$ up stack apply

After the changes have been applied, it can take roughly 10-40 minutes for CloudFront to distribute the configuration and SSL certificate globally, so until then our up-example.com domain won’t work.

Once available https://up-example.com will always point to production via up deploy production, and https://dev.up-example.com/ will point to the latest deployment via up.

Mapping Domains from External Registrars

If you purchased a domain via up domains buy you can skip this step, however if you used an external registrar such as Godaddy you will need to delegate to AWS for DNS management.

To do this you’ll need to sign in to your registrar’s site, and configure the nameservers. To figure out what values to use for the nameservers, run up stack, which outputs the NS records for the apex (top-level) domains of your application.

$ up stack

Staging

  domain: stage.up-example.com
  endpoint: d2od0udp1p8bru.cloudfront.net

Production

  domain: up-example.com
  endpoint: d72wsqljqg5cy.cloudfront.net
  nameservers:
   • ns-1495.awsdns-58.org
   • ns-103.awsdns-12.com
   • ns-1670.awsdns-16.co.uk
   • ns-659.awsdns-18.net

Save those four values in your registrar’s interface, and you should be good to go! Note that altering DNS records can take some time to propagate.

Mapping with Third-party DNS

If you manage DNS with a third-party such as Cloudflare, and wish to use Up only for deployment you will need to manually edit or add DNS records.

For example if your top-level domain sloths.com is managed by Cloudflare and you’d like point api.sloths.com to your app, you should first add it to your up.json:

{
  "name": "sloths"
  "stages": {
    "production": {
      "domain": "api.sloths.com"
    }
  }
}

Next you will need to up stack plan and up stack apply, this will set up a CloudFront end-point for the application. To view the endpoint information, run up stack:

$ up stack

Production

  domain: api.sloths.com
  endpoint: d72wsqljqg5cy.cloudfront.net

In your DNS provider – Cloudflare in this example – you should create a CNAME record pointing to the production endpoint. Make sure that the domain you use matches the domain in Cloudflare.

Stack Changes

The “stack” is all of the resources associated with your app. You plan changes via up stack plan and perform them with up stack apply.

Suppose you wanted to map the “staging” stage, you would first add it to up.json:

{
  "name": "up-example",
  "profile": "up-tobi",
  "stages": {
    "staging": {
      "domain": "stage.up-example.com"
    },
    "production": {
      "domain": "up-example.com"
    }
  }
}

Then run:

$ up stack plan

Review the output, it should be all “Add”s in this case, then apply:

$ up stack apply

Deleting the App

After you’re done messing around, you may want to remove all the resources and the app itself. To do so simply run:

$ up stack delete

Deploying Applications from Continuous Integration

Up makes it easy to deploy your applications from CI, thanks to its Go binaries you can install Up in seconds in any CI provider such as Travis, Circle, Semaphore among others.

Environment Variables

The first step is to set up environment variables so that you have access to your AWS account. You can get these values from cat ~/.aws/credentials:

  • AWS_ACCESS_KEY_ID – AWS access key
  • AWS_SECRET_ACCESS_KEY – AWS secret key

If using running Up Pro you’ll need your Up credentials in order to access Up Pro via the up upgrade command. To obtain this run up team ci or up team ci --copy to copy it directly to your clipboard, then paste this as the env var’s value.

  • UP_CONFIG – Up configuration as base64-encoded JSON

If you run into “403 Forbidden” errors this is due to GitHub’s low rate limit for unauthenticated users, consider creating a Personal Access Token and adding the following variable to your CI:

  • GITHUB_TOKEN — Github personal access token

Commands

You may install Up in the current working directory, and deploy to production with the following commands, omitting the up upgrade if you are not an Up Pro subscriber.

$ curl -sf https://up.apex.sh/install | BINDIR=. sh
$ ./up upgrade
$ ./up production

Or if you prefer installing globally within PATH:

$ sudo chown -R $(whoami) /usr/local/bin
$ curl -sf https://up.apex.sh/install | sh
$ up upgrade
$ up production

Mastering Logging

This section describes how you can log from your application in a way that Up will recognize. In the future Up will support forwarding your logs to services such as Loggly, Papertrail or ELK.

Plain Text

The first option is plain-text logs to stdout or stderr. Currently writes to stderr are considered ERROR-level logs, and stdout becomes INFO.

Writing plain-text logs is simple, for example with Node.js:

console.log('User signed in')
console.error('Failed to sign in: %s', err)

Would be collected as:

 INFO: User signed in
ERROR: Failed to sign in: something broke

JSON

The second option is structured logging with JSON events, which is preferred as it allows you to query against specific fields and treat logs like events.

JSON logs require a level and message field:

console.log(`{ "level": "info", "message": "User login" }`)

Would be collected as:

INFO: User login

The message field should typically contain no dynamic content, such as user names or emails, these can be provided as fields:

console.log(`{ "level": "info", "message": "User login", "fields": { "name": "Tobi", "email": "tobi@apex.sh" } }`)

Would be collected as:

INFO: User login name=Tobi email=tobi@apex.sh

Allowing you to perform queries such as:

$ up logs 'message = "User login" name = "Tobi"'

Or:

$ up logs 'name = "Tobi" or email = "tobi@*"'

Here’s a simple JavaScript logger for reference. All you need to do is output some JSON to stdout and Up will handle the rest!

function log(level, message, fields = {}) {
  const entry = { level, message, fields }
  console.log(JSON.stringify(entry))
}

For example, with the Go apex/log package you’d use the json handler, which outputs this format.

Log Query Language

Up supports a comprehensive query language, allowing you to perform complex filters against structured data, supporting operators, equality, substring tests and so on. This section details the options available when querying.

AND Operator

The and operator is implied, and entirely optional to specify, since this is the common case.

Suppose you have the following example query to show only production errors from a the specified IP address.

production error ip = "207.194.32.30"

The parser will inject and, effectively compiling to:

production and error and ip = "207.194.38.50"

Or Operator

There is of course also an or operator, for example showing warnings or errors.

production (warn or error)

These may of course be nested as you require:

(production or staging) (warn or error) method = "GET"

Equality Operators

The = and != equality operators allow you to filter on the contents of a field.

Here = is used to show only GET requests:

method = "GET"

Or for example != may be used to show anything except GET:

method != "GET"

Relational Operators

The >, >=, <, and <= relational operators are useful for comparing numeric values, for example response status codes:

status >= 200 status < 300

Stages

Currently all development, staging, and production logs are all stored in the same location, however, you may filter to find exactly what you need.

The keywords production, staging, and development expand to:

stage = "production"

For example, filtering on slow production responses:

production duration >= 1s

Is the same as:

stage = "production" duration >= 1s

Severity Levels

Up provides request level logging with severity levels applied automatically. For example, a 5xx response is an ERROR level, while 4xx is a WARN, and 3xx or 2xx are the INFO level.

This means that instead of using the following for showing production errors:

production status >= 500

You may use:

production error

In Operator

The in operator checks for the presence of a field within the set provided. For example, showing only POST, PUT and PATCH requests:

method in ("POST", "PUT", "PATCH")

Units

The log grammar supports units for bytes and durations. For example, showing responses larger than 56kb:

size > 56kb

Or showing responses longer than 1500ms:

duration > 1.5s

Byte units are:

  • b bytes (123b or 123 are equivalent)
  • kb bytes (5kb, 128kb)
  • mb bytes (5mb, 15.5mb)

Duration units are:

  • ms milliseconds (100ms or 100 are equivalent)
  • s seconds (1.5s, 5s)

Substring Matches

When filtering on strings, such as the log message, you may use the * character for substring matches.

For example if you want to show logs with a remote ip prefix of 207.:

ip = "207.*"

Or a message containing the word “login”:

message = "*login*"

There is also a special keyword for this case:

message contains "login"

Hot Reloading in Development

The up start command uses your proxy.command by default, which may be inferred based on your application type, such as node app.js for Node.js or ./server for Golang.

You may alter this command for up start with the development environment. For example with Golang you may want go run main.go, or hot reloading with gin as shown here:

{
  "name": "app",
  "stages": {
    "development": {
      "proxy": {
        "command": "gin --port $PORT"
      }
    }
  }
}

Note that the server must always listen on PORT which is provided by up start.

Accessing Lambda Context

Traditional AWS Lambda functions a provided a context object which contains runtime information such as API Gateway user identity. This information is exposed as JSON in the X-Context header field in Up as shown here:

const http = require('http')
const { PORT } = process.env

const app = http.createServer((req, res) => {
  const ctx = JSON.parse(req.headers['x-context'])
  res.end(JSON.stringify(ctx, null, 2))
})

console.log('Starting app on %s', PORT)
app.listen(PORT)

Output will be similar to the following. Visit the AWS Documentation for details.

{
  "apiId": "g4yn392afg",
  "resourceId": "ez0z8areob",
  "requestId": "d8314ef1-5543-11e8-a925-21fa0dd01c37",
  "accountId": "337344593553",
  "stage": "staging",
  "identity": {
    "apiKey": "",
    "accountId": "",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
    "sourceIp": "64.110.31.100",
    "accessKey": "",
    "caller": "",
    "user": "",
    "userARN": "",
    "cognitoIdentityId": "",
    "cognitoIdentityPoolId": "",
    "cognitoAuthenticationType": "",
    "cognitoAuthenticationProvider": ""
  },
  "authorizer": null
}

Git Integration

Up automatically detects and utilizes Git commit information when you deploy, such as recording the Git commit SHA or tag, and author. This information can be used for:

  • Viewing and filtering logs by version
  • Viewing the Git SHA or tag in the deployment history
  • Rolling back to a previous version via Git SHA or tag

Logging

When deploying from a Git repo the commit is also available in the logs for display and filtering, for example the tag v1.8.2 in the following log output:

Mar 15th 11:32:54am INFO production v1.8.2 request: id=467991e8-287f-11e8-bd4e-0ba9f514a0f0 ip=207.194.38.50 method=GET path=/favicon.ico
Mar 15th 11:32:54am INFO production v1.8.2 response: duration=0s id=467991e8-287f-11e8-bd4e-0ba9f514a0f0 ip=207.194.38.50 method=GET path=/favicon.ico size=66 B status=200

Filtering can be performed with the commit field:

$ up logs 'commit = "v1.8.2"'

Deployment History

Up Pro allows you to view deployment history via up deploys which will display the Git SHA, tag, or Lambda version if you are not using Git for the project.

$ up deploys

 Stage       Version  Author          Date           

 production  v1.8.0   TJ Holowaychuk  22 minutes ago
 production  v1.7.3   TJ Holowaychuk  23 minutes ago
 staging     f4f3143  TJ Holowaychuk  24 minutes ago
 staging     ca781f7  TJ Holowaychuk  24 minutes ago
 production  v1.7.2   TJ Holowaychuk  56 minutes ago
 staging     v1.7.2   TJ Holowaychuk  2 hours ago    
 production  7e62daf  TJ Holowaychuk  2 hours ago    
 production  v1.7.1   TJ Holowaychuk  2 hours ago    
 staging     v1.7.1   TJ Holowaychuk  2 hours ago    
 staging     15c46ba  TJ Holowaychuk  2 hours ago    
 staging     15c46ba  TJ Holowaychuk  2 hours ago    
 staging     74f9a92  TJ Holowaychuk  2 hours ago

Rollbacks

As mentioned in the rollback command section, with Up Pro you may use the Git tag or SHA for reverting to an older release:

$ up rollback -s production v1.8.0

Help

I didn’t receive a sign-in or certificate confirmation email

AWS email delivery can be slow sometimes. Please give it 30-60s. Otherwise, be sure to check your spam folder.

My application times out or seems slow

Lambda memory scales CPU alongside RAM, so if your application is slow to initialize or serve responses, you may want to try 1024 or above. See Lambda Pricing for options.

Ensure that all of your dependencies are deployed. You may use up -v to view what is added or filtered from the deployment or up build --size to output the contents of the zip.

I’m seeing 404 Not Found responses

By default, Up ignores files which are found in .upignore. Use the verbose flag such as up -v to see if files have been filtered or up build --size to see a list of files within the zip sorted by size. See Ignoring Files for more information.

My deployment seems stuck

The first deploy also creates resources associated with your project and can take roughly 1-2 minutes. AWS provides limited granularity into the creation progress of these resources, so the progress bar may appear “stuck”.

How do I sign into my team?

Run up team login if you aren’t signed in, then run up team login --team my-team-id to sign into any teams you’re an owner or member of.

Unable to associate certificate error

If you receive a Unable to associate certificate error it is because you have not verified the SSL certificate. Certs for CloudFront when creating a custom domain MUST be in us-east-1, so if you need to manually resend verification emails visit ACM in US East 1.

I’m seeing 403 Forbidden errors in CI

If you run into “403 Forbidden” errors this is due to GitHub’s low rate limit for unauthenticated users, consider creating a Personal Access Token and adding GITHUB_TOKEN to your CI.

FAQ

Is this a hosted service?

There are currently no plans for a hosted version. Up lets you deploy applications to your own AWS account for isolation, security, and longevity — don’t worry about a startup going out of business.

How much does Up Pro cost?

Up’s subscription fee is currently $20/mo USD. When subscribed, your team has access to Up Pro updates until the subscription is cancelled. When cancelled, you receive access until the end of your billing period.

For the subscription, you get unlimited access within your organization; there is no additional fee per team member or “seat”. You can deploy any number of applications as you wish.

Note that AWS charges for use of its resources. However, most small to medium applications will fit within the AWS free tier.

What platforms does Up support?

Currently AWS via API Gateway and Lambda are supported, this is the focus until Up is nearing feature completion, after which additional providers such as GCP and Azure will be added.

How is this different than other serverless frameworks?

Most of the AWS Lambda based tools are function-oriented, while Up abstracts this away entirely. Up does not use framework “shims”, the servers that you run using Up are regular HTTP servers and require no code changes for Lambda compatibility.

Up keeps your apps and APIs portable, makes testing them locally easier, and prevents vendor lock-in. The Lambda support for Up is simply an implementation detail, you are not coupled to API Gateway or Lambda. Up uses the API Gateway proxy mode to send all requests (regardless of path or method) to your application.

If you’re looking to manage function-level event processing pipelines, Apex or Serverless are likely better candidates, however if you’re creating applications, apis, micro services, or websites, Up is built for you.

Why run HTTP servers in Lambda?

You might be thinking this defeats the purpose of Lambda, however most people just want to use the tools they know and love. Up lets you be productive developing locally as you normally would, Lambda for hosting is only an implementation detail.

With Up you can use any Python, Node, Go, or Java framework you’d normally use to develop, and deploy with a single command, while maintaining the cost effectiveness, self-healing, and scaling capabilities of Lambda.

How much does it cost to run an application?

AWS API Gateway provides 1 million free requests per month, so there’s a good chance you won’t have to pay anything at all. Beyond that view the AWS Pricing for more information.

How well does it scale?

Up scales to fit your traffic on-demand, you don’t have to do anything beyond deploying your code. There’s no restriction on the number of concurrent instances, apps, custom domains and so on.

How much latency does Up’s reverse proxy introduce?

With a 512mb Lambda function Up introduces an average of around 500µs (microseconds) per request.

Can I remove the /staging and /production paths?

Up uses AWS API Gateway, which imposes the stage base paths. Currently there is no way to remove them, however when you use custom domains these paths are not present.

Do the servers stay active while idle?

This depends on the platform, and with Lambda being the initial platform provided the current answer is no, the server(s) are frozen when inactive and are otherwise “stateless”.

Typically relying on background work in-process is an anti-pattern as it does not scale. Lambda functions combined with CloudWatch scheduled events for example are a good way to handle this kind of work, if you’re looking for a scalable alternative.

What databases can I use?

You’re not limited to databases from any given platform, such as AWS Provided that the database host provides authentication, you can use anything. See the Wiki for a list of managed & serverless database solutions.

Why is Up licensed as GPLv3?

Up is licensed in such a way that myself as an independent developer can continue to improve the product and provide support. Commercial customers receive access to a premium version of Up with additional features, priority support for bugfixes, and of course knowing that the project will stick around! Up saves your team countless hours maintaining infrastructure and custom tooling, so you can get back to what makes your company and products unique.

Can I donate?

Yes you can! Head over to the OpenCollective page. Any donations are greatly appreciated and help me focus more on Up’s implementation, documentation, and examples. If you’re using the free OSS version for personal or commercial use please consider giving back, even a few bucks buys a coffee :).