Skip to content

Container Apps

Deploy applications from source code. Basepod builds your Dockerfile and runs it as a container.

Overview

Container apps are built from your source code using a Dockerfile:

  • Full control over your runtime environment
  • Support for any language or framework
  • Persistent storage with volumes
  • Environment variable configuration

Quick Start

bash
cd my-project
bp init
bp deploy

basepod.yaml:

yaml
name: my-app
type: container
port: 3000

build:
  dockerfile: Dockerfile

Dynamic Languages

Node.js

basepod.yaml:

yaml
name: my-node-app
type: container
port: 3000

build:
  dockerfile: Dockerfile

env:
  NODE_ENV: production

Dockerfile:

dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

Node.js with Bun

Dockerfile:

dockerfile
FROM oven/bun:1-alpine
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --production
COPY . .
EXPOSE 3000
CMD ["bun", "run", "index.ts"]

Express.js

Dockerfile:

dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

NestJS

Dockerfile:

dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/main.js"]

Nuxt (SSR)

basepod.yaml:

yaml
name: my-nuxt-app
type: container
port: 3000

build:
  dockerfile: Dockerfile

env:
  NITRO_PRESET: node-server

Dockerfile:

dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]

Next.js (SSR)

basepod.yaml:

yaml
name: my-next-app
type: container
port: 3000

build:
  dockerfile: Dockerfile

Dockerfile:

dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["npm", "start"]

Python / Flask

basepod.yaml:

yaml
name: my-flask-app
type: container
port: 5000

build:
  dockerfile: Dockerfile

Dockerfile:

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]

Python / FastAPI

basepod.yaml:

yaml
name: my-fastapi-app
type: container
port: 8000

build:
  dockerfile: Dockerfile

env:
  PYTHONUNBUFFERED: "1"

Dockerfile:

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Python / Django

Dockerfile:

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "-b", "0.0.0.0:8000"]

Ruby on Rails

basepod.yaml:

yaml
name: my-rails-app
type: container
port: 3000

build:
  dockerfile: Dockerfile

env:
  RAILS_ENV: production
  RAILS_LOG_TO_STDOUT: "true"

Dockerfile:

dockerfile
FROM ruby:3.3-slim
RUN apt-get update && apt-get install -y build-essential libpq-dev nodejs
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install --without development test
COPY . .
RUN bundle exec rake assets:precompile
EXPOSE 3000
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]

PHP / Laravel

basepod.yaml:

yaml
name: my-laravel-app
type: container
port: 80

build:
  dockerfile: Dockerfile

env:
  APP_ENV: production

Dockerfile:

dockerfile
FROM php:8.3-fpm-alpine

RUN apk add --no-cache nginx supervisor
RUN docker-php-ext-install pdo pdo_mysql

WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader

COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/supervisord.conf /etc/supervisord.conf

EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

PHP / Symfony

Dockerfile:

dockerfile
FROM php:8.3-fpm-alpine
RUN apk add --no-cache nginx
RUN docker-php-ext-install pdo pdo_mysql opcache
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader
RUN php bin/console cache:clear --env=prod
EXPOSE 80
CMD ["php-fpm"]

Compiled Languages

Go

basepod.yaml:

yaml
name: my-go-app
type: container
port: 8080

build:
  dockerfile: Dockerfile

Dockerfile:

dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o main .

FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/main /main
EXPOSE 8080
CMD ["/main"]

Go / Fiber

Dockerfile:

dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o main .

FROM scratch
COPY --from=builder /app/main /main
EXPOSE 3000
CMD ["/main"]

Rust

basepod.yaml:

yaml
name: my-rust-app
type: container
port: 8080

build:
  dockerfile: Dockerfile

Dockerfile:

dockerfile
FROM rust:1.75-alpine AS builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY . .
RUN cargo build --release

FROM alpine:latest
COPY --from=builder /app/target/release/myapp /myapp
EXPOSE 8080
CMD ["/myapp"]

.NET / ASP.NET Core

basepod.yaml:

yaml
name: my-dotnet-app
type: container
port: 8080

build:
  dockerfile: Dockerfile

env:
  ASPNETCORE_URLS: http://+:8080
  ASPNETCORE_ENVIRONMENT: Production

Dockerfile:

dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
EXPOSE 8080
CMD ["dotnet", "MyApp.dll"]

Java / Spring Boot

basepod.yaml:

yaml
name: my-spring-app
type: container
port: 8080

build:
  dockerfile: Dockerfile

env:
  JAVA_OPTS: "-Xmx512m"

Dockerfile:

dockerfile
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests

FROM eclipse-temurin:21-jre-alpine
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

Elixir / Phoenix

basepod.yaml:

yaml
name: my-phoenix-app
type: container
port: 4000

build:
  dockerfile: Dockerfile

env:
  MIX_ENV: prod
  SECRET_KEY_BASE: ${SECRET_KEY_BASE}

Dockerfile:

dockerfile
FROM elixir:1.16-alpine AS builder
RUN apk add --no-cache build-base npm
WORKDIR /app
ENV MIX_ENV=prod
COPY mix.exs mix.lock ./
RUN mix deps.get --only prod
COPY . .
RUN mix assets.deploy
RUN mix release

FROM alpine:latest
RUN apk add --no-cache libstdc++ openssl ncurses-libs
WORKDIR /app
COPY --from=builder /app/_build/prod/rel/myapp ./
EXPOSE 4000
CMD ["bin/myapp", "start"]

Configuration Options

Environment Variables

yaml
name: my-app
type: container
port: 3000

env:
  DATABASE_URL: postgres://localhost/mydb
  API_KEY: ${API_KEY}          # From shell
  DEBUG: "false"

Volumes (Persistent Storage)

yaml
name: my-app
type: container
port: 3000

volumes:
  - data:/app/data
  - uploads:/app/uploads

Resource Limits

yaml
name: my-app
type: container
port: 3000

resources:
  memory: 512m
  cpus: 1.0

Build Arguments

yaml
name: my-app
type: container
port: 3000

build:
  dockerfile: Dockerfile
  args:
    NODE_ENV: production
    API_URL: https://api.example.com

Ignored Files

These are automatically excluded from uploads:

  • .git/
  • node_modules/
  • .env, .env.local
  • __pycache__/, *.pyc
  • vendor/ (PHP)
  • target/ (Rust, Java)
  • .next/, .nuxt/, .output/

Add custom ignores in .basepodignore:

*.log
tmp/
coverage/

Deploying Updates

bash
# Make changes
git add . && git commit -m "Update"

# Deploy
bp deploy

Basepod will:

  1. Build a new image
  2. Stop the old container
  3. Start the new container
  4. Clean up old images

Released under the MIT License.