Quick Start
Deploy your first application with iop in minutes
Quick Start
Get your first application deployed with iop in just a few minutes. This guide will walk you through creating a simple web application and deploying it to your server.
Prerequisites
Before you begin, make sure you have:
- A server with SSH access (Ubuntu/Debian recommended)
- Docker installed locally for building images
- A domain name pointing to your server (optional, but recommended for SSL)
Step 1: Initialize Your Project
Navigate to your project directory and initialize iop:
cd your-project
iop init
You'll be prompted for a project name, or you can use non-interactive mode:
iop init --name my-app --non-interactive
This creates two files:
iop.yml
- Your deployment configuration.iop/secrets
- Secure credentials storage (automatically added to.gitignore
)
Step 2: Configure Your Deployment
Edit the generated iop.yml
file:
name: my-app
ssh:
username: iop # or root, or your deployment user
apps:
web:
build:
context: .
dockerfile: Dockerfile
server: your-server.com # Replace with your server IP or domain
environment:
plain:
- NODE_ENV=production
secret:
- DATABASE_URL # Optional: from .iop/secrets
proxy:
app_port: 3000 # Port your app runs on inside the container
health_check:
path: /up # Health check endpoint (default: /up)
# Optional: Add a database service
# services:
# db:
# image: postgres:17
# server: your-server.com
# ports:
# - "5432:5432"
# environment:
# plain:
# - POSTGRES_USER=postgres
# - POSTGRES_DB=my-app
# secret:
# - POSTGRES_PASSWORD
# volumes:
# - ./pgdata:/var/lib/postgresql/data
Key Configuration Options
name
- Your project name (used for Docker networks and container naming)server
- Your server IP or domain nameproxy.app_port
- Port your application runs on inside the containerbuild.context
- Docker build context (usually.
)health_check.path
- Health check endpoint (default:/up
)
Step 3: Add Secrets (Optional)
If your app needs environment variables with sensitive values, add them to .iop/secrets
:
# .iop/secrets
DATABASE_URL=postgres://user:pass@localhost:5432/myapp
API_KEY=your-secret-api-key
POSTGRES_PASSWORD=supersecret
Important: .iop/secrets
is automatically added to your .gitignore
file for security.
Step 4: Prepare Your Dockerfile
Make sure you have a Dockerfile
in your project. Here's a simple example for a Node.js app:
FROM node:18-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci --only=production
# Copy source code
COPY . .
# Build the app (if needed)
RUN npm run build
EXPOSE 3000
# Start the application
CMD ["npm", "start"]
Important: Health Check Endpoint
Your app must implement a health check endpoint. By default, iop expects /up
:
// Express.js example
app.get("/up", (req, res) => {
res.status(200).send("OK");
});
You can customize the health check path in iop.yml
:
health_check:
path: /api/health # Custom health check endpoint
Step 5: Deploy!
Deploy your application with a single command:
iop
That's it! iop will automatically:
- ✅ Build your Docker image locally
- ✅ Set up your server if needed (install Docker, create networks, set up proxy)
- ✅ Transfer the image securely via SSH (no registry required)
- ✅ Deploy with zero downtime using blue-green deployment
- ✅ Configure the reverse proxy for routing and SSL
- ✅ Verify health checks before switching traffic
Example Output
❯ iop
Using Git SHA for release ID: a1b2c3d
Starting deployment with release a1b2c3d
[✓] Configuration loaded (0ms)
[✓] Git status verified (3ms)
[✓] Infrastructure ready (1.2s)
Building Images
[✓] web → my-app/web:a1b2c3d (45.2s)
Deploying to Servers
└─ your-server.com
├─ [✓] Loading image (3.2s)
├─ [✓] Zero-downtime deployment (2.8s)
└─ [✓] Configuring proxy (0.8s)
[✓] Deployment completed successfully in 52.1s
Your app is live at:
└─ https://your-server.com (web)
Step 6: Verify Your Deployment
Check the status of your deployment:
iop status
Output:
❯ iop status
📱 App: web
Status: ✅ RUNNING (green active)
Replicas: 1/1 running
Image: my-app/web:a1b2c3d
Servers: your-server.com
Last Deployed: 2 minutes ago
Uptime: 2m 15s
Resource Usage: CPU 2.3%, Memory 125MB
🔧 Proxy Status:
your-server.com: ✅ RUNNING (port 80, 443)
- Version: elitan/iop-proxy:latest
- Uptime: 2m 30s
- Active routes: 1
Visit your domain - it should be live with automatic HTTPS!
What Happened Behind the Scenes?
During deployment, iop:
- Validated configuration and checked git status
- Built your Docker image locally using your Dockerfile
- Set up the server automatically:
- Installed Docker (if needed)
- Created Docker networks
- Deployed the iop reverse proxy for SSL and routing
- Transferred the image securely via SSH (compressed with docker save/load)
- Performed zero-downtime deployment using blue-green strategy:
- Started new container alongside old one
- Ran health checks on new container
- Switched traffic atomically via network aliases
- Removed old container
- Configured SSL certificates automatically via Let's Encrypt
- Updated proxy routing to direct traffic to your app
Adding Custom Domains
To use a custom domain instead of your server IP:
- Point your domain to your server's IP address
- Add the domain to your config:
apps:
web:
# ... other config
proxy:
hosts:
- myapp.com
- www.myapp.com
app_port: 3000
ssl: true # Automatic HTTPS (default: true)
- Redeploy:
iop
iop will automatically:
- Obtain SSL certificates from Let's Encrypt
- Configure HTTPS redirect
- Update proxy routing
Next Steps
Now that you have your first app deployed, explore more features:
Multi-Server Deployment
Deploy the same app to multiple servers for load balancing:
apps:
web:
# ... other config
server: server1.com # Just change to single server per app
# For multiple servers, deploy multiple apps:
web-backup:
# ... same config
server: server2.com
Add a Database Service
Add a PostgreSQL database to your deployment:
services:
db:
image: postgres:17
server: your-server.com
ports:
- "5432:5432"
environment:
plain:
- POSTGRES_USER=postgres
- POSTGRES_DB=my-app
secret:
- POSTGRES_PASSWORD
volumes:
- ./pgdata:/var/lib/postgresql/data
Don't forget to add the password to .iop/secrets
:
POSTGRES_PASSWORD=your-secure-password
Multiple Replicas
Scale your app with multiple replicas:
apps:
web:
# ... other config
replicas: 3 # Run 3 instances for load balancing
Environment-Specific Deployments
Create different config files for different environments:
# iop.staging.yml
name: my-app-staging
# ... staging config
# iop.production.yml
name: my-app-production
# ... production config
Deploy to specific environments:
iop -c iop.staging.yml # Deploy to staging
iop -c iop.production.yml # Deploy to production
Common Issues and Solutions
Build Failures
Problem: Docker build fails
Solutions:
- Test locally:
docker build .
- Check your Dockerfile syntax
- Ensure all files are included in build context
- Use
iop --verbose
for detailed build output
Health Check Failures
Problem: Deployment fails with "Health check failed"
Solutions:
- Ensure your app has a health check endpoint (default:
/up
) - Make sure the endpoint returns HTTP 200
- Check that your app is listening on the correct port
- Verify
app_port
in config matches your app's port
SSH Connection Issues
Problem: Cannot connect to server
Solutions:
- Test SSH manually:
ssh user@your-server.com
- Verify the username in
iop.yml
matches your server - Check firewall settings (ports 22, 80, 443 should be open)
- Use
iop --verbose
for detailed connection info
SSL Certificate Issues
Problem: HTTPS not working
Solutions:
- Ensure your domain points to your server IP
- Check DNS propagation:
dig your-domain.com
- Verify domain is correctly configured in
proxy.hosts
- Wait a few minutes for certificate generation
Example Projects
Check out these complete examples:
- Basic Go Application - Simple HTTP server with database
- Next.js Application - Full-stack React app
- Plausible Analytics - Real-world analytics deployment
Getting Help
Need help? Here are your options:
- Use help commands:
iop --help
oriop <command> --help
- Verbose output: Add
--verbose
to any command for detailed logs - Check status:
iop status --verbose
shows detailed deployment info - View proxy logs:
iop proxy logs --lines 100
You're now ready to deploy with confidence! 🚀