Most developers depend on SaaS vendors for error tracking, analytics, and deployment. We pay monthly subscriptions for Sentry, Google Analytics, and deployment platforms, accepting vendor lock-in and limited customization as the cost of convenience. But what if you could build a self-sufficient platform that you control and understand?
This article explores the journey from SaaS dependency to infrastructure independence. You’ll learn how to set up a self-hosted development platform with Docker and Coolify, including error tracking (GlitchTip), analytics (Matomo), and deployment automation. More importantly, you’ll understand the infrastructure-as-craft mindset and learn when self-hosting makes sense versus when SaaS is the right choice.
Why Self-Hosting? The Infrastructure Independence Mindset
You’re building a personal platform empire—not dependent on SaaS vendors, but on systems you control and understand. This isn’t about rejecting SaaS entirely; it’s about understanding your stack and having the option to own your infrastructure when it matters.
The Cost Reality
Let’s start with the numbers. A typical developer might pay:
- Sentry: $26/month for error tracking
- Google Analytics: Free, but with privacy concerns
- Deployment platform: $20-50/month
- Total: $46-76/month, or $552-912/year
With self-hosting, you’re paying for:
- A VPS: $5-10/month
- Domain: $12/year
- Total: $60-132/year
The cost savings are real, but they’re not the only benefit. More importantly, you’re not locked into vendor pricing changes, feature limitations, or service outages.
Control and Customization
When you self-host, you control:
- Data ownership: Your error logs, analytics data, and user data stays with you
- Feature customization: Need a specific feature? You can add it or modify the open-source tools
- Privacy compliance: GDPR, CCPA, and other regulations are easier when you control the data
- Uptime: You’re not dependent on a third-party service being available
Learning Opportunity
Self-hosting forces you to understand your stack. You’ll learn:
- Docker containerization patterns
- Database management and backups
- SSL certificate automation
- Monitoring and alerting
- System administration basics
This knowledge makes you a better developer, even if you eventually move back to managed services.
When Self-Hosting Makes Sense
Self-hosting is ideal when:
- You need data privacy and control
- You want to learn infrastructure skills
- You have predictable, manageable traffic
- You want to avoid vendor lock-in
- You need custom features not available in SaaS
Self-hosting doesn’t make sense when:
- You need enterprise-grade reliability and support
- You don’t have time to maintain infrastructure
- Your traffic is unpredictable or high-volume
- You need compliance certifications (SOC 2, etc.)
- You’re building an MVP and need to move fast
The key is understanding the trade-offs and choosing based on your specific needs, not ideology.
The Core Stack: Docker + Coolify
Docker is the foundation of modern self-hosting. It provides containerization that makes deployment consistent and reproducible. Coolify is a self-hosted deployment platform that simplifies Docker orchestration without the complexity of Kubernetes.
Docker as the Foundation
Docker containers package your application with all its dependencies, ensuring it runs the same way in development, staging, and production. This consistency eliminates “works on my machine” problems and makes deployment predictable.
Here’s a typical Dockerfile pattern from a production project:
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci --only=production
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
# Copy only production dependencies
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
# Expose port
EXPOSE 3000
# Start the application
CMD ["node", "dist/index.js"]
This multi-stage build keeps the final image small by excluding development dependencies and build tools.
docker-compose for Local Development
For local development, docker-compose simplifies running multiple services together:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
depends_on:
- db
volumes:
- ./src:/app/src
db:
image: postgres:16
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
This setup lets you run your entire stack locally with a single command: docker-compose up.
Coolify: Self-Hosted Deployment
Coolify is a self-hosted alternative to platforms like Vercel or Railway. It provides:
- One-click deployments from Git repositories
- Automatic SSL certificate management (Let’s Encrypt)
- Environment variable management
- Database provisioning
- Health monitoring
The beauty of Coolify is that it runs on your own server, giving you the convenience of a managed platform with the control of self-hosting.
CoolerCoolify: Enhancing the Tools You Use
One project that demonstrates the infrastructure-as-craft mindset is CoolerCoolify—a Laravel package that enhances Coolify’s UI with search, sorting, drag-and-drop, and icon support. This project shows that you’re not just using tools; you’re improving them, wrapping them, making them yours.
When you self-host, you can customize and enhance the tools you use. You’re not limited by what a SaaS vendor provides.
Building the Monitoring Stack
A self-hosted platform needs monitoring. You need to know when things break, how your applications perform, and what your users are doing.
GlitchTip: Sentry-Compatible Error Tracking
GlitchTip is a self-hosted, Sentry-compatible error tracking service. It provides the same API and features as Sentry, so you can use the same SDKs in your applications.
Setting up GlitchTip with Docker is straightforward:
version: '3.8'
services:
glitchtip:
image: glitchtip/glitchtip:latest
environment:
- DATABASE_URL=postgresql://user:password@db:5432/glitchtip
- SECRET_KEY=your-secret-key
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:16
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=glitchtip
Once deployed, you can use GlitchTip exactly like Sentry in your applications:
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: "https://your-key@glitchtip.example.com/1",
environment: process.env.NODE_ENV,
});
Matomo: Privacy-Focused Web Analytics
Matomo (formerly Piwik) is a privacy-focused alternative to Google Analytics. It’s GDPR-compliant, doesn’t use cookies by default, and gives you complete control over your analytics data.
Matomo provides:
- Real-time visitor tracking
- Custom dashboards and reports
- E-commerce tracking
- Heatmaps and session recordings (with plugins)
- A/B testing capabilities
Deploying Matomo with Docker:
version: '3.8'
services:
matomo:
image: matomo:latest
environment:
- MATOMO_DATABASE_HOST=db
- MATOMO_DATABASE_ADAPTER=mysql
- MATOMO_DATABASE_TABLES_PREFIX=matomo_
ports:
- "8080:80"
depends_on:
- db
db:
image: mariadb:10.11
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=matomo
- MYSQL_USER=matomo
- MYSQL_PASSWORD=matomopassword
Health Monitoring and Alerting
Beyond error tracking and analytics, you need health monitoring. Coolify provides basic health checks, but you can enhance this with:
- Uptime monitoring: Services like UptimeRobot (free tier) or self-hosted Uptime Kuma
- Log aggregation: Centralized logging with Loki or ELK stack
- Metrics collection: Prometheus for metrics, Grafana for visualization
The key is starting simple and adding complexity only when needed. A basic health check endpoint in your application is often enough:
app.get('/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
});
SSL Automation with Coolify
One of Coolify’s best features is automatic SSL certificate management. When you deploy a new service, Coolify automatically:
- Detects your domain
- Requests a Let’s Encrypt certificate
- Configures SSL/TLS
- Renews certificates automatically
This eliminates one of the biggest pain points of self-hosting: SSL certificate management.
Database and Data Layer
Your self-hosted platform needs reliable data storage. The choice of database depends on your use case, but PostgreSQL is an excellent default choice.
PostgreSQL for Primary Data
PostgreSQL is the database of choice for most modern applications. It’s:
- Open-source and battle-tested
- Feature-rich (JSON support, full-text search, extensions)
- Performant and scalable
- Well-supported by ORMs like Prisma
In the OpsWerk project, PostgreSQL serves as the primary database for GlitchTip and other services. It’s reliable, performant, and has excellent tooling.
MariaDB for Specific Use Cases
MariaDB (a MySQL fork) is useful when:
- You’re migrating from MySQL
- You need MySQL compatibility
- You’re using tools that require MySQL (like some CMS platforms)
In OpsWerk, MariaDB is used alongside PostgreSQL for services that specifically require MySQL compatibility.
Redis/Valkey for Caching
Redis (or its fork Valkey) is essential for:
- Session storage
- Caching frequently accessed data
- Rate limiting
- Real-time features (pub/sub)
A typical Redis setup in docker-compose:
services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
redis_data:
Backup Strategies
Backups are critical for self-hosted infrastructure. Your backup strategy should include:
- Database backups: Automated daily backups with retention policies
- Volume backups: Backup Docker volumes regularly
- Configuration backups: Version control for docker-compose files and configurations
- Off-site storage: Store backups in a different location (S3, Backblaze, etc.)
Here’s a simple backup script for PostgreSQL:
#!/bin/bash
BACKUP_DIR="/backups/postgres"
DATE=$(date +%Y%m%d_%H%M%S)
docker exec postgres_container pg_dump -U user database_name > "$BACKUP_DIR/backup_$DATE.sql"
# Keep only last 7 days
find "$BACKUP_DIR" -name "backup_*.sql" -mtime +7 -delete
Database Migration Patterns
When you self-host, you’re responsible for database migrations. Use migration tools like:
- Prisma Migrate: For Prisma-based applications
- Laravel Migrations: For Laravel applications
- Flyway or Liquibase: For database-first approaches
Always test migrations in a staging environment before production.
Real-World Application: Revolver API Case Study
Revolver API demonstrates a complete self-hosted API stack. It uses PostgREST to auto-generate a REST API from a PostgreSQL database schema, combined with an admin UI and webhook bridge service.
PostgREST: Database-as-API
PostgREST is a web server that automatically generates a REST API from your PostgreSQL database schema. Instead of writing API endpoints manually, you define your database schema, and PostgREST exposes it as a REST API.
Here’s how it works:
- Define your schema: Create tables, views, and functions in PostgreSQL
- Configure PostgREST: Point it to your database
- Get instant API: REST endpoints are automatically available
Example schema:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
title TEXT NOT NULL,
content TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
PostgREST automatically exposes:
GET /users- List all usersGET /users/:id- Get a specific userPOST /users- Create a userPATCH /users/:id- Update a userDELETE /users/:id- Delete a userGET /posts?user_id=eq.1- Get posts for user 1
Self-Hosted API Stack Architecture
Revolver API’s architecture includes:
- PostgreSQL 16: The database layer
- PostgREST 12: Auto-generated REST API
- Node.js/Express Bridge: Custom endpoints and webhook handling
- React Admin UI: Data management interface
- Docker Containers: All services containerized
This stack provides:
- Auto-generated REST API (no manual endpoint coding)
- Type-safe database access
- Admin interface for data management
- Webhook support for integrations
- JWT authentication
Admin UI Integration
The admin UI in Revolver API provides:
- Data browser for viewing and editing records
- Query builder for complex queries
- User management
- API key management
This demonstrates that self-hosted doesn’t mean basic. You can build sophisticated admin interfaces on top of your self-hosted infrastructure.
Webhook Bridge Service
The webhook bridge service handles:
- Receiving webhooks from external services
- Transforming webhook payloads
- Forwarding to PostgREST or custom endpoints
- Retry logic and error handling
This pattern is common in self-hosted setups where you need to integrate with external services while maintaining control over your data flow.
JWT Authentication Patterns
PostgREST supports JWT authentication. You configure it to validate JWTs and use claims for row-level security:
-- Enable row-level security
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Policy: Users can only see their own posts
CREATE POLICY user_posts ON posts
FOR SELECT
USING (user_id = current_setting('request.jwt.claim.user_id')::integer);
This provides secure, fine-grained access control without writing custom authentication logic.
Common Pitfalls
Self-hosting comes with challenges. Here are the most common pitfalls and how to avoid them:
Over-Engineering the Initial Setup
It’s tempting to set up everything at once: monitoring, logging, metrics, alerting, backups, and more. Start simple:
- Deploy your application
- Add error tracking
- Add basic monitoring
- Add backups
- Expand from there
Don’t build a complex infrastructure before you need it.
Neglecting Backups and Monitoring
Backups and monitoring are non-negotiable. Set them up from day one:
- Automated database backups
- Volume backups for persistent data
- Health checks and uptime monitoring
- Error tracking
Without these, you’re one failure away from data loss or extended downtime.
Security Misconfigurations
Common security mistakes:
- Exposing services without authentication
- Using default passwords
- Not keeping containers updated
- Exposing database ports publicly
- Weak SSL/TLS configurations
Always:
- Use strong, unique passwords
- Enable authentication on all services
- Keep containers and base images updated
- Use firewall rules to restrict access
- Enable SSL/TLS everywhere
Resource Allocation Mistakes
Self-hosting on a VPS means limited resources. Common mistakes:
- Running too many services on one server
- Not monitoring resource usage
- Not planning for traffic spikes
- Ignoring disk space
Monitor your resource usage and scale appropriately. Sometimes, splitting services across multiple servers is necessary.
When to Use Managed Services Instead
Self-hosting isn’t always the answer. Use managed services when:
- You need enterprise-grade reliability
- You don’t have time for maintenance
- You need compliance certifications
- Your traffic is unpredictable
- You’re building an MVP
The goal isn’t to self-host everything; it’s to understand your infrastructure and make informed choices.
Conclusion
Self-hosting isn’t about rejecting SaaS—it’s about building infrastructure you understand and control. With Docker and Coolify, you can create a self-sufficient development platform that grows with your needs.
The key takeaways:
- Infrastructure as craft mindset: Infrastructure isn’t a chore; it’s part of the product
- Practical stack: Docker + Coolify + monitoring provides a solid foundation
- Real production examples: OpsWerk and Revolver API show what’s possible
Start with one service—error tracking or analytics—containerize it, and expand from there. The infrastructure independence journey begins with a single container. You’re building a personal platform empire, one service at a time.