# Halo User Guide

Halo is a powerful, easy-to-use open-source website building tool. With a single self-hosted application you can run a personal blog, a knowledge base, a documentation site, a company homepage, or any content-driven website. This guide shows you how to install Halo, set it up, and use every part of the management console to publish and manage your content.

> [!NOTE]
> This guide covers the open-source **Halo Community Edition** (licensed under GPL-3.0). The application is bilingual; its administration console ships with multiple languages and defaults based on your browser. Commercial "Pro" and "Commerce" editions add features (mobile app, AI site building, online store) that are not part of this open-source project and are not documented here.

---

## 1. What Is Halo?

Halo is a self-contained server application. You run **one process** (or one container), point your browser at it, and manage your whole website from a built-in admin console. Visitors see your public site; you manage everything from a private dashboard.

At a glance, Halo gives you:

- **Content management** — posts, single pages, categories, tags, and a moderated comment system, all edited in a rich WYSIWYG editor.
- **A theme system** — swap the entire look of your public site by installing a theme; customize it through a settings form, no code required.
- **A plugin system** — extend functionality (comment widgets, search, sitemaps, RSS feeds, syntax highlighting, and more) by installing plugins.
- **Attachment (media) management** — upload, organize, and serve images and files, with pluggable storage backends.
- **User and permission management** — invite users, assign roles, and control exactly what each person can do.
- **Account security** — two-factor authentication, OAuth2 social login, personal access tokens, and login auditing.
- **Full-site backup and restore** — export your entire site (database + working files) to a single archive and restore it elsewhere.

> [!TIP]
> Halo stores everything it needs — database, uploaded files, themes, plugins, logs — under a single **working directory** (by default `~/.halo2`). Back up that one directory (plus a database dump if you use an external database) and you have backed up your entire site.

### Editions at a glance

| Edition | License | What it is |
|---------|---------|------------|
| **Community** | GPL-3.0 (free, open source) | The full self-hosted CMS documented in this guide. 100+ free themes and plugins. |
| Pro | Commercial | Community plus mobile app, AI site building, phone-number login, private deployment, paid theme/plugin market. |
| Commerce | Commercial | Pro plus an integrated online store (products, orders, payments). |

---

## 2. Quick Start (5 Minutes with Docker)

The fastest way to try Halo is Docker. This command starts a fully working Halo on port `8090`, using a file-based H2 database so you need nothing else installed:

```bash
docker run -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.24
```

```text
Unable to find image 'halohub/halo:2.24' locally
2.24: Pulling from halohub/halo
...
Status: Downloaded newer image for halohub/halo:2.24
a1b2c3d4e5f6...   (the container ID)
```

What each part does:

| Flag | Meaning |
|------|---------|
| `-d` | Run in the background (detached). |
| `--name halo` | Name the container `halo` so you can manage it later. |
| `-p 8090:8090` | Map host port `8090` to Halo's port `8090`. |
| `-v ~/.halo2:/root/.halo2` | Persist Halo's working directory on your host, so data survives container restarts. |
| `halohub/halo:2.24` | The official image, tag `2.24`. |

Now open a browser:

- **Public site:** `http://localhost:8090`
- **Admin console:** `http://localhost:8090/console`

On first launch Halo shows a **setup wizard** at `/console`. Fill in your site title, the administrator username, password, and email, and submit. You are then taken to the dashboard.

> [!IMPORTANT]
> The Quick Start above uses the built-in H2 database, which is perfect for evaluation but **not recommended for production**. For a real site, use PostgreSQL or MySQL and put Halo behind a reverse proxy with HTTPS. See [Section 4 (Installation)](#4-installation) and the Admin Guide.

> [!WARNING]
> The publicly hosted demo (`https://demo.halocms.site`, console `https://demo.halocms.site/console`) is reset periodically and shared with everyone. Never store anything private there.

### Try it without installing anything

If you do not have Docker locally, the project offers one-click cloud sandboxes via **Gitpod** and **ClawCloud Run** (links are on the project's GitHub page). These spin up a temporary Halo for experimentation only.

---

## 3. Requirements

Halo is distributed as a Docker image and as an executable Java archive (JAR). Pick whichever fits your environment.

| Method | What you need |
|--------|---------------|
| **Docker** (recommended) | Docker Engine. Nothing else — the image bundles Java. |
| **Executable JAR** | A **Java 21** runtime (JRE). The official images use `eclipse-temurin:21-jre`. |

Database options (choose one):

| Database | Notes |
|----------|-------|
| **H2** (file-based) | Default. Zero setup. Good for evaluation and very small sites. Not recommended for production. |
| **PostgreSQL** | Recommended for production. |
| **MySQL** | Supported for production. |
| **MariaDB** | Supported for production. |

> [!NOTE]
> Halo connects to databases reactively using **R2DBC** drivers (not the traditional JDBC). The official image ships drivers for H2, PostgreSQL, MySQL, and MariaDB, so no extra driver installation is required.

Network:

- Halo listens on TCP port **`8090`** by default.
- For a public site you will typically run a reverse proxy (Nginx, Caddy, Traefik, or a panel like 1Panel) in front of Halo to terminate HTTPS.

---

## 4. Installation

### 4.1 Docker (single container)

The Quick Start command in [Section 2](#2-quick-start-5-minutes-with-docker) is a complete single-container install. For anything beyond evaluation, pin a specific patch version and set your external URL and timezone.

=== "Linux / macOS"

    ```bash
    docker run -d \
      --name halo \
      -p 8090:8090 \
      -v ~/.halo2:/root/.halo2 \
      -e TZ=Asia/Shanghai \
      halohub/halo:2.24
    ```

=== "Windows (PowerShell)"

    ```powershell
    docker run -d `
      --name halo `
      -p 8090:8090 `
      -v ${HOME}\.halo2:/root/.halo2 `
      -e TZ=Asia/Shanghai `
      halohub/halo:2.24
    ```

> [!TIP]
> The container's default timezone is `Asia/Shanghai`. Override it with `-e TZ=...` (for example `-e TZ=America/Phoenix` or `-e TZ=UTC`) so timestamps on posts and logs match your locale.

### 4.2 Docker Compose (with PostgreSQL)

For production, run Halo and a real database together with Docker Compose. Create a `docker-compose.yaml`:

```yaml
services:
  halo:
    image: halohub/halo:2.24
    restart: on-failure:3
    depends_on:
      halodb:
        condition: service_healthy
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
    environment:
      - JVM_OPTS=-Xmx256m -Xms256m
    command:
      - --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
      - --spring.r2dbc.username=halo
      - --spring.r2dbc.password=openpostgresql
      - --spring.sql.init.platform=postgresql
      - --halo.external-url=http://localhost:8090/

  halodb:
    image: postgres:15.4
    restart: on-failure:3
    networks:
      halo_network:
    volumes:
      - ./halodb:/var/lib/postgresql/data
    healthcheck:
      test: [ "CMD", "pg_isready" ]
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      - POSTGRES_PASSWORD=openpostgresql
      - POSTGRES_USER=halo
      - POSTGRES_DB=halo
      - PGUSER=halo

networks:
  halo_network:
```

Start it:

```bash
docker compose up -d
```

```text
[+] Running 3/3
 ✔ Network halo_halo_network  Created
 ✔ Container halo-halodb-1     Healthy
 ✔ Container halo-halo-1       Started
```

> [!IMPORTANT]
> Set `--halo.external-url` to the real public address of your site (for example `https://blog.example.com/`). Halo uses it to build absolute links in feeds, sitemaps, social-share metadata, and emails. Getting it wrong causes broken links in those places.

The three command-line arguments that point Halo at PostgreSQL are the key ones to adapt for MySQL/MariaDB — see the table below.

| Database | `--spring.r2dbc.url` | `--spring.sql.init.platform` |
|----------|----------------------|------------------------------|
| PostgreSQL | `r2dbc:pool:postgresql://HOST/DB` | `postgresql` |
| MySQL | `r2dbc:pool:mysql://HOST/DB` | `mysql` |
| MariaDB | `r2dbc:pool:mariadb://HOST/DB` | `mariadb` |
| H2 (default) | *(omit — uses file DB in the work dir)* | `h2` |

### 4.3 Executable JAR

If you prefer not to use Docker, run the JAR directly on a host with Java 21:

```bash
java -jar halo.jar
```

```text
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Halo ::
```

Pass configuration as `--key=value` arguments, exactly like the Compose `command:` entries:

```bash
java -jar halo.jar \
  --halo.work-dir=/opt/halo/data \
  --halo.external-url=https://blog.example.com/ \
  --spring.r2dbc.url=r2dbc:pool:postgresql://localhost/halo \
  --spring.r2dbc.username=halo \
  --spring.r2dbc.password=secret \
  --spring.sql.init.platform=postgresql
```

> [!NOTE]
> Halo is a standard Spring Boot application. Any setting in this guide can be supplied three equivalent ways: a `--flag=value` command-line argument, an environment variable (`HALO_EXTERNAL_URL=...`), or a line in a `application.yaml` config file placed in the working directory. Command-line arguments win over environment variables, which win over the config file.

### 4.4 First-run setup wizard

However you install, the first time you open `/console` Halo presents a setup form:

- [ ] **Site title** — the name shown in the browser tab and theme header.
- [ ] **Username** — your administrator account login name.
- [ ] **Password** — choose a strong password; this account has full control.
- [ ] **Email** — used for notifications and password recovery.

Submit the form to create your admin account and finish initialization. You can change all of these later under **System → Settings** and **System → Users**.

---

## 5. The Console at a Glance

After logging in at `/console`, you land on the **Dashboard**. The left sidebar groups every feature into five areas:

| Sidebar group | What lives here |
|---------------|-----------------|
| **Dashboard** | At-a-glance widgets: post/comment/user counts, view statistics, quick actions. |
| **Content** | Posts, Pages, Categories, Tags, Comments, Attachments. |
| **Interface** | Themes, Menus. |
| **System** | Users, Roles, Plugins, Settings, Backup, and other administration. |
| **Tools** | Utilities contributed by plugins (for example content migration). |

There is also a separate **User Center** at `/uc` — a self-service area where any logged-in user (not just admins) manages their own profile, security, personal posts, and notifications. See [Section 13](#13-the-user-center-uc).

> [!TIP]
> The sidebar is dynamic. Installing a plugin can add new menu entries and even new menu groups. If a menu item is missing, your account's role may not grant permission to see it — ask an administrator.

---

## 6. Writing and Managing Posts

Posts are your primary, time-ordered content (blog articles, news, announcements).

### 6.1 Create a post

1. Go to **Content → Posts**.
2. Click **New Post** (or **New Page** in the Pages section).
3. Write in the editor. The default editor is a rich-text WYSIWYG editor built on Tiptap/ProseMirror; you can also switch to a Markdown-oriented editing experience if a Markdown editor plugin is installed.
4. Open the **settings panel** (usually a side drawer) to set the post's metadata before publishing.

The editor toolbar supports a full range of formatting because Halo bundles these editor extensions:

| Capability | Notes |
|-----------|-------|
| Headings, bold, italic, underline, strikethrough | Standard inline formatting. |
| Ordered/bullet/task lists | Including nested lists. |
| Code and code blocks | Syntax highlighting is provided by the bundled Shiki plugin. |
| Tables | Insert and edit grid tables. |
| Images, galleries, video, audio, iframe | Media embeds; images can be uploaded straight into the attachment library. |
| Blockquote, horizontal rule, details (collapsible) | Structural blocks. |
| Highlight, text color, font size, alignment, sub/superscript | Typographic controls. |
| Columns | Multi-column layout. |
| Slash commands menu | Type `/` to insert blocks quickly. |

> [!TIP]
> Type `/` in the editor to open the **commands menu** and insert images, tables, code blocks, and more without leaving the keyboard.

### 6.2 Post settings

In the post settings panel you control how the post is stored, addressed, and displayed:

| Setting | What it does |
|---------|--------------|
| **Title** | The post's display title. |
| **Permalink / slug** | The URL-friendly identifier. Halo generates one from the title (with transliteration for non-Latin titles) but you can override it. |
| **Categories** | Assign one or more categories (hierarchical). |
| **Tags** | Assign one or more tags (flat). |
| **Excerpt** | A short summary; can be auto-generated or written manually. |
| **Cover image** | The featured image, used by themes in lists and social cards. |
| **Visibility** | Public or private. |
| **Pinned / priority** | Pin important posts to the top of lists. |
| **Allow comments** | Toggle the comment form for this post. |
| **Publish time** | Publish now or schedule for later. |

### 6.3 Drafts, publishing, and revisions

- Saving without publishing keeps the post as a **draft** (not visible to the public).
- **Publish** makes it live. **Unpublish** returns it to draft without deleting it.
- Halo keeps **snapshots** of content as you edit, so you can review and roll back to earlier versions of a post.
- Deleting a post moves it to the **Recycle Bin** first; deleting from the bin is permanent.

> [!NOTE]
> Every post separates its *metadata* (title, slug, categories) from its *content snapshots*. This is why you can change a post's settings without creating a new content revision, and revert content without losing settings.

---

## 7. Pages, Categories, and Tags

### 7.1 Single pages

**Single pages** (under **Content → Pages**) are standalone, non-time-ordered content such as "About", "Contact", or a landing page. They use the same editor and settings model as posts but are not listed in your blog feed or organized by category.

### 7.2 Categories

Categories (**Content → Categories**) organize posts hierarchically (a category can have child categories). Each category has:

- A **name** and **slug** (used in the URL).
- An optional **description** and **cover**.
- A **template** override (themes may provide alternate layouts per category).

Reorder and re-nest categories by dragging them in the tree view.

### 7.3 Tags

Tags (**Content → Tags**) are a flat, lightweight way to label posts across categories. Create a tag, give it a name, slug, and optional color, then apply it from any post's settings panel.

> [!TIP]
> Use **categories** for your site's main structure (a handful of broad sections) and **tags** for cross-cutting topics (many fine-grained labels). Themes typically render category pages prominently and tags as a cloud or filter.

---

## 8. Comments and Moderation

Halo has a built-in, moderated comment system that works across posts, pages, and other comment-enabled content.

Manage comments under **Content → Comments**:

- See all comments and their threaded **replies** in one place.
- **Approve** pending comments to make them public, or leave moderation on so nothing appears until you approve it.
- **Reply** to a commenter directly from the console.
- **Delete** spam or unwanted comments.

> [!NOTE]
> The front-end comment box that visitors see is usually provided by the **comment widget plugin** (bundled by default). The console section above manages the data regardless of which front-end widget renders it.

> [!IMPORTANT]
> Comment creation is **rate-limited** by default (10 comments per minute per source) to reduce spam and abuse. Legitimate users are unaffected; automated flooding is throttled.

---

## 9. Attachments (Media Library)

The **attachment** system (**Content → Attachments**) is Halo's media library for images, documents, and other files.

### 9.1 Uploading

- Drag-and-drop files, or click to browse.
- Uploads can also happen inline while editing a post (for example pasting or dropping an image into the editor).
- Files are grouped, searchable, and reusable across posts.

### 9.2 Storage policies

Where files physically live is controlled by a **storage policy**. Out of the box Halo stores attachments in its working directory (local storage). By installing a storage plugin you can add policies that send uploads to object storage (S3-compatible services, etc.). Each attachment is associated with the policy it was uploaded under.

### 9.3 Thumbnails

Halo automatically generates **thumbnails** for images so themes can serve appropriately sized versions. Thumbnail generation can be tuned (quality, concurrency) or disabled by an administrator — see the Admin Guide's configuration reference.

> [!TIP]
> A "Default Storage Policy for User Avatars" and client-side image compression before upload are frequently requested enhancements tracked by the community. If you need object storage today, install the appropriate storage plugin from the application market.

---

## 10. Themes: Changing How Your Site Looks

A **theme** controls the entire appearance of your public site. Manage themes under **Interface → Themes**.

### 10.1 Install and activate

1. Go to **Interface → Themes**.
2. **Install** a theme by uploading its package (a `.zip`) or installing from a URL / the application market.
3. Click **Activate** to make it your live theme.

A fresh Halo ships with a default theme (internally the "earth" theme) so your site is never blank.

### 10.2 Customize a theme

Most themes expose a **settings form** — Halo renders it from the theme's own definition, so you configure colors, layout options, social links, and more through form fields rather than editing code. Themes can also define:

- **Custom templates** for specific posts, pages, categories, or tags.
- **Menu** integration (see below).

> [!NOTE]
> Themes are built with **Thymeleaf** server-side templates. You do not need to know Thymeleaf to *use* a theme — only to *build* one (covered in the Admin Guide and the developer documentation).

### 10.3 Menus

Navigation menus are managed under **Interface → Menus**:

- Create one or more **menus** (for example a header menu and a footer menu).
- Add **menu items** that link to posts, pages, categories, tags, or arbitrary URLs.
- Drag items to reorder and nest them.

Your active theme decides where each menu appears.

---

## 11. Plugins: Extending Halo

**Plugins** add features without changing Halo's core. Manage them under **System → Plugins**.

### 11.1 Install, enable, configure

1. Go to **System → Plugins**.
2. **Install** a plugin by uploading its `.jar` package or installing from the application market.
3. **Enable** it. Some plugins add new console menu items, new editor tools, new storage policies, or new front-end widgets.
4. If the plugin has settings, a **configuration** tab appears — fill in the form and save.

### 11.2 Plugins bundled by default

A standard Halo build downloads and includes several first-party plugins so common needs work out of the box:

| Plugin | Purpose |
|--------|---------|
| **Comment widget** | Renders the front-end comment box visitors use. |
| **Search widget** | Adds site search to your theme. |
| **Sitemap** | Generates `sitemap.xml` for search engines. |
| **Feed** | Generates RSS/Atom feeds. |
| **Shiki** | Syntax highlighting for code blocks. |
| **Editor hyperlink card** | Rich link-preview cards in the editor. |

> [!TIP]
> Browse more themes and plugins in the official **application market** (`halo.run/store/apps`) and the community-curated `awesome-halo` list. Plugins can be enabled and disabled at any time without reinstalling.

> [!CAUTION]
> Only install themes and plugins from sources you trust. A plugin runs inside your Halo server with broad access. Disable or uninstall anything you do not recognize.

---

## 12. Users, Roles, and Permissions

### 12.1 Users

Manage accounts under **System → Users**:

- **Create** users and set their display name, username, email, and avatar.
- **Assign roles** to grant permissions.
- **Disable** or delete accounts.

### 12.2 Roles

Halo uses **role-based access control (RBAC)**. A role is a named bundle of permissions (for example `view posts`, `manage attachments`, `manage users`). Manage roles under **System → Roles**:

- Use the built-in roles (such as a super administrator role with full access) or create custom roles.
- Assign one or more roles to each user; their effective permissions are the union.

> [!IMPORTANT]
> The **super administrator** role has unrestricted access, including sensitive system operations. Grant it sparingly. For everyday editors, create a limited role that grants only content permissions.

### 12.3 Authentication providers

Under **System → Auth Providers** you can enable additional sign-in methods (for example OAuth2 social login) supplied by plugins, alongside the built-in username/password login.

---

## 13. The User Center (`/uc`)

Separate from the admin console, the **User Center** at `/uc` is where *any* logged-in user manages their own account — useful when you have contributors who should not see the full admin console.

The User Center includes:

| Section | What a user can do |
|---------|--------------------|
| **Profile** | Edit display name, avatar, email, and bio. |
| **Security** | Change password, set up two-factor authentication, manage devices and personal access tokens. |
| **Posts** | Write and manage their own posts (if permitted). |
| **Notifications** | Read in-app notifications (new comments, replies, system messages) and manage subscription preferences. |

---

## 14. Securing Your Account

Halo includes several account-security features you can use right away from the User Center (`/uc → Security`).

### 14.1 Two-factor authentication (2FA)

Halo supports **TOTP** two-factor authentication (compatible with Google Authenticator, Authy, 1Password, etc.):

1. Go to **`/uc` → Security → Two-factor authentication**.
2. Scan the displayed QR code with your authenticator app.
3. Enter the 6-digit code to confirm and enable 2FA.

After enabling, logins require your password plus the current 6-digit code.

> [!WARNING]
> Save your recovery information when enabling 2FA. If you lose your authenticator device and have no recovery method, an administrator may need to intervene to restore access.

### 14.2 Personal access tokens (PAT)

For scripts and integrations, create a **personal access token** instead of using your password:

1. Go to **`/uc` → Security → Personal access tokens**.
2. Create a token, give it a name and scope, and copy it immediately (it is shown only once).
3. Use it as a bearer token when calling Halo's API.

> [!CAUTION]
> A personal access token carries your permissions. Treat it like a password, scope it as narrowly as possible, and revoke it the moment it is no longer needed.

### 14.3 "Remember me" and login protection

- **Remember me** keeps you signed in across browser restarts; the token is valid for 14 days by default and rotates automatically for safety.
- **Login attempts are rate-limited** (3 attempts per minute by default) to slow down password-guessing attacks. If you are temporarily blocked after several failures, wait a minute and try again.

---

## 15. Backing Up and Restoring Your Site

Halo can export your **entire site** — database content *and* working-directory files (themes, plugins, attachments) — into a single archive.

### 15.1 Create a backup

1. Go to **System → Backup**.
2. Click **Create backup**. Halo runs the backup asynchronously and reports progress; for large sites this can take a while.
3. When it finishes, **download** the `.zip` archive.

Backups are written to `${halo.work-dir}/backups/` on the server (for example `~/.halo2/backups/halo-full-backup-<timestamp>.zip`).

### 15.2 Restore a backup

1. Go to **System → Backup → Restore**.
2. Upload a previously created backup archive.
3. Halo restores the database records and working-directory files.

> [!IMPORTANT]
> Always **take a fresh backup before restoring** over an existing site. Restore replaces data, and some timestamps (such as creation times) may be reset to the restore time.

> [!TIP]
> Because a full backup is database-agnostic, it is the supported way to **migrate between databases** — for example from the default H2 to PostgreSQL — without worrying about SQL dialect differences. Back up on the old database, point a fresh Halo at the new database, and restore.

---

## 16. Common Workflows

### 16.1 Publish your first blog post

- [ ] Open `/console` and log in.
- [ ] Go to **Content → Categories** and create a category (e.g. "Blog").
- [ ] Go to **Content → Posts → New Post**.
- [ ] Write your content, set the title, slug, and category in the settings panel.
- [ ] Click **Publish**.
- [ ] Visit your public site to see it live.

### 16.2 Set up a custom domain with HTTPS

- [ ] Point your domain's DNS at your server.
- [ ] Put a reverse proxy (Nginx, Caddy, Traefik, or 1Panel) in front of Halo on port `8090`.
- [ ] Obtain a TLS certificate (Let's Encrypt) at the proxy.
- [ ] Set `--halo.external-url=https://yourdomain.com/` so Halo builds correct absolute links.
- [ ] Restart Halo and verify links in feeds and sitemaps are correct.

### 16.3 Add search, RSS, and a sitemap

- [ ] Go to **System → Plugins**.
- [ ] Ensure the **Search widget**, **Feed**, and **Sitemap** plugins are installed and enabled.
- [ ] Confirm your theme places the search box (Interface → Themes settings).
- [ ] Visit `/sitemap.xml` and your feed URL to confirm they generate.

### 16.4 Move your site to a new server

- [ ] On the old server: **System → Backup → Create backup**, then download the archive.
- [ ] On the new server: install Halo (same major version) pointed at your production database.
- [ ] Open `/console`, complete setup, then **System → Backup → Restore** the archive.

---

## 17. Troubleshooting

### Error: `External URL is required when property use-absolute-permalink is set to true.`

**Cause:** You enabled absolute permalinks but did not set an external URL, so Halo cannot build absolute links.

**Solution:** Set `--halo.external-url=https://yourdomain.com/` (or the `HALO_EXTERNAL_URL` environment variable) and restart. The URL must be a valid `http`/`https` address.

**Prevention:** Always configure `halo.external-url` before turning on absolute permalinks.

### Error: `External URL must be a http or https URL.`

**Cause:** The value of `halo.external-url` is not a valid HTTP/HTTPS URL (for example a missing scheme or an opaque URI).

**Solution:** Use a full URL including the scheme and host, e.g. `https://blog.example.com/`.

### Error: `Public key location does not exist` / `Private key location does not exist`

**Cause:** Halo's OAuth2/JWT signing keys could not be found at the configured location.

**Solution:** Let Halo manage keys in its working directory (the default), or set valid `halo.security.oauth2.jwt.public-key-location` and `...private-key-location` paths that point to existing RSA key files.

**Prevention:** Do not move or delete files under the working directory's security folder.

### Problem: The site loads but I cannot reach `/console`

**Cause:** Reverse proxy not forwarding all paths, or you are hitting the wrong port.

**Solution:** Confirm Halo is listening on `8090` and that your proxy forwards `/console`, `/uc`, and `/apis/**` — not just `/`. With `forward-headers-strategy: native` (the default), Halo honors `X-Forwarded-*` headers from your proxy.

### Problem: I was logged out / "too many attempts" on login

**Cause:** The default login rate limit (3 attempts per minute) tripped.

**Solution:** Wait about a minute and try again with the correct credentials. If you forgot your password, use the email password-reset flow.

### Problem: Uploaded images don't appear or thumbnails are missing

**Cause:** Storage policy misconfiguration, a full disk, or thumbnail generation disabled.

**Solution:** Check **Content → Attachments** that files uploaded successfully, verify free disk space in the working directory, and confirm the active storage policy. An administrator can re-enable thumbnails if they were turned off.

### Problem: Data disappeared after restarting the container

**Cause:** You did not mount a volume, so the container's working directory was ephemeral.

**Solution:** Always run with `-v ~/.halo2:/root/.halo2` (or a named volume). Without it, all data is lost when the container is removed.

**Prevention:** Treat the working-directory volume as the home of your entire site and back it up.

### Problem: Editor loses a character when typing inline code / certain characters

**Cause:** A known editor edge case reported by the community (see project issues such as inline-code input handling).

**Solution:** Update to the latest Halo release, which includes ongoing editor fixes. As a workaround, type the surrounding text first and apply inline-code formatting afterward.

### Problem: Duplicate notifications after configuring a notifier

**Cause:** A reported issue where extending a notifier could cause duplicate messages.

**Solution:** Keep Halo updated; review your notification settings under `/uc → Notifications` and avoid configuring overlapping notifiers for the same event.

> [!TIP]
> For deeper operational issues — container logs, database connectivity, performance tuning, health checks — see the **Halo Admin Guide**, which documents configuration, deployment, and diagnostics in detail.

---

## 18. Frequently Asked Questions

**Q: Is Halo free?**
Yes. The Community Edition documented here is fully open source under GPL-3.0 and free to self-host. Paid Pro/Commerce editions exist with additional features but are separate products.

**Q: Do I need to know how to code?**
No. Installing, theming, and managing content are all done through the console and form-based settings. Coding is only needed to *build* custom themes or plugins.

**Q: Which database should I use?**
H2 for evaluation. For a real site, use PostgreSQL (recommended) or MySQL/MariaDB.

**Q: Where is all my data stored?**
Under the working directory, `~/.halo2` by default (`/root/.halo2` inside the container). It holds the H2 database (if used), attachments, themes, plugins, logs, and backups.

**Q: How do I back up everything?**
Use **System → Backup** for a full-site archive, or copy the working directory plus a dump of your external database. See [Section 15](#15-backing-up-and-restoring-your-site).

**Q: How do I upgrade Halo?**
Pull the new image tag (e.g. `halohub/halo:2.24` → a newer patch) and recreate the container with the same volume, or replace the JAR. **Back up first.** Database schema migrations run automatically on startup.

**Q: Can I change the port?**
Yes. Set `--server.port=...` (and adjust your `-p` Docker mapping accordingly).

**Q: How do I migrate from Halo 1.x or another CMS?**
Use a migration plugin under **Tools**. Note that attachment paths from 1.x are served via the built-in `/upload/**` resource mapping for compatibility.

**Q: Can multiple people write on the same site?**
Yes. Create users, assign limited roles, and have contributors work from the User Center (`/uc`) so they never need full admin access.

**Q: How do I enable social login (Google, GitHub, etc.)?**
Install an OAuth2 authentication plugin, then enable and configure it under **System → Auth Providers**.

**Q: Is there an API?**
Yes — Halo exposes a comprehensive REST API (documented via OpenAPI) and an official JavaScript client. See the Admin Guide for the API surface and authentication.

**Q: My site is reachable but links use the wrong domain.**
Set `halo.external-url` to your real public URL and restart.

**Q: How do I get more themes and plugins?**
Browse the official application market at `halo.run/store/apps` and the community `awesome-halo` list.

---

## 19. Quick Reference

### Default ports and paths

| Item | Value |
|------|-------|
| HTTP port | `8090` |
| Public site | `http://<host>:8090/` |
| Admin console | `http://<host>:8090/console` |
| User Center | `http://<host>:8090/uc` |
| Working directory (host default) | `~/.halo2` |
| Working directory (in container) | `/root/.halo2` |
| Backups | `${work-dir}/backups/` |
| Logs | `${work-dir}/logs/halo.log` |

### Essential startup settings

| Setting | Purpose | Example |
|---------|---------|---------|
| `halo.work-dir` | Data directory | `/opt/halo/data` |
| `halo.external-url` | Public site URL | `https://blog.example.com/` |
| `server.port` | HTTP port | `8090` |
| `spring.r2dbc.url` | Database connection | `r2dbc:pool:postgresql://db/halo` |
| `spring.r2dbc.username` / `.password` | DB credentials | `halo` / `secret` |
| `spring.sql.init.platform` | DB dialect | `postgresql` |
| `JVM_OPTS` (env) | JVM tuning | `-Xmx512m -Xms512m` |
| `TZ` (env) | Container timezone | `UTC` |

### Console map

| Task | Where |
|------|-------|
| Write a post | Content → Posts |
| Make an "About" page | Content → Pages |
| Organize content | Content → Categories / Tags |
| Moderate comments | Content → Comments |
| Manage media | Content → Attachments |
| Change appearance | Interface → Themes |
| Edit navigation | Interface → Menus |
| Add features | System → Plugins |
| Manage people | System → Users / Roles |
| Configure site | System → Settings |
| Back up / restore | System → Backup |
| Manage your own account | `/uc` (User Center) |

### Useful Docker commands

```bash
# View logs
docker logs -f halo

# Stop / start / restart
docker stop halo && docker start halo
docker restart halo

# Upgrade (back up first!): pull a new tag and recreate with the SAME volume
docker pull halohub/halo:2.24
docker rm -f halo
docker run -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.24
```

> [!NOTE]
> For configuration internals, architecture, security hardening, performance tuning, the REST API surface, and theme/plugin development, continue to the **Halo Admin Guide**.

---

_Generated June 2026 from halo-dev/halo at 7bf96ee. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
