Lucky Framework deployment with Apex Up

Dusty Candland | | lucky, luckyframework, apexup, aws, crystal

Hosting a Lucky Framework application on AWS Lambda using Apex Up.

Crystal Version: 0.35.1 Lucky Version: 0.25


The app needs to be build in a docker container. Crystal provides an image that we can use.

I used a make file to run on the docker image. I'm building an API and don't need Node/Yarn. Might need a custom docker image with those installed.

# Makefile
.PHONY: help

IS_PROD := $(filter prod, $(MAKECMDGOALS))
STAGE := $(if $(IS_PROD),prod,development)

@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

prod: ## Set the deploy target to prod
@echo "Setting Prod"

build: ## Build server.go
shards install
crystal build -o server src/ --release --static

clean: ## Remove exec
rm -f server

Apex Up Configuration

Apex docs are good, but you need to setup your VPC info before the first up run.

There are environment secrets in this file with the OSS version. The Pro version allows encrypted environment variables.

up.json configuration file

"name": "my-app",
"profile": "my_aws_profile",
"regions": [
"environment": {
"LUCKY_ENV": "production",
"SECRET_KEY_BASE": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
"DATABASE_URL": "postgresql://",
"SEND_GRID_KEY": "unused",
"hooks": {
"build": "docker run --rm -v $(pwd):/src -w /src crystallang/crystal make prod clean build",
"clean": "rm server"
"lambda": {
"memory": 512,
"vpc": {
"subnets": [
"security_groups": [

The APP_DOMAIN environment variable won't be known until after the first deployment, update and then redeploy.

Add an .upignore file to exclude everything except the server binary and the ./config/watch.yml file. The yml file shouldn't be needed, but it seemed to error without it.


Database setup

I created a DB using AWS RDS service. Not sure why it didn't create a database, but I had to do that manually.

  • Create an EC2 server and SSH to it.
  • Install postgres-client
  • Make sure the postgres security group allows connections from the VPC ip range.
  • Connect to the postgres database & create the database
sudo apt-get update
sudo apt-get install postgresql-client

psql "postgresql://"
create database my_app_staging;

Lucky setup

Need to setup the DB when the app starts. Not the most effienct way, but I added the DB setup to the file.

  • Setup migration tracking tables
  • Run migrations
  • Ensure everything is good
  • Run the required data seeds
# src/
require "./app"
require "../tasks/db/seed/"


if Lucky::Env.development?!

if Lucky::Env.production?
Avram::Migrator::Runner.setup_migration_tracking_tables true).call!

app_server =
puts "Listening on http://#{}:#{app_server.port}"

Signal::INT.trap do



Run the up command to deploy.


These are webmentions via the IndieWeb and Mention this post from your site: