Conduit (Serverless & CloudFront) Quickstart

Deploying the Conduit Web App

The “RealWorld” demo app named Conduit provides a simple demonstration of using Runway to deploy a Serverless Framework backend with an Angular frontend.


  • An AWS account, and configured terminal environment for interacting with it with an admin role.

  • The following installed tools:

    • npm

    • yarn

    • git (Available out of the box on macOS)


  1. Prepare the project directory. See Repo Structure for more details.

    mkdir conduit
    cd conduit
    git init
    git checkout -b ENV-dev
  2. Download/install Runway. Here we are showing the curl option. To see other available install methods, see Installation.


    curl -L -o runway
    chmod +x runway


    curl -L -o runway
    chmod +x runway


    iwr -Uri -OutFile runway.exe
  3. Download the source files.


    curl -O
    unzip v1.0.0
    rm v1.0.0
    mv realworld-dynamodb-lambda-1.0.0 backend
    cd backend
    sed -i '/package-lock\.json/d' .gitignore
    echo '.dynamodb' >> .gitignore
    npm install
    cd ..
    curl -O
    unzip 35a66d144d8def340278cd55080d5c745714aca4
    rm 35a66d144d8def340278cd55080d5c745714aca4
    mv angular-realworld-example-app-35a66d144d8def340278cd55080d5c745714aca4 frontend
    cd frontend
    mkdir scripts
    cd scripts && { curl -O ; cd -; }
    sed -i 's/^\s*"build":\s.*$/    "build": "node scripts\/build",/' package.json
    sed -i 's/^\s*"rxjs":\s.*$/    "rxjs": "~6.3.3",/' package.json
    npm install
    curl -O
    cd ..
    curl -O


    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    Invoke-WebRequest -OutFile
    Expand-Archive .
    Remove-Item -Force
    Rename-Item realworld-dynamodb-lambda-1.0.0 backend
    cd backend
    (gc .\.gitignore -raw).Replace("package-lock.json`n", "") | sc .\.gitignore
    ".dynamodb`r`n" | Out-File .\.gitignore -Append -Encoding UTF8
    $(gc .\package.json) -replace "dynamodb install .*$", "dynamodb install`"" | Out-File .\package.json -Force -Encoding UTF8
    npm install
    cd ..
    Invoke-WebRequest -OutFile
    Expand-Archive .
    Remove-Item -Force
    Rename-Item angular-realworld-example-app-35a66d144d8def340278cd55080d5c745714aca4 frontend
    cd frontend
    (gc .\package.json -raw).Replace("`"rxjs`": `"^6.2.1`"", "`"rxjs`": `"~6.3.3`"") | sc .\package.json
    mkdir scripts
    Invoke-WebRequest -OutFile scripts/build.js
    $(gc .\package.json) -replace "^\s*`"build`":\s.*$", "    `"build`": `"node scripts/build`"," | Out-File .\package.json -Force -Encoding UTF8
    npm install
    Invoke-WebRequest -OutFile
    cd ..
    Invoke-WebRequest -OutFile Pipfile
    Invoke-WebRequest -OutFile runway.yml


Execute pipenv run runway deploy, enter all (to deploy the backend followed by the frontend). Deployment will take some time (mostly waiting for the CloudFront distribution to stabilize).

The CloudFront domain at which the site can be reached will be displayed near the last lines of output once deployment is complete, e.g.:

staticsite: sync & CF invalidation of E17B5JWPMTX5Z8 (domain complete


Execute pipenv run runway destroy, enter all.

The backend DynamoDB tables will still be retained after the destroy is complete. They must be deleted separately:

On macOS/Linux:

for i in realworld-dev-articles realworld-dev-comments realworld-dev-users; do aws dynamodb delete-table --region us-east-1 --table-name $i; done

On Windows:

foreach($table in @("realworld-dev-articles", "realworld-dev-comments", "realworld-dev-users"))
  CMD /C "pipenv run aws dynamodb delete-table --region us-east-1 --table-name $table"

Next Steps / Additional Notes

The serverless-plugin-export-endpoints plugin is a good alternative to the custom script deployed above to update the environment file.


The specific IAM permissions required to manage the resources in this demo are as follows

# CloudFormation
- cloudformation:CreateStack
- cloudformation:DeleteStack
- cloudformation:CreateChangeSet
- cloudformation:DescribeChangeSet
- cloudformation:DeleteChangeSet
- cloudformation:DescribeStackResource
- cloudformation:DescribeStackResources
- cloudformation:DescribeStacks
- cloudformation:DescribeStackEvents
- cloudformation:GetTemplate
- cloudformation:UpdateStack
- cloudformation:ExecuteChangeSet
- cloudformation:ValidateTemplate
# Serverless
- apigateway:GET
- apigateway:DELETE
- apigateway:POST
- apigateway:PUT
- lambda:AddPermission
- lambda:CreateAlias
- lambda:CreateFunction
- lambda:DeleteAlias
- lambda:DeleteFunction
- lambda:GetFunction
- lambda:GetFunctionConfiguration
- lambda:ListVersionsByFunction
- lambda:PublishVersion
- lambda:UpdateAlias
- lambda:UpdateFunctionCode
- lambda:UpdateFunctionConfiguration
- iam:CreateRole
- iam:DeleteRole
- iam:DeleteRolePolicy
- iam:GetRole
- iam:PassRole
- iam:PutRolePolicy
- logs:CreateLogGroup
- logs:DeleteLogGroup
- logs:DescribeLogGroups
- s3:CreateBucket
- s3:DeleteBucket
- s3:DeleteBucketPolicy
- s3:DeleteObject
- s3:DeleteObjectVersion
- s3:GetObjectVersion
- s3:ListBucket
- s3:ListBucketVersions
- s3:PutBucketVersioning
- s3:PutBucketPolicy
- s3:PutLifecycleConfiguration
# Frontend
- cloudfront:CreateCloudFrontOriginAccessIdentity
- cloudfront:CreateDistribution
- cloudfront:CreateInvalidation
- cloudfront:DeleteCloudFrontOriginAccessIdentity
- cloudfront:DeleteDistribution
- cloudfront:GetCloudFrontOriginAccessIdentity
- cloudfront:GetCloudFrontOriginAccessIdentityConfig
- cloudfront:GetDistribution
- cloudfront:GetDistributionConfig
- cloudfront:GetInvalidation
- cloudfront:ListDistributions
- cloudfront:TagResource
- cloudfront:UntagResource
- cloudfront:UpdateCloudFrontOriginAccessIdentity
- cloudfront:UpdateDistribution
- s3:DeleteBucketWebsite
- s3:GetBucketAcl
- s3:GetObject
- s3:PutBucketAcl
- s3:GetBucketWebsite
- s3:PutBucketWebsite
- s3:PutObject
- ssm:GetParameter
- ssm:PutParameter
# Backend
- dynamodb:CreateTable
- dynamodb:DeleteTable
- dynamodb:DescribeTable
- dynamodb:TagResource
- dynamodb:UntagResource
- dynamodb:UpdateTable