> ## Documentation Index
> Fetch the complete documentation index at: https://www.towbar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Plausible CE

> Plausible Community Edition is a privacy-focused website analytics platform.

export const UseCaseNavigation = () => {
  useLayoutEffect(() => {
    const storageKey = "towbar-use-case-open-groups";
    const groupSelector = "#sidebar li[data-title] > button[aria-expanded]";
    let restoring = false;
    let frame = 0;
    function storedGroups() {
      try {
        return new Set(JSON.parse(sessionStorage.getItem(storageKey) || "[]"));
      } catch {
        return new Set();
      }
    }
    function save(groups) {
      try {
        sessionStorage.setItem(storageKey, JSON.stringify([...groups]));
      } catch {}
    }
    function groupName(button) {
      return button.parentElement?.dataset.title;
    }
    function rememberOpenGroups() {
      const groups = new Set();
      for (const button of document.querySelectorAll(groupSelector)) {
        if (button.getAttribute("aria-expanded") === "true") {
          const name = groupName(button);
          if (name) groups.add(name);
        }
      }
      save(groups);
    }
    function restoreOpenGroups() {
      frame = 0;
      const groups = storedGroups();
      if (!groups.size) return;
      restoring = true;
      for (const button of document.querySelectorAll(groupSelector)) {
        if (groups.has(groupName(button)) && button.getAttribute("aria-expanded") === "false") {
          button.click();
        }
      }
      restoring = false;
    }
    function scheduleRestore() {
      if (!frame) frame = requestAnimationFrame(restoreOpenGroups);
    }
    function onClick(event) {
      if (restoring || !(event.target instanceof Element)) return;
      const button = event.target.closest(groupSelector);
      if (button) {
        const name = groupName(button);
        if (!name) return;
        const groups = storedGroups();
        if (button.getAttribute("aria-expanded") === "true") groups.delete(name); else groups.add(name);
        save(groups);
        return;
      }
      if (event.target.closest('a[href^="/docs/use-cases/"]')) {
        rememberOpenGroups();
      }
    }
    const observer = new MutationObserver(scheduleRestore);
    document.addEventListener("click", onClick, true);
    observer.observe(document.getElementById("sidebar") || document.body, {
      childList: true,
      subtree: true
    });
    scheduleRestore();
    return () => {
      document.removeEventListener("click", onClick, true);
      observer.disconnect();
      cancelAnimationFrame(frame);
    };
  }, []);
  return null;
};

<UseCaseNavigation />

<img className="towbar-doc-brand-logo" src="https://mintcdn.com/avgeek/Wq-9tmR7jDSzqtpH/assets/use-case-logos/plausibleanalytics.svg?fit=max&auto=format&n=Wq-9tmR7jDSzqtpH&q=85&s=b0d524b199ef64937e6e5e155aac1b21" alt="Plausible CE logo" aria-hidden="true" width="24" height="24" data-path="assets/use-case-logos/plausibleanalytics.svg" />

**Upstream source:** [Current installation guide](https://github.com/plausible/community-edition).

Plausible Community Edition uses PostgreSQL for accounts and sites, ClickHouse for events, and its own application data directory. They share one Compose network. This example keeps both databases private; Towbar does not treat their Compose volumes as managed Datastores.

## Towbar manifest

```yaml title=".towbar/services/plausible-ce.compose.yml" theme={"system"}
id: plausible-ce
name: Plausible CE
file: deploy/plausible-ce/compose.yml
strategy: maintenance
services:
  plausible:
    port: 8000
    domains:
      - plausible-ce.example.com
    ingress:
      type: proxy
  plausible_db: {}
  plausible_events_db: {}
environments:
  production:
    server: 192.0.2.10
secrets:
  runtime:
    - POSTGRES_PASSWORD
    - BASE_URL
    - SECRET_KEY_BASE
```

## Compose project

```yaml title="deploy/plausible-ce/compose.yml" theme={"system"}
services:
  plausible_db:
    image: postgres:16-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea
    environment:
      POSTGRES_USER: plausible
      POSTGRES_DB: plausible
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U plausible -d plausible
      interval: 10s
      retries: 10
  plausible_events_db:
    image: clickhouse/clickhouse-server:24.12-alpine@sha256:cd450891db46cc6ffe313ca2b0fb7dbfb897a6873ca74a724cbe050a2cf62621
    environment:
      CLICKHOUSE_SKIP_USER_SETUP: "1"
    volumes:
      - events-data:/var/lib/clickhouse
      - events-logs:/var/log/clickhouse-server
    healthcheck:
      test:
        - CMD-SHELL
        - wget -q -O - http://127.0.0.1:8123/ping || exit 1
      interval: 10s
      retries: 10
  plausible:
    image: ghcr.io/plausible/community-edition:v3.2.1@sha256:33e60bfb40f2df5da00f8753b76fad04f67dba3abe6d73eb516e440e3fb62985
    command:
      - sh
      - -c
      - /entrypoint.sh db createdb && /entrypoint.sh db migrate &&
        /entrypoint.sh run
    depends_on:
      plausible_db:
        condition: service_healthy
      plausible_events_db:
        condition: service_healthy
    environment:
      BASE_URL: ${BASE_URL}
      SECRET_KEY_BASE: ${SECRET_KEY_BASE}
      HTTP_PORT: "8000"
      TMPDIR: /var/lib/plausible/tmp
      DATABASE_URL: postgres://plausible:${POSTGRES_PASSWORD}@plausible_db:5432/plausible
      CLICKHOUSE_DATABASE_URL: http://plausible_events_db:8123/plausible_events_db
    volumes:
      - plausible-data:/var/lib/plausible
volumes:
  postgres-data: {}
  events-data: {}
  events-logs: {}
  plausible-data: {}
```

## Configure

1. Prepare the example server, connect the repository, and map `production` to the branch containing these files. Replace the example server IP and domain.
2. Commit every file shown below under `deploy/plausible-ce/`. The Towbar manifest points to the Compose file; it does not create it for you.
3. Sync the repository and inspect the resolved Compose project. Save the runtime values below if this example declares any.
4. Give the server enough memory for ClickHouse as well as the application; the official low-memory configuration is a separate tuning step.
5. Back up PostgreSQL, ClickHouse, and Plausible's own data volume together. These Compose databases do not receive Towbar Datastore backup/restore operations.
6. Deploy it manually and run the verification below before enabling auto-deploy.

## Runtime values

Save these values on the Compose project after the repository sync. The manifest declares required keys, not their values.

| Key                 | Value to save                                                        |
| ------------------- | -------------------------------------------------------------------- |
| `POSTGRES_PASSWORD` | Generate a unique PostgreSQL password.                               |
| `BASE_URL`          | [https://plausible-ce.example.com](https://plausible-ce.example.com) |
| `SECRET_KEY_BASE`   | Generate at least 64 random bytes for sessions and encryption.       |

## Verify

Create an account and a site, install its tracking snippet on a test page, and confirm a visit appears. Then restart the project and verify historical visits remain.

For field constraints, see [Compose guide](/docs/services/modes/compose).
