Skip to main content

Quick start with Docker

The fastest way to get Halo running is with Docker and the embedded H2 database.
docker run -d \
  --name halo \
  -p 8090:8090 \
  -v ~/.halo2:/root/.halo2 \
  halohub/halo:2.22
After the container starts, access Halo at http://localhost:8090.

Environment variables

Halo supports the following environment variables for configuration:
HALO_WORK_DIR
string
default:"/root/.halo2"
Working directory for Halo data, including database, logs, and uploads
SPRING_CONFIG_LOCATION
string
Additional Spring configuration file locations
JVM_OPTS
string
default:""
JVM options for memory and performance tuning (e.g., -Xmx512m -Xms512m)
TZ
string
default:"Asia/Shanghai"
Timezone for the container

Production deployment

Do not use the embedded H2 database in production. Use PostgreSQL or MySQL for better performance and reliability.

With PostgreSQL

Create a docker-compose.yml file:
docker-compose.yml
version: '3.8'

services:
  halo:
    image: halohub/halo:2.22
    container_name: halo
    restart: unless-stopped
    ports:
      - "8090:8090"
    volumes:
      - ./halo:/root/.halo2
    command:
      - --spring.r2dbc.url=r2dbc:pool:postgresql://postgres:5432/halo
      - --spring.r2dbc.username=halo
      - --spring.r2dbc.password=your_secure_password
      - --spring.sql.init.platform=postgresql
      - --halo.external-url=https://yourdomain.com
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:15.4
    container_name: halo-postgres
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "halo"]
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      POSTGRES_PASSWORD: your_secure_password
      POSTGRES_USER: halo
      POSTGRES_DB: halo
      PGUSER: halo
    volumes:
      - ./postgres:/var/lib/postgresql/data

With MySQL

Create a docker-compose.yml file:
docker-compose.yml
version: '3.8'

services:
  halo:
    image: halohub/halo:2.22
    container_name: halo
    restart: unless-stopped
    ports:
      - "8090:8090"
    volumes:
      - ./halo:/root/.halo2
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://mysql:3306/halo
      - --spring.r2dbc.username=halo
      - --spring.r2dbc.password=your_secure_password
      - --spring.sql.init.platform=mysql
      - --halo.external-url=https://yourdomain.com
    depends_on:
      mysql:
        condition: service_healthy

  mysql:
    image: mysql:8.0
    container_name: halo-mysql
    restart: unless-stopped
    command:
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      MYSQL_ROOT_PASSWORD: your_secure_password
      MYSQL_DATABASE: halo
      MYSQL_USER: halo
      MYSQL_PASSWORD: your_secure_password
    volumes:
      - ./mysql:/var/lib/mysql

Start your deployment

1

Update configuration

Replace your_secure_password and https://yourdomain.com with your actual values in the docker-compose.yml file.
2

Start containers

docker-compose up -d
3

Check logs

docker-compose logs -f halo
Wait until you see “Started HaloApplication” in the logs.
4

Access Halo

Open your browser and navigate to http://localhost:8090 (or your configured external URL).Complete the initial setup wizard to create your admin account.

Volume mounts

Halo requires persistent storage for data and uploads:
  • Application data: Mount /root/.halo2 to persist database, logs, and configuration
  • Database data: Mount database-specific directories (/var/lib/postgresql/data or /var/lib/mysql)
The working directory contains:
  • db/ - Database files (H2 only)
  • logs/ - Application logs
  • plugins/ - Installed plugins
  • themes/ - Installed themes
  • upload/ - User-uploaded files

JVM tuning

For production environments, configure JVM options based on your server resources:
docker-compose.yml
services:
  halo:
    image: halohub/halo:2.22
    environment:
      - JVM_OPTS=-Xmx2g -Xms2g -XX:+UseG1GC
Recommended settings:
  • Small sites (< 1000 posts): -Xmx512m -Xms512m
  • Medium sites (1000-5000 posts): -Xmx1g -Xms1g
  • Large sites (> 5000 posts): -Xmx2g -Xms2g

Health checks

Halo provides health check endpoints for monitoring:
# Readiness check
curl http://localhost:8090/actuator/health/readiness

# Liveness check
curl http://localhost:8090/actuator/health/liveness
Add health checks to your Docker deployment:
docker-compose.yml
services:
  halo:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s

Upgrading

1

Backup your data

Create a backup of your volumes before upgrading:
docker-compose down
tar -czf halo-backup-$(date +%Y%m%d).tar.gz ./halo ./postgres
2

Update image version

Edit your docker-compose.yml and change the image tag:
image: halohub/halo:2.23  # Update to new version
3

Pull and restart

docker-compose pull
docker-compose up -d
4

Verify upgrade

Check logs for successful startup and database migration:
docker-compose logs -f halo

Next steps

Reverse proxy setup

Configure Nginx or Caddy for SSL and domain routing

Backup and restore

Set up automated backups for your Halo installation

Build docs developers (and LLMs) love