Examples
Real-world examples and configurations for iop deployments
Examples
Real-world examples showing how to deploy different types of applications with iop.
Basic Web Application
A simple HTTP server deployed with zero-downtime.
Go Application
Here's a complete example of deploying a Go web application:
main.go:
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func handler(w http.ResponseWriter, r *http.Request) {
hostname, _ := os.Hostname()
fmt.Fprintf(w, "Hello from %s!\n", hostname)
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "OK")
}
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/api/health", healthHandler)
port := os.Getenv("PORT")
if port == "" {
port = "3000"
}
log.Printf("Server starting on port %s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
Dockerfile:
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o main .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 3000
CMD ["./main"]
iop.yml:
name: my-go-app
ssh:
username: deploy
apps:
web:
build:
context: .
dockerfile: Dockerfile
servers:
- your-server.com
environment:
plain:
- PORT=3000
secret:
- SECRET_VAR
proxy:
hosts:
- myapp.com
app_port: 3000
health_check:
path: /api/health
Deployment
iop init # Creates configuration files
# Edit iop.yml with your settings
iop setup # Prepare server
iop deploy # Deploy app
Next.js Application
Deploy a full-stack Next.js application with production optimizations.
next.config.ts:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
experimental: {
outputFileTracingRoot: undefined,
},
};
module.exports = nextConfig;
Dockerfile:
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
# Health check endpoint
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/up || exit 1
CMD ["node", "server.js"]
iop.yml:
name: my-nextjs-app
ssh:
username: deploy
apps:
web:
build:
context: .
dockerfile: Dockerfile
servers:
- your-server.com
environment:
plain:
- NODE_ENV=production
proxy:
hosts:
- mynextapp.com
app_port: 3000
health_check:
path: /up
Health check page (src/pages/up.tsx
):
import { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ status: "ok" });
}
Full-Stack Application with Database
Deploy a complete application with frontend, API, and PostgreSQL database.
iop.yml:
name: ecommerce-app
ssh:
username: deploy
port: 22
apps:
frontend:
image: ecommerce/frontend
servers:
- web1.mysite.com
- web2.mysite.com
build:
context: ./frontend
dockerfile: Dockerfile
proxy:
hosts:
- shop.mysite.com
- www.shop.mysite.com
app_port: 3000
environment:
plain:
- NODE_ENV=production
- API_URL=https://api.shop.mysite.com
secret:
- STRIPE_PUBLIC_KEY
health_check:
path: /health
api:
image: ecommerce/backend
servers:
- api.mysite.com
build:
context: ./backend
dockerfile: Dockerfile
proxy:
hosts:
- api.shop.mysite.com
app_port: 8080
environment:
plain:
- NODE_ENV=production
- PORT=8080
secret:
- DATABASE_URL
- JWT_SECRET
- STRIPE_SECRET_KEY
health_check:
path: /api/health
services:
postgres:
image: postgres:15
servers:
- db.mysite.com
environment:
plain:
- POSTGRES_DB=ecommerce
- POSTGRES_USER=ecommerce
secret:
- POSTGRES_PASSWORD
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ecommerce"]
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:7
servers:
- cache.mysite.com
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 3s
retries: 3
.iop/secrets:
DATABASE_URL=postgres://ecommerce:secure_password@db.mysite.com:5432/ecommerce
POSTGRES_PASSWORD=secure_password
JWT_SECRET=your-jwt-secret
STRIPE_PUBLIC_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
Deployment Steps
# Deploy services first (database, cache)
iop deploy --services
# Then deploy applications
iop deploy
# Check everything is running
iop status
Microservices Architecture
Deploy multiple microservices with load balancing and service discovery.
iop.yml:
name: microservices-platform
ssh:
username: deploy
apps:
gateway:
image: platform/gateway
servers:
- gateway.platform.com
build:
context: ./gateway
proxy:
hosts:
- api.platform.com
app_port: 8080
environment:
secret:
- JWT_SECRET
health_check:
path: /health
user-service:
image: platform/users
replicas: 3
servers:
- app1.platform.com
- app2.platform.com
build:
context: ./services/users
proxy:
hosts:
- users.platform.com
app_port: 8081
environment:
secret:
- DATABASE_URL
- JWT_SECRET
health_check:
path: /api/users/health
order-service:
image: platform/orders
replicas: 2
servers:
- app1.platform.com
- app2.platform.com
build:
context: ./services/orders
proxy:
hosts:
- orders.platform.com
app_port: 8082
environment:
secret:
- DATABASE_URL
- PAYMENT_SERVICE_URL
health_check:
path: /api/orders/health
payment-service:
image: platform/payments
servers:
- secure.platform.com
build:
context: ./services/payments
proxy:
hosts:
- payments.platform.com
app_port: 8083
environment:
secret:
- DATABASE_URL
- STRIPE_SECRET_KEY
- ENCRYPTION_KEY
health_check:
path: /api/payments/health
services:
postgres:
image: postgres:15
servers:
- db1.platform.com
environment:
plain:
- POSTGRES_DB=platform
- POSTGRES_USER=platform
secret:
- POSTGRES_PASSWORD
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7
servers:
- cache.platform.com
volumes:
- redis_data:/data
Multi-Environment Setup
Deploy the same application to different environments with environment-specific configurations.
iop.staging.yml:
name: myapp-staging
ssh:
username: deploy
apps:
web:
image: myapp/web
servers:
- staging.myapp.com
build:
context: .
dockerfile: Dockerfile
proxy:
hosts:
- staging.myapp.com
app_port: 3000
environment:
plain:
- NODE_ENV=staging
- API_URL=https://staging-api.myapp.com
secret:
- DATABASE_URL_STAGING
- STRIPE_TEST_KEY
api:
image: myapp/api
servers:
- staging.myapp.com
build:
context: ./api
proxy:
hosts:
- staging-api.myapp.com
app_port: 8080
environment:
secret:
- DATABASE_URL_STAGING
services:
postgres:
image: postgres:15
servers:
- staging.myapp.com
environment:
plain:
- POSTGRES_DB=myapp_staging
secret:
- POSTGRES_PASSWORD_STAGING
volumes:
- postgres_staging_data:/var/lib/postgresql/data
iop.production.yml:
name: myapp-production
ssh:
username: deploy
apps:
web:
image: myapp/web
replicas: 3
servers:
- web1.myapp.com
- web2.myapp.com
- web3.myapp.com
build:
context: .
dockerfile: Dockerfile.prod
proxy:
hosts:
- myapp.com
- www.myapp.com
app_port: 3000
environment:
plain:
- NODE_ENV=production
- API_URL=https://api.myapp.com
secret:
- DATABASE_URL_PROD
- STRIPE_LIVE_KEY
api:
image: myapp/api
replicas: 2
servers:
- api1.myapp.com
- api2.myapp.com
build:
context: ./api
dockerfile: Dockerfile.prod
proxy:
hosts:
- api.myapp.com
app_port: 8080
environment:
secret:
- DATABASE_URL_PROD
services:
postgres:
image: postgres:15
servers:
- db1.myapp.com
- db2.myapp.com # Primary/replica setup
environment:
plain:
- POSTGRES_DB=myapp_production
secret:
- POSTGRES_PASSWORD_PROD
volumes:
- postgres_prod_data:/var/lib/postgresql/data
Environment Deployment
# Deploy to staging
iop deploy -c iop.staging.yml
# Test staging environment
curl https://staging.myapp.com/health
# Deploy to production
iop deploy -c iop.production.yml
# Monitor production
iop status -c iop.production.yml
CI/CD Integration
GitHub Actions
.github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install iop
run: npm install -g iop
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
- name: Create secrets file
run: |
mkdir -p .iop
echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> .iop/secrets
echo "API_KEY=${{ secrets.API_KEY }}" >> .iop/secrets
- name: Deploy to production
run: iop deploy -c iop.production.yml
GitLab CI
.gitlab-ci.yml:
stages:
- deploy
deploy:
stage: deploy
image: node:18
before_script:
- npm install -g iop
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts
- mkdir -p .iop
- echo "DATABASE_URL=$DATABASE_URL" >> .iop/secrets
script:
- iop deploy -c iop.production.yml
only:
- main
Best Practices
Security
- Use dedicated deployment user:
ssh:
username: deploy # Not root
- Separate environment secrets:
# .iop/secrets.staging
DATABASE_URL=postgres://...staging...
# .iop/secrets.production
DATABASE_URL=postgres://...production...
- Network security:
services:
postgres:
ports:
- "127.0.0.1:5432:5432" # Bind to localhost only
Performance
- Multi-stage Docker builds:
FROM node:18 AS builder
# Build steps...
FROM node:18-alpine AS runtime
COPY --from=builder /app/dist ./dist
- Health check optimization:
health_check:
path: /health # Lightweight endpoint
- Resource limits:
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
Monitoring
- Comprehensive health checks:
app.get("/health", async (req, res) => {
try {
await db.ping();
await redis.ping();
res.status(200).json({ status: "healthy" });
} catch (error) {
res.status(503).json({ status: "unhealthy", error: error.message });
}
});
- Status monitoring:
# Check all environments
iop status -c iop.staging.yml
iop status -c iop.production.yml
These examples provide a solid foundation for deploying various types of applications with iop. Adapt them to your specific needs and infrastructure requirements.