Self-Hosting Guide
Complete guide to self-hosting ownet on your own infrastructure
Self-Hosting Ownet
Want complete control? You can self-host indie-wemblate on your own infrastructure.
Prerequisites
- A GNU/Linux server - Ubuntu, Debian, Fedora, Arch, Gentoo, etc.
- A domain name - e.g.,
example.comorblog.example.com - Root or sudo access - For installing packages and configuring services
- Deployment method (choose one):
- Docker/Podman for container deployment
- Rust 1.92+ and PostgreSQL 17+ for native builds
System Dependencies
The Ownet ecosystem relies on several external system-level tools and services:
- Container Runtime: Either Podman or Docker. Used by the control plane to provision and manage individual indie-wemblate instances in isolated containers.
- Caddy: A powerful, production-ready open-source web server with automatic HTTPS. The control plane interacts with Caddy's Admin API to dynamically configure reverse proxy routes for tenant instances. Caddy needs to be installed and running separately.
-
PostgreSQL Client Utilities:
pg_dumpandpg_restore. These are required for indie-wemblate's database backup and restore functionalities. They are typically part of your operating system's PostgreSQL client package.
Deployment Options
Option A: Docker/Podman
# Clone the repository
git clone https://codeberg.org/ownet/indie-wemblate.git
cd indie-wemblate
# Copy environment configuration
cp .env.sample .env
# Edit .env with your settings
nano .env
# Using docker
docker compose up -d --build
# OR with Podman
podman compose up -d --build
Your blog will be running at http://localhost:1337
Environment Configuration (.env)
After copying .env.sample to .env, configure the following variables:
# Database credentials
POSTGRES_USER=indie_user # PostgreSQL username
POSTGRES_PASSWORD=your-secure-pass # Strong password (generate with: openssl rand -base64 32)
POSTGRES_DB=indie_wemblate # Database name
POSTGRES_PORT=5432 # PostgreSQL port (default: 5432)
# Application port
APP_PORT=8000 # Port for indie-wemblate to listen on
# Application name
APP_NAME="Your Site Name" # The name of your blog/site
# Deployment mode
SINGLE_USER_MODE=false # false = multi-user mode (default, URLs include /users/username/)
# true = single-user mode (personal blog, clean URLs like /posts)
MAIL_FEATURE_ENABLED=false # Set to true for email features with SMTP
# Database URL (for native builds only)
# For Docker/Podman: comment out or remove this line
# For native builds: uncomment this line
# DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@127.0.0.1:${POSTGRES_PORT}/${POSTGRES_DB}
Important:
- Generate a strong password with:
openssl rand -base64 32 - For Docker/Podman deployment, the
DATABASE_URLline should be commented out (as shown above) - For native builds, uncomment the
DATABASE_URLline
Option B: Native Build
# Install PostgreSQL 17+ (if not already installed)
# Ubuntu/Debian
sudo apt install postgresql-17
# Fedora/RHEL
sudo dnf install postgresql17-server
# Arch Linux
sudo pacman -S postgresql
# Gentoo
sudo emerge dev-db/postgresql:17
# Install Rust dependencies
cargo install sqlx-cli --no-default-features --features postgres
# Clone and configure
git clone https://codeberg.org/ownet/indie-wemblate.git
cd indie-wemblate
cp .env.sample .env
nano .env
# Set up database
sqlx migrate run
# Build assets
cargo run --release --bin build-assets
# Build application (multi-user mode)
cargo build --release --bin indie-wemblate
# OR for single-user mode (personal blog)
cargo build --release --features single-user --bin indie-wemblate
# Run application
./target/release/indie-wemblate
Your blog will be running at http://localhost:8000
Production Deployment
For complete production deployment instructions, see the indie-wemblate DEPLOYMENT.md.
Production best practices:
- Reverse Proxy - Use Caddy with automatic HTTPS (see below)
- Database Backups - Set up regular PostgreSQL backups
- Monitoring - Set up health checks and alerts
- Firewall - Restrict database access to application only
- Security Updates - Enable automatic security updates
Caddy Reverse Proxy Setup
For production deployments, Caddy provides automatic HTTPS with Let's Encrypt. This guide shows you how to set up Caddy for your self-hosted indie-wemblate instance.
Prerequisites
- A domain name you own (e.g.,
blog.example.comorexample.com) - DNS A record pointing your domain to your server's IP address
- Ports 80 and 443 open in your firewall
- indie-wemblate running (via Docker/Podman or natively)
DNS Configuration (Required First)
Before setting up Caddy, configure your DNS records to point to your server:
# Example DNS records (replace with your domain and IP)
example.com A YOUR_SERVER_IP
# OR use a subdomain
blog.example.com A YOUR_SERVER_IP
Important: Wait for DNS propagation (5-30 minutes) before proceeding with Caddy setup.
Installation
Install Caddy as a system service (recommended for production):
# Ubuntu/Debian
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy
# Fedora/RHEL
sudo dnf install 'dnf-command(copr)'
sudo dnf copr enable @caddy/caddy
sudo dnf install caddy
# Arch Linux
sudo pacman -S caddy
# Gentoo
sudo emerge www-servers/caddy
Configuration
indie-wemblate includes a sample Caddy configuration file for self-hosting.
Step 1: Copy the Sample Configuration
# From the indie-wemblate repository
sudo cp Caddyfile.example /etc/caddy/Caddyfile
Step 2: Edit the Configuration
sudo nano /etc/caddy/Caddyfile
Replace the following placeholders:
YOUR_DOMAIN- Your actual domain (e.g.,example.comorblog.example.com)YOUR_EMAIL@example.com- Your email for Let's Encrypt notificationslocalhost:8000- Change tolocalhost:1337for container deployment
Step 3: Create Log Directory
sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddy
Step 4: Validate and Start
# Validate configuration
sudo caddy validate --config /etc/caddy/Caddyfile
# If validation passes, enable and start Caddy
sudo systemctl enable --now caddy
# Check status
sudo systemctl status caddy
Verify Your Setup
- Check Caddy is running:
sudo systemctl status caddy - Check indie-wemblate is accessible locally:
curl http://localhost:1337(or 8000 for native) - Access your blog via your domain:
https://example.com - Verify SSL certificate:
curl -I https://example.com
SSL Certificate Management
Caddy automatically obtains and renews SSL certificates from Let's Encrypt:
- ✅ Free SSL certificates via Let's Encrypt
- ✅ Automatic certificate issuance on first request (usually takes 10-30 seconds)
- ✅ Auto-renewal happens 30 days before expiration
- ✅ HTTP requests are automatically redirected to HTTPS
- ✅ Modern TLS 1.2+ with strong ciphers
Requirements for automatic SSL:
- Ports 80 and 443 must be accessible from the internet
- Your domain's DNS must be correctly configured
- Caddy uses HTTP-01 challenge by default (no DNS API needed)
Container Configuration
If running indie-wemblate in a Docker/Podman container, update the reverse_proxy line in your Caddyfile:
# For containerized deployment, use port 1337
reverse_proxy localhost:1337
# Or use container name if Caddy is also containerized
reverse_proxy indie-wemblate-app:8000
Troubleshooting
- Certificate not issued
-
- Verify DNS records:
dig example.comornslookup example.com - Check ports 80/443 are open:
sudo ss -tlnp | grep -E ':(80|443)' - Check firewall rules:
sudo ufw statusorsudo firewall-cmd --list-all - View Caddy logs for ACME errors:
sudo journalctl -u caddy -f - Ensure no other service is using ports 80/443
- Verify DNS records:
- 502 Bad Gateway
-
- Check indie-wemblate is running:
curl http://localhost:1337(or 8000 for native) - Verify the port in Caddyfile matches indie-wemblate's port
- Check Caddy logs:
sudo journalctl -u caddy -f - For containers: ensure Caddy can reach the container network
- Check indie-wemblate is running:
- DNS not resolving
-
- Wait 5-30 minutes for DNS propagation
- Check DNS with:
dig example.com - Verify A record points to correct IP address
- Try flushing DNS cache on your computer
Security Best Practices
- Keep Caddy updated to the latest version
- Use strong security headers (included in sample Caddyfile)
- Configure firewall to allow only ports 80/443 from internet
- Monitor Caddy logs for suspicious activity
- Consider adding rate limiting for additional protection
View Configuration and Logs
# View Caddy configuration
sudo cat /etc/caddy/Caddyfile
# View live logs
sudo journalctl -u caddy -f
# View recent logs
sudo journalctl -u caddy -n 100
# Check Caddy version
caddy version
Configuration
indie-wemblate uses environment variables and configuration files.
Environment Variables (.env)
# Database Configuration
POSTGRES_USER=indie_user
POSTGRES_PASSWORD=your-secure-password
POSTGRES_DB=indie_wemblate
POSTGRES_HOST=127.0.0.1
POSTGRES_PORT=5432
# Application Settings
ROCKET_PORT=8000
ROCKET_ADDRESS=0.0.0.0
Key Configuration Options
- base_url
- Your blog's public URL (required for IndieAuth)
- port
- HTTP server port (default: 8000)
- address
- Bind address (0.0.0.0 for external access)
IndieWeb Features
indie-wemblate has full support for IndieWeb protocols.
IndieAuth
Use your blog as your identity on the web:
- Authorization Server - Built-in IndieAuth provider
- Client Support - Sign in to other IndieWeb sites
- Token Management - Manage authorized applications in admin panel
Micropub
Post to your blog from any Micropub client:
- Media Endpoint - Upload images and files
- Post Types - Articles, notes, photos, replies, likes, bookmarks
- Syndication - Cross-post to other platforms
Webmentions
Receive and send cross-site interactions:
- Incoming Webmentions - Accept mentions from other sites
- Moderation - Approve or reject mentions in admin panel
- Display - Show mentions on your posts
- Outgoing - Automatically send webmentions when you link to others
Microsub
Follow other sites and read feeds:
- Feed Reader - Built-in RSS/Atom/h-feed reader
- Channels - Organize feeds into channels
- Timeline - Unified timeline of followed sites
- Multiple Formats - RSS, Atom, JSON Feed, microformats2