Self-Hosting Ownet

Want complete control? You can self-host indie-wemblate on your own infrastructure.

Note: Looking for managed hosting instead? Check out our managed hosting service for easier setup, updates, and management. See pricing plans or the main documentation.

Prerequisites

  • A GNU/Linux server - Ubuntu, Debian, Fedora, Arch, Gentoo, etc.
  • A domain name - e.g., example.com or blog.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_dump and pg_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_URL line should be commented out (as shown above)
  • For native builds, uncomment the DATABASE_URL line

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.com or example.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.com or blog.example.com)
  • YOUR_EMAIL@example.com - Your email for Let's Encrypt notifications
  • localhost:8000 - Change to localhost:1337 for 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

  1. Check Caddy is running: sudo systemctl status caddy
  2. Check indie-wemblate is accessible locally: curl http://localhost:1337 (or 8000 for native)
  3. Access your blog via your domain: https://example.com
  4. 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.com or nslookup example.com
  • Check ports 80/443 are open: sudo ss -tlnp | grep -E ':(80|443)'
  • Check firewall rules: sudo ufw status or sudo firewall-cmd --list-all
  • View Caddy logs for ACME errors: sudo journalctl -u caddy -f
  • Ensure no other service is using ports 80/443
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
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