Server Type: Halo is not compatible with shared web hosting environments. You will require a cloud server or a Virtual Private Server (VPS). If you have not yet provisioned a server, you may use our affiliate link to get started.
CPU: There are no specialized processing requirements. The Docker image is optimized for multiple platforms and architectures.
Memory: A minimum of 1GB RAM is required to ensure stable performance.
Disk: Requirements depend on your content. If you do not plan to upload large volumes of attachments, disk space is not a significant constraint. However, using an SSD will improve overall system responsiveness.
Network: While Halo can function offline, certain themes rely on third-party resources and may require public internet access to render correctly.
Halo can be deployed in any environment that supports Docker or Java.
Docker (Recommended): We strongly suggest using Docker for deployment. It eliminates the complexities of manual environment configuration and ensures consistency across different systems.
JRE (Optional): You do not need to install a JRE if you are using the Docker image. For standalone JAR deployments: Halo versions 2.21+ require JRE 21; versions 2.20 and below require JRE 17.
Database: Halo supports PostgreSQL, MySQL, MariaDB, and H2. While H2 is an embedded database that does not require a separate server, the others must be managed independently. The best practice is to use Docker Compose to run Halo alongside its database. Note: Do not use the default H2 database in a production environment; it is prone to data corruption if mishandled. If you must use H2, ensure you perform regular backups.
Web Server (Optional): For production environments using a custom domain, configure a reverse proxy such as Nginx or Caddy. Please note that Halo does not support proxying to a subdirectory (e.g., yourdomain.com/blog).
Wget (Optional): This documentation uses wget for file downloads. Ensure it is installed on your system, though any equivalent download tool may be used.
VIM (Optional): We use VIM for editing configuration files in these examples. You may use any text editor you prefer.
~ (Tilde) – Refers to the current user's home directory.
Image – The Docker image containing the Halo application. This serves as the blueprint for starting your Halo container.
Working Directory – The location where Halo stores all persistent data. At runtime, the application creates a .halo2 folder within your user directory (absolute path: ~/.halo2). This directory holds the database, themes, plugins, attachments, logs, application.yaml, backups, and static files. When using Docker, you must map this directory to ensure data persistence.
Theme – A package consisting of page templates. The visual appearance of your site is determined by the theme activated in the admin panel.
Plugin – A modular software package that extends Halo's functionality. Plugins can be installed, upgraded, or removed independently of the core application.
Before proceeding, please review the "Before You Begin" documentation for a conceptual overview of the Halo ecosystem.
Always follow the official Docker documentation, as some Linux distributions provide outdated versions in their default software repositories.
Halo maintains images across several registries. You may choose your preferred source:
registry.fit2cloud.com/halo/halohalohub/haloghcr.io/halo-dev/haloImportant Note on Versioning: Halo 2 does not update the latest tag to prevent accidental breaking changes for users upgrading from 1.x. You should use a specific version tag. For example:
registry.fit2cloud.com/halo/halo:2 points to the latest 2.x release.:2.21 points to the latest 2.21.x maintenance release.:2.21.0 points to a specific version.We will use registry.fit2cloud.com/halo/halo:2.21 for this guide. Create a dedicated directory for your deployment (e.g., ~/halo):
mkdir ~/halo && cd ~/halo
All persistent data for your Halo instance will be stored here. Ensure this directory is included in your backup routine.
docker-compose.yamlThe following configurations cover various database setups. All Halo settings are passed as container command arguments, eliminating the need for a manual application.yaml file.
version: "3"
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
halo_network:
volumes:
- ./halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
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:
- ./db:/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:
Note: The PostgreSQL container does not expose ports to the host by default. If you require external database access, add a port mapping for 5432 to the halodb service.
version: "3"
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
halo_network:
volumes:
- ./halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
- --spring.r2dbc.username=root
- --spring.r2dbc.password=o#DwN&JSa56
- --spring.sql.init.platform=mysql
- --halo.external-url=http://localhost:8090/
halodb:
image: mysql:8.1.0
restart: on-failure:3
networks:
halo_network:
command:
- --default-authentication-plugin=caching_sha2_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --explicit_defaults_for_timestamp=true
volumes:
- ./mysql:/var/lib/mysql
- ./mysqlBackup:/data/mysqlBackup
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
environment:
- MYSQL_ROOT_PASSWORD=o#DwN&JSa56
- MYSQL_DATABASE=halo
networks:
halo_network:
Note: The MySQL container does not expose ports to the host by default. Add a port mapping for 3306 if external access is needed.
version: "3"
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
restart: on-failure:3
volumes:
- ./halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --halo.external-url=http://localhost:8090/
Warning: Do not use H2 in production. It is highly susceptible to data corruption. Use PostgreSQL or MySQL for live sites.
version: "3"
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
restart: on-failure:3
network_mode: "host"
volumes:
- ./halo2:/root/.halo2
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:mysql://localhost:3306/halo
- --spring.r2dbc.username=root
- --spring.r2dbc.password=YOUR_PASSWORD
- --spring.sql.init.platform=mysql
- --halo.external-url=http://localhost:8090/
- --server.port=8090
If using an external database, you must create the database manually before starting the container. For MySQL, use:
CREATE DATABASE halo CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
| Parameter | Description |
|---|---|
spring.r2dbc.url |
Database connection string (refer to the table below) |
spring.r2dbc.username |
Database username |
spring.r2dbc.password |
Database password |
spring.sql.init.platform |
Database type: postgresql, mysql, mariadb, or h2 |
halo.external-url |
The public URL for the instance. Use your domain or IP |
| Database | URL Format | spring.sql.init.platform |
|---|---|---|
| PostgreSQL | r2dbc:pool:postgresql://{HOST}:{PORT}/{DATABASE} |
postgresql |
| MySQL | r2dbc:pool:mysql://{HOST}:{PORT}/{DATABASE} |
mysql |
| MariaDB | r2dbc:pool:mariadb://{HOST}:{PORT}/{DATABASE} |
mariadb |
| H2 | r2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSE |
h2 |
For a full list of configuration options, please refer to the configuration documentation.
To launch the stack in detached mode:
docker-compose up -d
To monitor logs in real-time:
docker-compose logs -f
Once the container is running, navigate to http://your-ip:8090/console to begin the initialization process.
Note: If you intend to use a custom domain, configure your DNS and reverse proxy before running the initialization. If you cannot access the page via IP, ensure that port 8090 is open in your server's firewall and any cloud provider security groups.
docker-compose.yaml: Update the image tag to the desired version:services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
docker-compose up -d
Ensure your reverse proxy software is already installed. For advanced configurations, refer to the documentation for Nginx Proxy Manager or Traefik.
upstream halo {
server 127.0.0.1:8090;
}
server {
listen 80;
listen [::]:80;
server_name www.yourdomain.com;
client_max_body_size 1024m;
location / {
proxy_pass http://halo;
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
www.yourdomain.com
encode gzip
reverse_proxy 127.0.0.1:8090
To use Traefik, update your Halo stack configuration as follows (assuming an existing traefik network):
version: "3.8"
networks:
traefik:
external: true
halo:
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
restart: on-failure:3
volumes:
- ./halo2:/root/.halo2
networks:
- traefik
- halo
command:
- --halo.external-url=https://yourdomain.com
labels:
traefik.enable: "true"
traefik.docker.network: traefik
traefik.http.routers.halo.rule: Host(`yourdomain.com`)
traefik.http.routers.halo.tls: "true"
traefik.http.routers.halo.tls.certresolver: myresolver
traefik.http.services.halo.loadbalancer.server.port: 8090
How to Install Open Notebook: A Guide for Docker and Source Setup
Parlant: Build AI Agents That Follow Rules, Not Prompts
Coze Studio: Build and Deploy AI Agents with Golang and React
Common Ground: Multi-Agent Collaboration That Actually Works
Build AI Agent Interfaces Faster with agents-ui-kit
LandPPT: Create AI-Powered Presentations from Any Document
Claude Code for Windows: Run Natively Without WSL or Docker
Twenty CRM Local Setup and Docker Deployment Guide for Developers
TensorZero: Optimize LLM Applications with Production Feedback
AgentCPM-GUI: A Local LLM Agent for Navigating Chinese Mobile Apps
News Agents: Scalable RSS Summarization with Amazon Q and tmux
Shendeng VPN: Unlimited Bandwidth, Smart Routing & VIP Membership (¥28/Month)