Haven logo

Haven

Private blogging platform for sharing with friends and family

Alternative to: Substack, Tumblr, WordPress.com, CaringBridge


About

Haven is a private blog application built with Ruby on Rails for sharing what you write with people you choose to share it with, not the public. It has no self-signup, built-in private RSS feeds so friends can follow you, a built-in RSS reader, a markdown editor with live preview, and support for images, video, and audio. Pages load fast with no JavaScript frameworks, ads, or trackers.

Haven Docker Compose example

Self-host Haven on your own server, homelab, or VPS starting from this Docker Compose example. It runs Haven in Docker containers using the official ghcr.io/havenweb/haven:latest, postgres:16-alpine images, with persistent volumes and automatic restarts preconfigured. Review the environment variables and adjust them to your setup, save the file as compose.yml (or docker-compose.yml), and start the stack with docker compose up -d.

services:
  haven:
    image: ghcr.io/havenweb/haven:latest
    depends_on:
      - postgresql
    volumes:
      - storage:/app/storage
    tmpfs:
      - /tmp/pids/
    restart: unless-stopped
    environment:
      # Path to the Rails server PID file. Kept on tmpfs so a restarted container never trips over a stale pid.
      PIDFILE: "/tmp/pids/server.pid"
      # Rails environment. Keep as production for a real deployment.
      RAILS_ENV: "production"
      # Hostname of the bundled PostgreSQL service (matches the service name below).
      HAVEN_DB_HOST: "postgresql"
      # Name of the PostgreSQL database Haven uses.
      HAVEN_DB_NAME: "haven"
      # PostgreSQL role (user) Haven connects as.
      HAVEN_DB_ROLE: "haven"
      # Password for the PostgreSQL role. Internal to the compose network only (Postgres runs with trust auth), so it is not security-sensitive.
      HAVEN_DB_PASSWORD: "supersecretrandomstring"
      # Email of the initial admin account created on first boot. This is your login — change it.
      HAVEN_USER_EMAIL: "changeme@example.com"
      # Password for the initial admin account created on first boot. Change it.
      HAVEN_USER_PASS: "changeme"

  postgresql:
    image: postgres:16-alpine
    restart: unless-stopped
    # Non-durability tuning recommended by upstream for Haven's workload.
    # https://www.postgresql.org/docs/current/static/non-durability.html
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "synchronous_commit=off"
      - "-c"
      - "fsync=off"
      - "-c"
      - "full_page_writes=off"
      - "-c"
      - "max_wal_size=4GB"
      - "-c"
      - "checkpoint_timeout=30min"
      - "-c"
      - "wal_level=logical"
    environment:
      # Allow connections without a password. Safe here: Postgres is reachable only inside the compose network.
      POSTGRES_HOST_AUTH_METHOD: "trust"
      # Superuser/role name. With no POSTGRES_DB set, Postgres also creates a database of this name for Haven.
      POSTGRES_USER: "haven"
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  storage:
  db_data:

Values set to changeme are required — replace them with your own values before starting Haven.

Prefer a managed setup? WinterFlow installs, configures, and updates Haven for you using this same Docker Compose configuration.