Part 3 of 3
Free Stack Templates
Two common web stacks, pre-converted from Docker Compose to Apple Container. Grab them, swap in your project, go.
Template 1: Nginx + Node.js
A reverse proxy in front of an Express/Node.js API — the most common web stack pattern.
Docker Compose (original)
services:
app:
image: node:22-alpine
working_dir: /app
volumes:
- ./src:/app/src
- ./package.json:/app/package.json
environment:
- PORT=3000
- NODE_ENV=production
command: node src/server.js
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
Apple Container — start script
#!/bin/bash
set -e
DIR=$(cd "$(dirname "$0")" && pwd)
container machine create node-stack 2>/dev/null || true
container run --name node-app --machine node-stack \
--env PORT=3000 --env NODE_ENV=production \
--mount type=bind,src=$DIR/src,dst=/app/src \
--mount type=bind,src=$DIR/package.json,dst=/app/package.json \
node:22-alpine node src/server.js
# Wait for Node to be ready
until curl -s http://node-app.dev.internal:3000/health > /dev/null 2>&1; do
sleep 1
done
container run --name nginx-proxy --machine node-stack \
--mount type=bind,src=$DIR/nginx.conf,dst=/etc/nginx/nginx.conf \
nginx:alpine
echo "Node app: http://node-app.dev.internal:3000"
echo "Via Nginx: http://nginx-proxy.dev.internal"
nginx.conf (identical for both Docker and Apple Container)
events { worker_connections 1024; }
http {
server {
listen 80;
server_name _;
location / {
proxy_pass http://node-app.dev.internal:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Template 2: Python + PostgreSQL
Django/FastAPI/Flask app with a PostgreSQL database — data persistence and inter-container networking.
Docker Compose (original)
services:
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=app
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=appdb
volumes:
- pgdata:/var/lib/postgresql/data
web:
image: python:3.13-slim
working_dir: /app
environment:
- DATABASE_URL=postgresql://app:secret@db:5432/appdb
volumes:
- ./src:/app/src
- ./requirements.txt:/app/requirements.txt
command: uvicorn src.main:app --host 0.0.0.0 --port 8000
depends_on:
- db
volumes:
pgdata:
Apple Container — start script
#!/bin/bash
set -e
DIR=$(cd "$(dirname "$0")" && pwd)
PG_PASSWORD=secret
container machine create python-stack 2>/dev/null || true
# Create a named volume for PostgreSQL data
container volume create pgdata 2>/dev/null || true
container run --name postgres-db --machine python-stack \
--env POSTGRES_USER=app \
--env POSTGRES_PASSWORD=$PG_PASSWORD \
--env POSTGRES_DB=appdb \
--mount type=volume,src=pgdata,dst=/var/lib/postgresql/data \
postgres:16-alpine
# Wait for PostgreSQL to accept connections
until curl -s http://postgres-db.dev.internal:5432 > /dev/null 2>&1; do
sleep 1
done
container run --name python-web --machine python-stack \
--env "DATABASE_URL=postgresql://app:$PG_PASSWORD@postgres-db.dev.internal:5432/appdb" \
--mount type=bind,src=$DIR/src,dst=/app/src \
--mount type=bind,src=$DIR/requirements.txt,dst=/app/requirements.txt \
python:3.13-slim sh -c "pip install -r requirements.txt && uvicorn src.main:app --host 0.0.0.0 --port 8000"
echo "API: http://python-web.dev.internal:8000"
echo "Postgres: http://postgres-db.dev.internal:5432"
Key difference: In Docker Compose, containers reach each other by service name (
db:5432). In Apple Container, they use the FQDN (postgres-db.dev.internal:5432). The connection string changes, but the behavior is identical.
Need More Templates?
The full manual includes 3 additional premium templates: Rails+Redis, Go+PostgreSQL, and a Microservices demo with 4 services.
$39 — Production Manual with 5 templates
Get the Production ManualOr start with the Migration Guide ($29) — 2 templates included.