Skip to content
Docs Extensions Blog Pricing 中文 GitHub

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Pigsty Docs v4.5

PostgreSQL In Great STYle”: Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours.

—— Battery-Included, Local-First PostgreSQL Distribution as a Free & Open-Source RDS Alternative

Free & Open Source Local First Production Ready

GitHub | Demo | Blog | Discuss | Discord | DeepWiki | Roadmap | Chinese Docs

Press with K on macOS, or Ctrl with K, to open local search and the command palette from anywhere.

Getting Started

Learn the project, understand the concepts, get hands-on on a single node, then go to production — four steps to master Pigsty:

Get Started: Prepare a node with a fresh Linux installation, and run as a user with passwordless ssh and sudo privileges:

Terminal
curl -fsSL https://repo.pigsty.io/get | bash -s v4.5.0   # download the public stable source
cd ~/pigsty      # enter source dir
./configure      # generate config
./deploy.yml     # run installation

Download, Configure and Deploy — Pigsty completes installation in minutes! You can add more nodes and database clusters later.

Next, explore the Web UI, access PostgreSQL services on port 5432, and Grafana dashboards on port 3000 (username / password: admin / pigsty).

You can also wrap PostgreSQL kernel flavors as RDS services: Citus, WiltonDB, IvorySQL, OpenHalo, Percona, OrioleDB, PolarDB, and Supabase.

Modules

Pigsty is composed of modules. Among them, PGSQL / INFRA / NODE / ETCD (the PINE stack) are required for self-hosting PostgreSQL RDS services:

There are also optional modules that work well alongside PostgreSQL, bringing extra value to your data infrastructure:

MINIOOPTIONAL

S3-compatible object storage, an optional centralized repository for database backups.

REDISOPTIONAL

High-performance in-memory data structure server with standalone, cluster, and sentinel modes.

DOCKEROPTIONAL

Container runtime for launching containerized, stateless software and application templates.

JUICEOPTIONAL

JuiceFS distributed file system with PostgreSQL as the metadata engine, providing shared POSIX storage.

VIBEOPTIONAL

AI coding sandbox: Code-Server, JupyterLab, Claude Code, and Codex CLI.

KAFKAOPTIONAL

Apache Kafka 4.x dynamic KRaft message queue clusters with security and monitoring included.

MYSQLOPTIONAL

Native MySQL 8.4 LTS as a standalone instance or a three-node InnoDB Cluster.

PILOTPILOT

Experimental module family: Kubernetes, DuckDB, TigerBeetle, and more for early adopters.

Reference

Comprehensive references, the extension catalog, ready-to-use templates, and companion tool manuals:

1 - Get Started

Deploy Pigsty single-node version on your laptop/cloud server, access DB and Web UI

Pigsty uses a scalable architecture design, suitable for both large-scale production environments and single-node development/demo environments. This guide focuses on the latter.

If you intend to learn about Pigsty, you can start with the Quick Start single-node deployment. A Linux virtual machine with 1C/2G is sufficient to run Pigsty.

You can use a Linux MiniPC, free/discounted virtual machines provided by cloud providers, Windows WSL, or create a virtual machine on your own laptop for Pigsty deployment. Pigsty provides out-of-the-box Vagrant templates and Terraform templates to help you provision Linux VMs with one click locally or in the cloud.

pigsty-arch

The single-node version of Pigsty includes all core features: 576 PG extensions, self-contained Grafana/Victoria monitoring, IaC provisioning capabilities, and local PITR point-in-time recovery. If you have external object storage (for PostgreSQL PITR backup), then for scenarios like demos, personal websites, and small services, even a single-node environment can provide a certain degree of data persistence guarantee. However, single-node cannot achieve High Availability—automatic failover requires at least 3 nodes.

If you want to install Pigsty in an environment without internet connection, please refer to the Offline Install mode. If you only need the PostgreSQL database itself, please refer to the Slim Install mode. If you are ready to start serious multi-node production deployment, please refer to the Deployment Guide.


Quick Start

Prepare a node with compatible Linux system, and execute as an admin user with passwordless ssh and sudo privileges:

curl -fsSL https://repo.pigsty.io/get | bash  # Install Pigsty and dependencies
cd ~/pigsty; ./configure -g                   # Generate config (with 1-node template, -g generates random passwords)
./deploy.yml                                  # Execute deployment playbook

Yes, it’s that simple. You can use pre-configured templates to bring up Pigsty with one click without understanding any details.

Next, you can explore the Graphical User Interface, access PostgreSQL database services; or perform configuration customization and execute playbooks to deploy more clusters.

1.1 - Single-Node Installation

Get started with Pigsty—complete single-node install on a fresh Linux host!

This is the Pigsty single-node install guide Single Node. For multi-node HA production deployment, refer to the Deployment docs.

Pigsty single-node installation consists of three steps: Install, Configure, and Deploy.


Summary

Prepare a node with compatible OS, and run as an admin user with nopass ssh and sudo:

pigsty.io (Global)
curl -fsSL https://repo.pigsty.io/get | bash
pigsty.cc (China)
curl -fsSL https://repo.pigsty.cc/get | bash

This command runs the install script, downloads and extracts Pigsty source to your home directory and installs dependencies. Then complete Configure and Deploy:

Enter the Source Directory

Terminal
cd ~/pigsty

Generate the Inventory

Terminal
./configure -g

Skip this step if you already have a prepared pigsty.yml.

Run the Deployment Playbook

Terminal
./deploy.yml

After installation, access the Web UI via IP/domain + port 80/443 through Nginx, and access the default PostgreSQL service via port 5432.

The complete process takes 3–10 minutes depending on server specs/network. Offline installation speeds this up significantly; for monitoring-free setups, use Slim Install for even faster deployment.

Video Example: Online Single-Node Installation (Debian 13, x86_64)

demo/install-hero.cast

Prepare

Installing Pigsty involves some preparation work. Here’s a checklist.

For single-node installations, many constraints can be relaxed—typically you only need to know your IP address. If you don’t have a static IP, use 127.0.0.1.

ItemRequirementItemRequirement
Node1-node, at least 1C2G, no upper limitDisk/data mount point, xfs recommended
OSLinux x86_64 / aarch64, EL/Debian/UbuntuNetworkStatic IPv4; single-node without fixed IP can use 127.0.0.1
SSHnopass SSH login via public keySUDOsudo privilege, preferably with nopass option

Typically, you only need to focus on your local IP address—as an exception, for single-node deployment, use 127.0.0.1 if no static IP available.


Install

Use the following commands to auto-install Pigsty source to ~/pigsty (recommended). Deployment dependencies (Ansible) are installed automatically.

pigsty.io (Global)
curl -fsSL https://repo.pigsty.io/get | bash            # Install current default version
curl -fsSL https://repo.pigsty.io/get | bash -s v4.5.0  # Pin current public stable release
pigsty.cc (China)
curl -fsSL https://repo.pigsty.cc/get | bash            # Install current default version
curl -fsSL https://repo.pigsty.cc/get | bash -s v4.5.0  # Pin current public stable release

If you prefer not to run a remote script, you can manually download or clone the source. When using git, always checkout a specific version before use.

Terminal
git clone https://github.com/pgsty/pigsty; cd pigsty;
git checkout v4.5.0;  # Always checkout a released tag when using git

For manual download/clone installations, run the bootstrap script to install Ansible and other dependencies. You can also install them yourself.

Terminal
./bootstrap           # Install ansible for subsequent deployment

Configure

In Pigsty, deployment blueprints are defined by the inventory, the pigsty.yml configuration file. You can customize through declarative configuration.

Pigsty provides the configure script as an optional configuration wizard, which generates an inventory with good defaults based on your environment and input:

Terminal
./configure -g                # Use config wizard to generate config with random passwords

The generated config file is at ~/pigsty/pigsty.yml by default. Review and customize as needed before installation.

Many configuration templates are available for reference. You can skip the wizard and directly edit pigsty.yml:

Terminal
./configure                  # Default template, install PG 18 with essential extensions
./configure -v 16            # Use PG 16 instead of default PG 18
./configure -c rich          # Create local repo, download all extensions, install major ones
./configure -c slim          # Minimal install template, use with ./slim.yml playbook
./configure -c app/supa      # Use app/supa self-hosted Supabase template
./configure -c ivory         # Use IvorySQL kernel instead of native PG
./configure -i 10.11.12.13   # Explicitly specify primary IP address
./configure -r china         # Use China mirrors instead of default repos
./configure -c ha/full -s    # Use 4-node sandbox template, skip IP replacement/detection

The output below is from v4.5.0. If you install another version, the first line reports that version.

Example 1 Example configure output from the current release
Current configure output
configure output
vagrant@meta:~/pigsty$ ./configure

configure pigsty v4.5.0 begin
[ OK ] region  = default
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = rpm,dnf
[ OK ] vendor  = rocky (Rocky Linux)
[ OK ] version = 9 (9.6)
[ OK ] sudo = vagrant ok
[ OK ] ssh = [email protected] ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.24	inet 192.168.121.24/24 brd 192.168.121.255 scope global dynamic noprefixroute eth0
    (2) 10.10.10.12	    inet 10.10.10.12/24 brd 10.10.10.255 scope global noprefixroute eth1
[ IN ] INPUT primary_ip address (of current meta node, e.g 10.10.10.10):
=> 10.10.10.12    # <------- INPUT YOUR PRIMARY IPV4 ADDRESS HERE!
[ OK ] primary_ip = 10.10.10.12 (from input)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (el9)
[ OK ] locale  = C.UTF-8
[ OK ] configure pigsty done
proceed with ./deploy.yml

Common configure Arguments

-i | --ip , IPv4

The primary private IP of the current host, used to replace the 10.10.10.10 placeholder in the inventory.

-c | --conf , string

A configuration template name relative to conf/, without the .yml suffix.

-v | --version , integer

PostgreSQL major version 14 through 19; PG19 is Beta, so use the dedicated pg19 template.

-r | --region , enum , defaultdefault

Upstream repository region for faster downloads: default, china, or europe.

-n | --non-interactive , boolean , defaultfalse

Use command-line arguments for the primary IP and skip the interactive wizard.

-x | --proxy , boolean , defaultfalse

Use current environment variables to configure proxy_env.

If your machine has multiple IPs bound, use -i|--ip <ipaddr> to explicitly specify the primary IP, or provide it in the interactive prompt. The script replaces the placeholder 10.10.10.10 with your node’s primary IPv4 address. Choose a static IP; do not use public IPs.

Change default passwords!

We strongly recommend modifying default passwords and credentials in the config file before installation. See Security Recommendations for details.


Deploy

Pigsty’s deploy.yml playbook applies the blueprint from Configure to target nodes.

Terminal
./deploy.yml     # Deploy the defined modules in the core path at once
Example deployment output
deploy output
......

TASK [pgsql : pgsql init done] *************************************************
ok: [10.10.10.11] => {
    "msg": "postgres://10.10.10.11/postgres | meta  | dbuser_meta dbuser_view "
}
......

TASK [pg_monitor : load grafana datasource meta] *******************************
changed: [10.10.10.11]

PLAY RECAP *********************************************************************
10.10.10.11                : ok=302  changed=232  unreachable=0    failed=0    skipped=65   rescued=0    ignored=1
localhost                  : ok=6    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

When you see pgsql init done, PLAY RECAP and similar output at the end, installation is complete!

Upstream repo changes may cause online installation failures!

Upstream repos used by Pigsty (like Linux/PGDG repos) can sometimes enter a broken state due to improper updates, causing deployment failures (this has happened multiple times)! You can wait for upstream fixes or use pre-made offline packages to solve this.

Avoid re-running the deployment playbook!

Warning: Running deploy.yml again on an existing deployment may restart services and overwrite configurations!


Interface

After single-node installation, you typically have four modules installed on the current node: PGSQL, INFRA, NODE, and ETCD.

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1infra-1etcd-1

The INFRA module provides a graphical management interface, accessible via Nginx on ports 80/443.

The PGSQL module provides a PostgreSQL database server, listening on 5432, also accessible via Pgbouncer/HAProxy proxies.

Pigsty online demo homepage


More

Use the current node as a base to deploy and monitor more clusters: add cluster definitions to the inventory and run:

bin/node-add   pg-test      # Add the 3 nodes of cluster pg-test to Pigsty management
bin/pgsql-add  pg-test      # Initialize a 3-node pg-test HA PG cluster
bin/redis-add  redis-ms     # Initialize Redis cluster: redis-ms

Most modules require the NODE module installed first. See available modules for details:

PGSQL, INFRA, NODE, ETCD, MINIO, REDIS, DOCKER……

1.2 - Docker Deployment

Spin up Pigsty in Docker containers for quick testing on macOS/Windows

Pigsty is designed for native Linux, but can also run in Linux containers with systemd. If you don’t have native Linux (e.g., macOS or Windows), use Docker to spin up a local single-node Pigsty for testing.


Quick Start

Enter the docker/ dir in Pigsty source and launch with one command:

cd ~/pigsty/docker
make launch          # Start container + generate config + deploy

After deployment, access services:

ServiceURL / CommandCredentials
SSHssh root@localhost -p 2222Password: pigsty
Web Portalhttp://localhost:8080-
Grafanahttp://localhost:8080/uiadmin / grafana_admin_password
PostgreSQLpsql 'postgres://dbuser_dba:<pg_admin_password>@localhost:5432/postgres'pg_admin_password

make launch runs ./configure -g internally to generate random passwords. You can check them with:

cd ~/pigsty/docker
make pass | grep -E 'grafana_admin_password|pg_admin_password'
Web Portal & PostgreSQL

Web Portal and PostgreSQL are only available after Deployment (./deploy.yml) completes.


Prepare

Docker deployment requires:

ItemRequirementItemRequirement
DockerDocker 20.10+ (Desktop or CE)CPUAt least 1 core
RAMAt least 2GBDiskAt least 20GB free

Ensure default host ports (2222/8080/8443/5432) are available, or edit .env first.

Good Use Cases
  • Quick Pigsty experience on macOS/Windows without native Linux
  • Learning and testing Pigsty features, dev and debug
  • Quick local PostgreSQL dev environment
Not Recommended For
  • Production: Container perf and stability inferior to native Linux
  • HA Clusters: Docker single-node mode can’t achieve multi-node HA
  • Large Scale: Use native Linux VMs or physical machines

Image

Pigsty provides an out-of-the-box Docker image on Docker Hub.

ImagePullSizeContents
pgsty/pigsty~500MB1.3GBDebian 13 + systemd + SSH + pig + Ansible
  • Supports both amd64 (x86_64) and arm64 (Apple Silicon, AWS Graviton)
  • Image tags follow Pigsty versions. latest and v4.5.0 both point at the current release; pin the version tag for reproducible builds.
  • Pre-configured with docker template, ready to run ./deploy.yml

Built on Debian 13 (Trixie), pre-installed with pig CLI and Ansible, Pigsty source already initialized.


Launch

Pigsty provides out-of-the-box Docker support in the docker/ source directory.

Simplest way is make launch, which auto-completes: start container, generate config, and deploy:

cd ~/pigsty/docker
make launch          # One-liner: up + config + deploy

Or step by step for inspection at each stage:

cd ~/pigsty/docker
make up              # Start container
make exec            # Enter container
./configure -c docker -g --ip 127.0.0.1  # Generate config (optional, pre-configured)
./deploy.yml         # Execute deployment

To build locally instead of pulling from Docker Hub:

cd ~/pigsty/docker
make build           # Build image locally
make launch          # Start container + generate config + deploy

Config

Customize image version and port mappings via .env:

PIGSTY_VERSION=v4.5.0         # Current main source default; verify the remote tag before pulling
PIGSTY_SSH_PORT=2222          # SSH port
PIGSTY_HTTP_PORT=8080         # Nginx HTTP port
PIGSTY_HTTPS_PORT=8443        # Nginx HTTPS port
PIGSTY_PG_PORT=5432           # PostgreSQL port

Port Mapping:

Env VarDefaultContainerDescription
PIGSTY_VERSIONv4.5.0-Current main source default; verify the remote tag separately
PIGSTY_SSH_PORT222222SSH access port
PIGSTY_HTTP_PORT808080Nginx HTTP port
PIGSTY_HTTPS_PORT8443443Nginx HTTPS port
PIGSTY_PG_PORT54325432PostgreSQL port

Override via env vars if defaults are occupied:

PIGSTY_HTTP_PORT=8888 docker compose up -d

Commands

Pigsty Docker provides Makefile commands for container and image management.

Docker Compose

Recommended way to run:

make up           # Start container
make down         # Stop and remove container
make start        # Start stopped container
make stop         # Stop container
make restart      # Restart container
make pull         # Pull latest image
make config       # Run ./configure in container
make deploy       # Run ./deploy.yml in container
make launch       # One-liner: up + config + deploy

Container Access

make exec         # Enter container bash
make ssh          # SSH into container
make log          # View container logs
make status       # View systemd status
make ps           # View process list
make conf         # View config file
make pass         # View passwords in config

Image Build

make build        # Build image locally
make buildnc      # Build without cache
make push         # Build and push multi-arch image

Image Management

make save         # Export image to pigsty-<version>-<arch>.tgz
make load         # Import image from tgz file
make rmi          # Remove current version's pigsty image

Cleanup

make clean        # Stop and remove container
make purge        # Stop and remove the container, then directly delete ./data in the current directory
Use make purge with care

The current Makefile no longer provides a countdown prompt. After removing the container, make purge runs rm -rf -- ./data directly. Verify the current directory and target data first, and back it up when necessary.


Manual Run

If you prefer docker run over Docker Compose:

mkdir -p ./data
docker run -d --privileged --name pigsty \
  -p 2222:22 -p 8080:80 -p 5432:5432 \
  -v ./data:/data \
  pgsty/pigsty:<version>

docker exec -it pigsty ./configure -c docker -g --ip 127.0.0.1
docker exec -it pigsty ./deploy.yml

Or use Makefile’s make run:

make run          # Start with docker run
make exec         # Enter container
make clean        # Stop and remove container
make purge        # Remove container and directly delete ./data in the current directory

How It Works

Pigsty Docker image is based on Debian 13 (Trixie) with systemd as init. Service management inside container stays consistent with native Linux via systemctl.

Key features:

  • systemd support: Full systemd for proper service management
  • SSH access: Pre-configured SSH, root password is pigsty
  • Privileged mode: Requires --privileged for systemd
  • Data persistence: Via /data volume mount
  • Pre-installed: pig CLI + Ansible, Pigsty source initialized

Image build executes these init steps:

# Install pig CLI
RUN echo "deb [trusted=yes] https://repo.pigsty.io/apt/infra/ generic main" \
    > /etc/apt/sources.list.d/pigsty.list \
    && apt-get update && apt-get install -y pig

# Initialize Pigsty source and install Ansible
RUN pig sty init -v ${PIGSTY_VERSION} \
    && pig sty boot \
    && pig sty conf -c docker --ip 127.0.0.1

Running ./configure with -c docker applies the Docker-optimized config template:

  • Uses 127.0.0.1 as default IP
  • Tuned for container environment

FAQ

Container won’t start

Ensure Docker is properly installed with sufficient resources. On Docker Desktop, allocate at least 2GB RAM. Check for port conflicts on 2222, 8080, 8443, 5432.

Can’t access services

Web Portal and PostgreSQL only available after deployment. Ensure ./deploy.yml finished successfully. Use make status to check service status.

Port conflicts

Override via .env or env vars:

PIGSTY_HTTP_PORT=8888 PIGSTY_PG_PORT=5433 docker compose up -d

Data persistence

Container data mounted to ./data. To wipe and start fresh:

make purge        # Remove container and directly delete ./data in the current directory (no countdown)

macOS performance

On macOS with Docker Desktop, performance is worse than native Linux due to virtualization overhead. Expected—Docker deployment is for dev/testing. For production, use native Linux installation.


More

1.3 - Web Interface

Explore Pigsty’s Web graphical management interface, Grafana dashboards, and how to access them via domain names and HTTPS.

After single-node installation, you’ll have the INFRA module installed on the current node, which includes an out-of-the-box Nginx web server.

The default server configuration provides a WebUI graphical interface for displaying monitoring dashboards and unified proxy access to other component web interfaces.


Access

You can access this graphical interface by entering the deployment node’s IP address in your browser. By default, Nginx serves on standard ports 80/443.

Pigsty online demo homepage


Monitoring

To access Pigsty’s monitoring system dashboards (Grafana), visit the /ui endpoint on the server.

If your service is exposed to Internet or office network, we recommend accessing via domain names and enabling HTTPS encryption—only minimal configuration is needed.


Endpoints

By default, Nginx exposes the following endpoints via different paths on the default server at ports 80/443:

EndpointComponentNative PortDescriptionPublic Demo
/Nginx80/443Homepage, local repo, file servicedemo.pigsty.io
/ui/Grafana3000Grafana dashboard portaldemo.pigsty.io/ui/
/vmetrics/VictoriaMetrics8428Time series database Web UIdemo.pigsty.io/vmetrics/
/vlogs/VictoriaLogs9428Log database Web UIdemo.pigsty.io/vlogs/
/vtraces/VictoriaTraces10428Distributed tracing Web UIdemo.pigsty.io/vtraces/
/vmalert/VMAlert8880Alert rule managementdemo.pigsty.io/vmalert/
/alertmgr/AlertManager9059Alert management Web UIdemo.pigsty.io/alertmgr/
/blackbox/Blackbox9115Blackbox exporter
/haproxy/*HAProxy9101Load balancer admin Web UI
/pevPEV280PostgreSQL execution plan visualizerdemo.pigsty.io/pev
/nginxNginx80Nginx status page (for metrics)

Domain Access

If you have your own domain name, you can point it to Pigsty server’s IP address to access various services via domain.

If you want to enable HTTPS, you should modify the home server configuration in the infra_portal parameter:

all:
  vars:
    infra_portal:
      home : { domain: i.pigsty } # Replace i.pigsty with your domain
all:
  vars:
    infra_portal:  # domain specifies the domain name  # certbot parameter specifies certificate name
      home : { domain: demo.pigsty.io ,certbot: mycert }

You can run make cert command after deployment to apply for a free Let’s Encrypt certificate for the domain. If you don’t define the certbot field, Pigsty will use the local CA to issue a self-signed HTTPS certificate by default. In this case, you must first trust Pigsty’s self-signed CA to access normally in your browser.

You can also mount local directories and other upstream services to Nginx. For more management details, refer to INFRA Management - Nginx.

1.4 - Getting Started with PostgreSQL

Get started with PostgreSQL—connect using CLI and graphical clients

PostgreSQL (abbreviated as PG) is the world’s most advanced and popular open-source relational database. Use it to store and retrieve multi-modal data.

This guide is for developers with basic Linux CLI experience but not very familiar with PostgreSQL, helping you quickly get started with PG in Pigsty.

We assume you’re a personal user deploying in the default single-node mode. For prod multi-node HA cluster access, refer to Prod Service Access.


Basics

In the default single-node installation template, you’ll create a PostgreSQL database cluster named pg-meta on the current node, with only one primary instance.

PostgreSQL listens on port 5432, and the cluster has a preset database meta available for use.

After installation, exit the current admin user ssh session and re-login to refresh environment variables. Then simply type pp and press Enter to access the database cluster via the psql CLI tool (p is the shortcut for the pig CLI):

vagrant@pg-meta-1:~$ pp
psql (18.6 (Ubuntu 18.6-1.pgdg24.04+1))
Type "help" for help.

postgres=#

You can also switch to the postgres OS user and execute psql directly to connect to the default postgres admin database.


Connecting to Database

To access a PostgreSQL database, use a CLI tool or graphical client and fill in the PostgreSQL connection string:

postgres://username:password@host:port/dbname

Some drivers and tools may require you to fill in these parameters separately. The following five are typically required:

ParameterDescriptionExample ValueNotes
hostDatabase server address10.10.10.10Replace with your node IP or domain; can omit for localhost
portPort number5432PG default port, can be omitted
usernameUsernamedbuser_dbaPigsty default database admin
passwordPasswordDBUser.DBAPigsty default admin password (change this!)
dbnameDatabase namemetaDefault template database name

For personal use, you can directly use the Pigsty default database superuser dbuser_dba for connection and management. The dbuser_dba has full database privileges. By default, if you specified the configure -g parameter when configuring Pigsty, the password will be randomly generated and saved in ~/pigsty/pigsty.yml:

cat ~/pigsty/pigsty.yml | grep pg_admin_password

Default Accounts

Pigsty’s default single-node template presets the following database users, ready to use out of the box:

UsernamePasswordRolePurpose
dbuser_dbaDBUser.DBASuperuserDatabase admin (change this!)
dbuser_metaDBUser.MetaBusiness adminApp R/W (change this!)
dbuser_viewDBUser.ViewerRead-only userData viewing (change this!)

For example, you can connect to the meta database in the pg-meta cluster using three different connection strings with three different users:

postgres://dbuser_dba:[email protected]:5432/meta
postgres://dbuser_meta:[email protected]:5432/meta
postgres://dbuser_view:[email protected]:5432/meta

Note: These default passwords are automatically replaced with random strong passwords when using configure -g. Remember to replace the IP address and password with actual values.


Using CLI Tools

psql is the official PostgreSQL CLI client tool, powerful and the first choice for DBAs and developers.

On a server with Pigsty deployed, you can directly use psql to connect to the local database:

# Simplest way: use postgres system user for local connection (no password needed)
sudo -u postgres psql

# Use connection string (recommended, most universal)
psql 'postgres://dbuser_dba:[email protected]:5432/meta'

# Use parameter form
psql -h 10.10.10.10 -p 5432 -U dbuser_dba -d meta

# Use env vars to avoid password appearing in command line
export PGPASSWORD='DBUser.DBA'
psql -h 10.10.10.10 -p 5432 -U dbuser_dba -d meta

After successful connection, you’ll see a prompt like this:

psql (18.6)
Type "help" for help.

meta=#

Common psql Commands

After entering psql, you can execute SQL statements or use meta-commands starting with \:

CommandDescriptionCommandDescription
Ctrl+CInterrupt queryCtrl+DExit psql
\?Show all meta commands\hShow SQL command help
\lList all databases\c dbnameSwitch to database
\d tableView table structure\d+ tableView table details
\duList all users/roles\dxList installed extensions
\dnList all schemas\dtList all tables

Executing SQL

In psql, directly enter SQL statements ending with semicolon ;:

-- Check PostgreSQL version
SELECT version();

-- Check current time
SELECT now();

-- Create a test table
CREATE TABLE test (id SERIAL PRIMARY KEY, name TEXT, created_at TIMESTAMPTZ DEFAULT now());

-- Insert data
INSERT INTO test (name) VALUES ('hello'), ('world');

-- Query data
SELECT * FROM test;

-- Drop test table
DROP TABLE test;

Using Graphical Clients

If you prefer graphical interfaces, here are some popular PostgreSQL clients:

Grafana

Pigsty’s INFRA module includes Grafana with a pre-configured PostgreSQL data source (Meta). You can directly query the database using SQL from the Grafana Explore panel through the browser graphical interface, no additional client tools needed.

Grafana’s default username is admin, and the password can be found in the grafana_admin_password field in the inventory (default pigsty).

DataGrip

DataGrip is a professional database IDE from JetBrains, with powerful features. IntelliJ IDEA’s built-in Database Console can also connect to PostgreSQL in a similar way.

DBeaver

DBeaver is a free open-source universal database tool supporting almost all major databases. It’s a cross-platform desktop client.

pgAdmin

pgAdmin is the official PostgreSQL-specific GUI tool from PGDG, available through browser or as a desktop client.

Pigsty provides a configuration template for one-click pgAdmin service deployment using Docker in Software Template: pgAdmin.


Viewing Monitoring Dashboards

Pigsty provides many PostgreSQL monitoring dashboards, covering everything from cluster overview to single-table analysis.

We recommend starting with PGSQL Overview. Many elements in the dashboards are clickable, allowing you to drill down layer by layer to view details of each cluster, instance, database, and even internal database objects like tables, indexes, and functions.


Trying Extensions

One of PostgreSQL’s most powerful features is its extension ecosystem. Extensions can add new data types, functions, index methods, and more to the database.

Pigsty provides 576 extensions covering 16 major categories including time-series, geographic, vector, and full-text search, installable with one click. Start with three commonly used extensions, then install more extensions such as timescaledb as needed.

  • postgis: Geographic information system for processing maps and location data (installed by default)
  • pgvector: Vector database supporting AI embedding vector similarity search (installed by default)
  • timescaledb: Time-series database for efficient storage and querying of time-series data (optional install)
\dx                            -- psql meta command, list installed extensions
TABLE pg_available_extensions; -- Query installed, available extensions
CREATE EXTENSION postgis;      -- Enable postgis extension

Next Steps

Congratulations on completing the PostgreSQL basics! Next, you can start configuring and customizing your database.

1.5 - Customize Pigsty with Configuration

Express your infra and clusters with declarative config files

Besides using the configuration wizard to auto-generate configs, you can write Pigsty config files from scratch. This tutorial guides you through building a complex inventory step by step.

If you define NODE, INFRA, ETCD, MINIO, and PGSQL in the inventory upfront, deploy.yml can deploy this core path in one run—but it hides the details. Optional modules such as Docker, Redis, Kafka, native MySQL, JUICE, and VIBE require their own playbooks.

This doc breaks down all modules and playbooks, showing how to incrementally build from a simple config to a complete deployment.


Minimal Configuration

The simplest valid config only defines the admin_ip variable—the IP address of the node where Pigsty is installed (admin node):

Minimal
all: { vars: { admin_ip: 10.10.10.10 } }
Mirror
# Set region: china to use mirrors
all: { vars: { admin_ip: 10.10.10.10, region: china } }

This config deploys nothing, but running ./deploy.yml generates a self-signed CA in files/pki/ca for issuing certificates.

For convenience, you can also set region to specify which region’s software mirrors to use (default, china, europe).


Add Nodes

Pigsty’s NODE module manages cluster nodes. Any IP address in the inventory will be managed by Pigsty with the NODE module installed.

Minimal
all:  # Remember to replace 10.10.10.10 with your actual IP
  children: { nodes: { hosts: { 10.10.10.10: {} } } }
  vars:
    admin_ip: 10.10.10.10                   # Current node IP
    region: default                         # Default repos
    node_repo_modules: node,pgsql,infra     # Add node, pgsql, infra repos
Mirror
all:  # Remember to replace 10.10.10.10 with your actual IP
  children: { nodes: { hosts: { 10.10.10.10: {} } } }
  vars:
    admin_ip: 10.10.10.10                 # Current node IP
    region: china                         # Use mirrors
    node_repo_modules: node,pgsql,infra   # Add node, pgsql, infra repos

We added two global parameters: node_repo_modules specifies repos to add; region specifies which region’s mirrors to use.

These parameters enable the node to use correct repositories and install required packages. The NODE module offers many customization options: node names, DNS, repos, packages, NTP, kernel params, tuning templates, monitoring, log collection, etc. Even without changes, the defaults are sufficient.

Run deploy.yml or more precisely node.yml to bring the defined node under Pigsty management.

IDNODEINFRAETCDPGSQLDescription
110.10.10.10---Add node

Add Infrastructure

A full-featured RDS cloud database service needs infrastructure support: monitoring (metrics/log collection, alerting, visualization), NTP, DNS, and other foundational services.

Define a special group infra to deploy the INFRA module:

Minimal
all:  # Simply changed group name from nodes -> infra and added infra_seq
  children: { infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } } }
  vars:
    admin_ip: 10.10.10.10
    region: default
    node_repo_modules: node,pgsql,infra
Mirror
all:  # Simply changed group name from nodes -> infra and added infra_seq
  children: { infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } } }
  vars:
    admin_ip: 10.10.10.10
    region: china
    node_repo_modules: node,pgsql,infra

We also assigned an identity parameter: infra_seq to distinguish nodes in multi-node HA INFRA deployments.

Run infra.yml to install INFRA **](/docs/infra/) and [**NODE modules on 10.10.10.10:

./infra.yml   # Install INFRA module on infra group (includes NODE module)
demo/infra.cast

NODE module is implicitly defined as long as an IP exists. NODE is idempotent—re-running has no side effects.

After completion, you’ll have complete observability infrastructure and node monitoring, but PostgreSQL database service is not yet deployed.

If your goal is just to set up this monitoring system (Grafana + Victoria), you’re done! The infra template is designed for this. Everything in Pigsty is modular: you can deploy only monitoring infra without databases; or vice versa—run HA PostgreSQL clusters without infra—Slim Install.

IDNODEINFRAETCDPGSQLDescription
110.10.10.10infra-1--Add infrastructure

Deploy Database Cluster

To provide PostgreSQL service, install the PGSQL` module and its dependency ETCD—just two lines of config:

Minimal
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq:  1 } } } # Add etcd cluster
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } } # Add pg cluster
  vars: { admin_ip: 10.10.10.10, region: default, node_repo_modules: node,pgsql,infra }
Mirror
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq:  1 } } } # Add etcd cluster
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } } # Add pg cluster
  vars: { admin_ip: 10.10.10.10, region: china, node_repo_modules: node,pgsql,infra }

We added two new groups: etcd and pg-meta, defining a single-node etcd cluster and a single-node PostgreSQL cluster.

Use ./deploy.yml to converge the defined modules in the core path again, or deploy incrementally:

./etcd.yml  -l etcd      # Install ETCD module on etcd group
./pgsql.yml -l pg-meta   # Install PGSQL module on pg-meta group

PGSQL depends on ETCD for HA consensus, so install ETCD first. After completion, you have a working PostgreSQL service!

IDNODEINFRAETCDPGSQLDescription
110.10.10.10infra-1etcd-1pg-meta-1Add etcd and PostgreSQL cluster

We used node.yml, infra.yml, etcd.yml, and pgsql.yml to deploy all four core modules on a single machine.


Define Databases and Users

In Pigsty, you can customize PostgreSQL cluster internals like databases and users through the inventory:

all:
  children:
    # Other groups and variables hidden for brevity
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:       # Define database users
          - { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user  }
        pg_databases:   # Define business databases
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [vector] }
  • pg_users: Defines a new user dbuser_meta with password DBUser.Meta
  • pg_databases: Defines a new database meta with Pigsty CMDB schema (optional) and vector extension

Pigsty offers rich customization parameters covering all aspects of databases and users. If you define these parameters upfront, they’re automatically created during ./pgsql.yml execution. For existing clusters, you can incrementally create or modify users and databases:

bin/pgsql-user pg-meta dbuser_meta      # Ensure user dbuser_meta exists in pg-meta
bin/pgsql-db   pg-meta meta             # Ensure database meta exists in pg-meta

Configure PG Version and Extensions

You can install different major versions of PostgreSQL, and up to 576 extensions. Let’s remove the current default PG 18 and install PG 16:

./pgsql-rm.yml -l pg-meta --check # Preflight old pg-meta removal; execute only after backup and target confirmation

We can customize parameters to install and enable common extensions by default: timescaledb, postgis, and pgvector:

all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq:  1 } } } # Add etcd cluster
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_version: 16   # Specify PG version as 16
        pg_extensions: [ timescaledb, postgis, pgvector ]      # Install these extensions
        pg_libs: 'timescaledb,pg_stat_statements,auto_explain'  # Preload these extension libraries
        pg_databases: { { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [vector, postgis, timescaledb ] } }
        pg_users: { { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user } }

  vars:
    admin_ip: 10.10.10.10
    region: default
    node_repo_modules: node,pgsql,infra
./pgsql.yml -l pg-meta   # Install PG16 and extensions, recreate pg-meta cluster

Add More Nodes

Add more nodes to the deployment, bring them under Pigsty management, deploy monitoring, configure repos, install software…

# Add entire cluster at once, or add nodes individually
bin/node-add pg-test

bin/node-add 10.10.10.11
bin/node-add 10.10.10.12
bin/node-add 10.10.10.13
demo/node.cast

Deploy HA PostgreSQL Cluster

Now deploy a new database cluster pg-test on the three newly added nodes, using a three-node HA architecture:

all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } } }, vars: { etcd_cluster: etcd } }
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }
    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
        10.10.10.12: { pg_seq: 2, pg_role: replica  }
        10.10.10.13: { pg_seq: 3, pg_role: replica  }
      vars: { pg_cluster: pg-test }
demo/pgsql.cast

Deploy Redis Cluster

Pigsty provides optional Redis support as a caching service in front of PostgreSQL:

bin/redis-add redis-ms
bin/redis-add redis-meta
bin/redis-add redis-test

Redis HA requires cluster mode or sentinel mode. See Redis Configuration.


Deploy Silo Object Storage

Pigsty’s MINIO module currently deploys Silo S3-compatible object storage, which can serve as a PostgreSQL backup repository. The module, inventory group, and playbooks retain the compatible minio name.

./minio.yml -l minio

Serious production Silo deployments typically require at least 4 nodes with 4 disks each (4N/16D).


Deploy Docker Module

If you want to use containers to run tools for managing PG or software using PostgreSQL, install the DOCKER module:

./docker.yml -l infra

Use pre-made application templates to launch common software tools with one click, such as the GUI tool for PG management: Pgadmin:

./app.yml    -l infra -e app=pgadmin

You can even self-host enterprise-grade Supabase with Pigsty, using external HA PostgreSQL clusters as the foundation and running stateless components in containers.

1.6 - Run Playbooks with Ansible

Use Ansible playbooks to deploy and manage Pigsty clusters

Pigsty uses Ansible to manage clusters, a very popular large-scale/batch/automation ops tool in the SRE community.

Ansible can use declarative approach for server configuration management. All module deployments are implemented through a series of idempotent Ansible playbooks.

For example, in single-node deployment, you’ll use the deploy.yml playbook. Pigsty has more built-in playbooks, you can choose to use as needed.

Understanding Ansible basics helps with better use of Pigsty, but this is not required, especially for single-node deployment.


Deploy Playbook

Pigsty provides a “one-stop” deploy playbook deploy.yml for the core path: CA/software repository, NODE, INFRA, ETCD, PGSQL, and MINIO when enabled in the inventory. Optional modules such as Redis, Kafka, and native MySQL require their own module playbooks even when defined in the inventory.

PlaybookCommandGroupinfra[nodes]etcdminio[pgsql]
infra.yml./infra.yml-l infra
node.yml./node.yml
etcd.yml./etcd.yml-l etcd
minio.yml./minio.yml-l minio
pgsql.yml./pgsql.yml

This is the simplest deployment method. You can also follow instructions in Customization Guide to incrementally complete deployment of all modules and nodes step by step.


Install Ansible

When using the Pigsty installation script or the bootstrap phase of offline installation, Pigsty will automatically install ansible and its dependencies for you.

If you want to manually install Ansible, refer to the following instructions. The minimum supported Ansible version is 2.9.

Debian / Ubuntu
sudo apt install -y ansible python3-jmespath
EL
sudo dnf install -y ansible python3.12-jmespath python3-cryptography  # EL 8
sudo dnf install -y ansible python3-jmespath                           # EL 9
sudo dnf install -y ansible                                            # EL 10
MacOS
brew install ansible
pip3 install jmespath
Change default passwords!

Please note that EL10 EPEL repo doesn’t yet provide a complete Ansible package. Pigsty PGSQL EL10 repo supplements this.

Ansible is also available on macOS. You can use Homebrew to install Ansible on Mac, and use it as an admin node to manage remote cloud servers. This is convenient for single-node Pigsty deployment on cloud VPS, but not recommended in prod envs.


Execute Playbook

Ansible playbooks are executable YAML files containing a series of task definitions to execute. Running playbooks requires the ansible-playbook executable in your environment variable PATH. Running ./node.yml playbook is essentially executing the ansible-playbook node.yml command.

You can use some parameters to fine-tune playbook execution. The following 4 parameters are essential for effective Ansible use:

PurposeParameterDescription
Target-l|--limit <pattern>Limit execution to specific groups/hosts/patterns
Tasks-t|--tags <tags>Only run tasks with specific tags
Params-e|--extra-vars <vars>Extra command-line parameters
Config-i|--inventory <path>Use a specific inventory file
./node.yml                         # Run node playbook on all hosts
./pgsql.yml -l pg-test             # Run pgsql playbook on pg-test cluster
./infra.yml -t repo_build          # Run infra.yml subtask repo_build
./pgsql-rm.yml -l pg-test -e pg_rm_pkg=false --check # Preflight removal while keeping packages
./infra.yml -i conf/mynginx.yml    # Use another location's config file

Limit Hosts

Playbook execution targets can be limited with -l|--limit <selector>. This is convenient when running playbooks on specific hosts/nodes or groups/clusters. Here are some host limit examples:

./pgsql.yml                              # Run on all hosts (dangerous!)
./pgsql.yml -l pg-test                   # Run on pg-test cluster
./pgsql.yml -l 10.10.10.10               # Run on single host 10.10.10.10
./pgsql.yml -l pg-*                      # Run on hosts/groups matching glob `pg-*`
./pgsql.yml -l '10.10.10.11,&pg-test'    # Run on 10.10.10.11 in pg-test group
./pgsql-rm.yml -l 'pg-test,!10.10.10.11' --check # Preflight removal; verify target and backups before execution

See all details in Ansible documentation: Patterns: targeting hosts and groups

Use caution when running playbooks without host limits!

Missing this value can be dangerous—most playbooks execute on all hosts. Use with caution.


Limit Tasks

Execution tasks can be controlled with -t|--tags <tags>. If specified, only tasks with the given tags will execute instead of the entire playbook.

./infra.yml -t repo          # Create repo
./node.yml  -t node_pkg      # Install node packages
./pgsql.yml -t pg_install    # Install PG packages and extensions
./etcd.yml  -t etcd_config   # Render ETCD configuration again
./minio.yml -t minio_alias   # Write the mcli client alias

To run multiple tasks, specify multiple tags separated by commas -t tag1,tag2:

./node.yml  -t node_repo,node_pkg   # Add repos, then install packages
./pgsql.yml -t pg_hba,pg_reload     # Configure, then reload pg hba rules

Extra Vars

You can override config parameters at runtime using CLI arguments, which have highest priority.

Extra command-line parameters are passed via -e|--extra-vars KEY=VALUE, usable multiple times:

# Create admin using another admin user
./node.yml -e ansible_user=admin -k -K -t node_admin

# Initialize a specific Redis instance: 10.10.10.11:6379
./redis.yml -l 10.10.10.10 -e redis_port=6379 -t redis

# Remove PostgreSQL but keep packages and data
./pgsql-rm.yml -l pg-test -e pg_rm_pkg=false -e pg_rm_data=false --check

For complex parameters, use JSON strings to pass multiple complex parameters at once:

# Add repo and install packages
./node.yml -t node_install -e '{"node_repo_modules":"infra","node_packages":["duckdb"]}'

Specify Inventory

The default config file is pigsty.yml in the Pigsty home directory.

You can use -i <path> to specify a different inventory file path.

./pgsql.yml -i conf/rich.yml            # Initialize single node with all extensions per rich config
./pgsql.yml -i conf/ha/full.yml         # Initialize 4-node cluster per full config
./pgsql.yml -i conf/app/supa.yml        # Initialize 1-node Supabase deployment per supa.yml
Changing the default inventory file

To permanently change the default config file, modify the inventory parameter in ansible.cfg.


Convenience Scripts

Pigsty provides a series of convenience scripts to simplify common operations. These scripts are in the bin/ directory:

bin/node-add   <cls>            # Add nodes to Pigsty management: ./node.yml -l <cls>
bin/node-rm    <cls>            # Remove nodes from Pigsty: ./node-rm.yml -l <cls>
bin/pgsql-add  <cls>            # Initialize PG cluster: ./pgsql.yml -l <cls>
bin/pgsql-rm   <cls>            # Remove PG cluster: ./pgsql-rm.yml -l <cls>
bin/pgsql-user <cls> <username> # Add business user: ./pgsql-user.yml -l <cls> -e username=<user>
bin/pgsql-db   <cls> <dbname>   # Add business database: ./pgsql-db.yml -l <cls> -e dbname=<db>
bin/redis-add  <cls>            # Initialize Redis cluster: ./redis.yml -l <cls>
bin/redis-rm   <cls>            # Remove Redis cluster: ./redis-rm.yml -l <cls>

These scripts are simple wrappers around Ansible playbooks, making common operations more convenient.


Playbook List

Below are the built-in playbooks in Pigsty. You can also easily add your own playbooks, or customize and modify playbook implementation logic as needed.

ModulePlaybookFunction
INFRAdeploy.ymlOne-click deploy Pigsty on current node
INFRAinfra.ymlInitialize Pigsty infrastructure on infra nodes
INFRAinfra-rm.ymlRemove infrastructure components from infra nodes
INFRAcache.ymlCreate offline packages from target node
INFRAcert.ymlIssue certificates using Pigsty self-signed CA
NODEnode.ymlInitialize node, adjust to desired state
NODEnode-rm.ymlRemove node from Pigsty
PGSQLpgsql.ymlInitialize HA PostgreSQL cluster or add replica
PGSQLpgsql-rm.ymlRemove PostgreSQL cluster or replica
PGSQLpgsql-db.ymlAdd new business database to existing cluster
PGSQLpgsql-user.ymlAdd new business user to existing cluster
PGSQLpgsql-pitr.ymlPerform point-in-time recovery on cluster
PGSQLpgsql-monitor.ymlMonitor remote PostgreSQL with local exporter
PGSQLpgsql-migration.ymlGenerate migration manual and scripts
PGSQLslim.ymlInstall Pigsty with minimal components
REDISredis.ymlInitialize Redis cluster/node/instance
REDISredis-rm.ymlRemove Redis cluster/node/instance
ETCDetcd.ymlInitialize ETCD cluster or add new member
ETCDetcd-rm.ymlRemove ETCD cluster/data or shrink member
MINIOminio.ymlInitialize a Silo object-storage cluster
MINIOminio-rm.ymlRemove Silo, its configuration, and optional data
DOCKERdocker.ymlInstall Docker on nodes
DOCKERapp.ymlInstall applications using Docker Compose
JUICEjuice.ymlInstall and configure JuiceFS
VIBEvibe.ymlInstall the Vibe coding environment
KAFKAkafka.ymlCreate or converge a Kafka dynamic KRaft cluster
KAFKAkafka-rm.ymlRemove a Kafka cluster or member
MYSQL (Pilot)mysql.ymlDeploy native MySQL 8.4 standalone or three-node clusters
MYSQL (Pilot)mysql-rm.ymlStop and retire native MySQL while retaining local state

1.7 - Offline Installation

Install Pigsty in air-gapped env using offline packages

Pigsty installs from Internet upstream by default, but some envs are isolated from the Internet. To address this, Pigsty supports offline installation using offline packages. Think of them as Linux-native Docker images.


Overview

Offline packages bundle all required RPM/DEB packages and dependencies; they are snapshots of the local APT/YUM repo after a normal installation.

In serious prod deployments, we strongly recommend using offline packages. They ensure all future nodes have consistent software versions with the existing env, and avoid online installation failures caused by upstream changes (quite common!), guaranteeing you can run it independently forever.

Advantages of offline packages
  • Easy delivery in Internet-isolated envs.
  • Pre-download all packages in one pass to speed up installation.
  • No need to worry about upstream dependency breakage causing install failures.
  • If you have multiple nodes, all packages only need to be downloaded once, saving bandwidth.
  • Use local repo to ensure all nodes have consistent software versions for unified version management.
Disadvantages of offline packages
  • Offline packages are made for specific OS minor versions, typically cannot be used across versions.
  • It’s a snapshot at the time of creation, may not include the latest updates and OS security patches.
  • Offline packages are typically about 1GB, while online installation downloads on-demand, saving space.

Offline Packages

v4.5.0 publishes a dual-architecture offline package for every one of the seven recommended OS versions, fourteen artifacts in total, and all of them are downloadable from GitHub:

Linux DistributionSystem CodeMinor VersionPackage
RockyLinux 9 x86_64el9.x86_649.8pigsty-pkg-v4.5.0.el9.x86_64.tgz
RockyLinux 9 aarch64el9.aarch649.8pigsty-pkg-v4.5.0.el9.aarch64.tgz
RockyLinux 10 x86_64el10.x86_6410.2pigsty-pkg-v4.5.0.el10.x86_64.tgz
RockyLinux 10 aarch64el10.aarch6410.2pigsty-pkg-v4.5.0.el10.aarch64.tgz
Debian 12 x86_64d12.x86_6412.15pigsty-pkg-v4.5.0.d12.x86_64.tgz
Debian 12 aarch64d12.aarch6412.15pigsty-pkg-v4.5.0.d12.aarch64.tgz
Debian 13 x86_64d13.x86_6413.6pigsty-pkg-v4.5.0.d13.x86_64.tgz
Debian 13 aarch64d13.aarch6413.6pigsty-pkg-v4.5.0.d13.aarch64.tgz
Ubuntu 26.04 x86_64u26.x86_6426.04.0pigsty-pkg-v4.5.0.u26.x86_64.tgz
Ubuntu 26.04 aarch64u26.aarch6426.04.0pigsty-pkg-v4.5.0.u26.aarch64.tgz
Ubuntu 24.04 x86_64u24.x86_6424.04.4pigsty-pkg-v4.5.0.u24.x86_64.tgz
Ubuntu 24.04 aarch64u24.aarch6424.04.4pigsty-pkg-v4.5.0.u24.aarch64.tgz
Ubuntu 22.04 x86_64u22.x86_6422.04.5pigsty-pkg-v4.5.0.u22.x86_64.tgz
Ubuntu 22.04 aarch64u22.aarch6422.04.5pigsty-pkg-v4.5.0.u22.aarch64.tgz

Download them from the GitHub release page, which also carries a checksums manifest and a detached PGP signature (.asc) for each artifact. The MD5 checksums for all v4.5.0 offline packages are:

e042059379bdfae8f774022b89e8d1e3  pigsty-pkg-v4.5.0.el9.aarch64.tgz
997e812a433a6b969b976fad2c023a1f  pigsty-pkg-v4.5.0.el9.x86_64.tgz
1e1045db965282d564680534bd7d72e2  pigsty-pkg-v4.5.0.el10.aarch64.tgz
9a53f1e85cbb2d4f85969a6112ae4b05  pigsty-pkg-v4.5.0.el10.x86_64.tgz
b7501783c90311176f21bdd35390c746  pigsty-pkg-v4.5.0.d12.aarch64.tgz
f3ecaa449a0bf8e0f01907f83831e74a  pigsty-pkg-v4.5.0.d12.x86_64.tgz
863165dba76b044ed8615d6743710005  pigsty-pkg-v4.5.0.d13.aarch64.tgz
d86655361ccad7aa95a345a82bb37d10  pigsty-pkg-v4.5.0.d13.x86_64.tgz
017f2d7931eb644d2d0fa2f71930134e  pigsty-pkg-v4.5.0.u26.aarch64.tgz
61451ee610134423ff08f1a69dfced33  pigsty-pkg-v4.5.0.u26.x86_64.tgz
5d9cfc52a25545b56e73e94ab5b5e175  pigsty-pkg-v4.5.0.u24.aarch64.tgz
dba0eef49899509d1524b3a1c37d0ddc  pigsty-pkg-v4.5.0.u24.x86_64.tgz
5564841c7c099489708cd1fe49ffa1b9  pigsty-pkg-v4.5.0.u22.aarch64.tgz
dc52b6cee50cf6226e23b065e5aa8395  pigsty-pkg-v4.5.0.u22.x86_64.tgz
afb5cd77903613cb945bd519e4059c76  pigsty-v4.5.0.tgz
Offline packages are made for specific Linux OS minor versions

When OS minor versions don’t match, it may work or may fail—we don’t recommend taking the risk.

The v4.5.0 artifacts above were built on EL 9.8/10.2, Debian 12.15/13.6, and Ubuntu 22.04.5/24.04.4/26.04.0. Cross-minor installation may fail due to OpenSSL/system library differences. Use online installation on matching OS versions to build your own offline package, or contact us for custom packages.


Using Offline Packages

Offline installation steps:

  1. Download Pigsty offline package, place it at /tmp/pkg.tgz
  2. Download Pigsty source package, extract and enter directory (assume extracted to home: cd ~/pigsty)
  3. ./bootstrap, it will extract the package and configure using local repo (and install ansible from it offline)
  4. ./configure -g -c rich, you can directly use the rich template configured for offline installation, or configure yourself
  5. Run ./deploy.yml as usual to install the core path from the local repository; other optional modules still require their own playbooks
demo/install-offline.cast
Warning

If you encounter “No package nginx available” errors during offline installation, it usually means a previous installation attempt failed. Delete the /www/pigsty directory and re-run the deployment.

If you want to use the already extracted and configured offline package in your own config, modify and ensure these settings:

  • repo_enabled: Set to true, will build local software repo (explicitly disabled in most templates)
  • node_repo_modules: Set to local, then all nodes in the env will install from the local software repo
    • In most templates, this is explicitly set to: node,infra,pgsql, i.e., install directly from these upstream repos.
    • Setting it to local will use the local software repo to install all packages, fastest, no interference from other repos.
    • If you want to use both local and upstream repos, you can add other repo module names too, e.g., local,node,infra,pgsql

The first parameter, if enabled, Pigsty will create a local software repo. The second parameter, if contains local, then all nodes in the env will use this local software repo. If it only contains local, then it becomes the sole repo for all nodes. If you still want to install other packages from other upstream repos, you can add other repo module names too, e.g., local,node,infra,pgsql.

Hybrid Installation Mode

If your environment has Internet access, there’s a hybrid approach that combines the advantages of offline and online installation. You can use the offline package as a base, and supplement missing packages online.

For example, suppose you run RockyLinux 9.6 while the v4.5.0 package was built for RockyLinux 9.8. You can use the el9 offline package (though made for 9.8), then execute make repo-build before formal installation to re-download missing packages for 9.6. Pigsty will download the required increments from upstream repos.


Making Offline Packages

If your OS isn’t in the default list, you can make your own offline package with the built-in cache.yml playbook:

  1. Find a node running the exact same OS version with Internet access
  2. Use the rich template for an online installation (./configure -c rich), and confirm that the target INFRA node has generated its local repository at /www/pigsty; if not, run ./infra.yml -t repo against that node first
  3. Run cd ~/pigsty; ./cache.yml -l <infra-host> to select one INFRA node that already has a local repository, build the package there, and fetch it
  4. By default, the artifact is ~/pigsty/dist/${version}/pigsty-pkg-${version}.${os}.${arch}.tgz; copy it to the offline environment (ftp, scp, USB, etc.), then unpack it with bootstrap

Current cache.yml defaults can be overridden with extra variables:

ParameterDefaultDescription
cache_pkg_namepigsty-pkg-${version}.${os}.${arch}.tgzOffline package filename template
cache_pkg_dirdist/${version}Output directory on the admin node
cache_repopigstyLocal repository to package on the target node; separate multiple repositories with commas

We offer paid services providing tested, pre-made offline packages for specific Linux major.minor versions (¥200).


Bootstrap

Pigsty relies on ansible to execute playbooks; this script is responsible for ensuring ansible is correctly installed in various ways.

./bootstrap       # Ensure ansible is correctly installed (if offline package exists, use offline installation and extract first)

Usually, you need to run this script in two cases:

  • You didn’t install Pigsty via the installation script, but by downloading or git clone of the source package, so ansible isn’t installed.
  • You’re preparing to install Pigsty via offline packages and need to use this script to install ansible from the offline package.

The bootstrap script will automatically detect if the offline package exists (-p to specify, default is /tmp/pkg.tgz). If it exists, it will extract and use it, then install ansible from it. If the offline package doesn’t exist, it will try to install ansible from the Internet. If that still fails, you’re on your own!

Where are my yum/apt repo files?

The bootloader will by default move away existing repo configurations to ensure only required repos are enabled. You can find them in /etc/yum.repos.d/backup (EL) or /etc/apt/backup (Debian / Ubuntu).

If you want to keep existing repo configurations during bootstrap, use the -k|--keep parameter.

./bootstrap -k # or --keep

1.8 - Slim Installation

Install only HA PostgreSQL clusters with minimal dependencies

If you only want HA PostgreSQL database cluster itself without monitoring, infra, etc., consider Slim Installation.

Slim installation has no INFRA module, no monitoring, no local repo—just ETCD and PGSQL and partial NODE functionality.

Slim installation is suitable for:
  • Only needing PostgreSQL database itself, no observability infra required.
  • Extremely resource-constrained envs unwilling to bear infra overhead (~0.2 vCPU / 500MB on single node).
  • Already having external monitoring system, wanting to use your own unified monitoring framework.
  • Not needing the Grafana visualization dashboard component.
Limitations of slim installation:
  • No INFRA module, cannot use WebUI and local software repo features.
  • Offline Install is limited to single-node mode; multi-node slim install can only be done online.

Overview

To use slim installation, you need to:

  1. Use the slim.yml slim install config template (configure -c slim)
  2. Run the slim.yml playbook instead of the default deploy.yml
curl https://repo.pigsty.io/get | bash
./configure -g -c slim
./slim.yml
demo/install-slim.cast

Description

Slim installation only installs/configures these components:

ComponentRequiredDescription
patroni⚠️ RequiredBootstrap HA PostgreSQL cluster
etcd⚠️ RequiredMeta database dependency (DCS) for Patroni
pgbouncer✔️ OptionalPostgreSQL connection pooler
vip-manager✔️ OptionalL2 VIP binding to PostgreSQL cluster primary
haproxy✔️ OptionalAuto-routing services via Patroni health checks
chronyd✔️ OptionalTime synchronization with NTP server
tuned✔️ OptionalNode tuning template and kernel parameter management

You can disable all optional components via configuration, keeping only the required patroni and etcd.

Because there’s no INFRA module’s Nginx providing local repo service, offline installation only works in single-node mode.


Configuration

Slim installation config file example: conf/slim.yml:

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1No INFRA moduleetcd-1
---
#==============================================================#
# File      :   slim.yml
# Desc      :   Pigsty slim installation config template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://pigsty.io/docs/conf/slim
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for slim / minimal installation
# No monitoring & infra will be installed, just raw postgresql
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c slim
#   ./slim.yml

all:
  children:

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        #10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        #10.10.10.12: { etcd_seq: 3 }  # three-member cluster keeps an odd voter count
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd

    #----------------------------------------------#
    # PostgreSQL Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        #10.10.10.11: { pg_seq: 2, pg_role: replica } # you can add more!
        #10.10.10.12: { pg_seq: 3, pg_role: replica, pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ vector ]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Deployment

Slim installation uses the slim.yml playbook instead of deploy.yml:

./slim.yml

HA Cluster

Slim installation can also deploy HA clusters—just add more nodes to the etcd and pg-meta groups. A three-node deployment example:

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1No INFRA moduleetcd-1
210.10.10.11pg-meta-2No INFRA moduleetcd-2
310.10.10.12pg-meta-3No INFRA moduleetcd-3
all:
  children:
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
        10.10.10.11: { etcd_seq: 2 }  # <-- New
        10.10.10.12: { etcd_seq: 3 }  # <-- New

    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica } # <-- New
        10.10.10.12: { pg_seq: 3, pg_role: replica } # <-- New
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ vector ]}
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # full backup daily at 1am
  vars:
    # omitted ……

1.9 - Security Recommendations

Basic security checks for quick-start and single-node deployments.

The default configuration targets local demonstrations and development or testing on a trusted intranet. If other hosts can reach the deployment, complete at least three checks: credentials, network boundaries, and critical files.

Production environments should also review the Security Model, Compliance, and Security Considerations.


Passwords

Pigsty default credentials are public in the source code and documentation and must not be used directly in production.

The configuration wizard can randomize built-in parameters and example credentials that it recognizes:

./configure -g

configure -g does not replace:

  • the pgBackRest cipher_pass;
  • Silo users and selected example passwords in ha/safe;
  • database, object-storage, or application credentials added by the user.

After generation, inspect pigsty.yml and replace every uncovered credential. The wizard prints generated passwords to the terminal, so protect terminal history and automation logs as sensitive data.

See the Default Credentials Checklist for the complete scope.


Firewall

node_firewall_mode defaults to zone. It trusts the intranet defined by node_firewall_intranet and restricts ports exposed to public networks.

PortServicePublic by Default
22SSHYes
80Nginx HTTPYes
443Nginx HTTPSYes
5432PostgreSQLNot in the base default; exposed additionally by the demo pigsty.yml

Production deployments should normally remove 5432 from the demo configuration. If applications need direct database access, restrict source addresses in the cloud security group, host firewall, and HBA.

Also verify that the intranet definition matches the actual trust boundary. The default RFC 1918 ranges may be too broad; office networks, container networks, and other tenant networks should not become trusted automatically.


Files

The following files and directories contain highly sensitive information:

  • pigsty.yml: system and application credentials, node definitions, and service configuration;
  • files/pki/ca/ca.key: local CA private key;
  • the administration user’s SSH private key, used to access managed nodes;
  • files/pki/misc/*.key: client-certificate private keys;
  • /pg/tmp/pg-user-*.sql: SQL containing plaintext passwords generated during user creation.

Restrict access to the admin node and configuration repository. Do not commit complete inventories or private keys to public repositories. Maintain controlled backups of the CA private key and required configuration.


2 - Deployment

Multi-node, high-availability Pigsty deployment for production environments.

Unlike Getting Started, production Pigsty deployments require more Architecture Planning and Preparation.

This chapter helps you understand the complete deployment process and provides best practices for production environments.


Before deploying to production, we recommend testing in Pigsty’s Sandbox to fully understand the workflow. Use Vagrant to create a local 4-node sandbox, or leverage Terraform to provision larger simulation environments in the cloud.

pigsty-sandbox

For production, you typically need at least three nodes for high availability. You should understand Pigsty’s core Concepts and common administration procedures, including Configuration, Ansible Playbooks, and Security Hardening for enterprise compliance.

2.1 - Install Pigsty for Production

How to install Pigsty on Linux hosts for production?

This is the Pigsty production multi-node deployment guide. For single-node Demo/Dev setups, see Getting Started.


Summary

Prepare nodes with SSH access following your architecture plan, install a compatible Linux OS, then execute with an admin user having passwordless ssh and sudo:

curl -fsSL https://repo.pigsty.io/get | bash;         # International
curl -fsSL https://repo.pigsty.cc/get | bash;         # Backup Mirror

This runs the install script, downloading and extracting Pigsty source to your home directory with dependencies installed. Complete configuration and deployment to finish.

Before running deploy.yml for deployment, review and edit the configuration inventory: pigsty.yml.

cd ~/pigsty      # Enter Pigsty directory
./configure -g   # Generate config file (optional, skip if you know how to configure)
./deploy.yml     # Execute deployment playbook based on generated config

After installation, access the WebUI via IP/domain + ports 80/443, and PostgreSQL service via port 5432.

Full installation takes 3-10 minutes depending on specs/network. Offline installation significantly speeds this up; slim installation further accelerates when monitoring isn’t needed.

Video Example: 20-node Production Simulation (Ubuntu 24.04 x86_64)

demo/install-simu.cast

Prepare

Production Pigsty deployment involves preparation work. Here’s the complete checklist:

ItemRequirementItemRequirement
NodeAt least 1C2G, no upper limitPlanMultiple homogeneous nodes: 2/3/4 or more
Disk/data as default mount pointFSxfs recommended; ext4/zfs as needed
VIPL2 VIP, optional (unavailable in cloud)NetworkStatic IPv4, single-node can use 127.0.0.1
CASelf-signed CA or specify existing certsDomainLocal/public domain, optional, default i.pigsty
KernelLinux x86_64 / aarch64Linuxel8, el9, el10, d12, d13, u22, u24, u26
LocaleC.UTF-8 or CFirewallPorts: 80/443/22/5432 (optional)
UserAvoid root and postgresSudosudo privilege, preferably with nopass
SSHPasswordless SSH via public keyAccessiblessh <ip|alias> sudo ls no error

Install

Use the following to automatically install the Pigsty source package to ~/pigsty (recommended). Deployment dependencies (Ansible) are auto-installed.

pigsty.io (Global)
curl -fsSL https://repo.pigsty.io/get | bash            # Install current default version
curl -fsSL https://repo.pigsty.io/get | bash -s v4.5.0  # Explicitly install the current public stable release
pigsty.cc (China)
curl -fsSL https://repo.pigsty.cc/get | bash            # Install current default version
curl -fsSL https://repo.pigsty.cc/get | bash -s v4.5.0  # Explicitly install the current public stable release

If you prefer not to run remote scripts, manually download or clone the source. When using git, always checkout a specific version before use:

git clone https://github.com/pgsty/pigsty; cd pigsty;
git checkout v4.5.0;  # Always checkout a released tag when using git

For manual download/clone, additionally run bootstrap to manually install Ansible and other dependencies, or install them yourself:

./bootstrap           # Install ansible for subsequent deployment

Configure

In Pigsty, deployment details are defined by the configuration inventory—the pigsty.yml config file. Customize through declarative configuration.

Pigsty provides configure as an optional configuration wizard, generating a configuration inventory with good defaults based on your environment:

./configure -g                # Use wizard to generate config with random passwords

The generated config defaults to ~/pigsty/pigsty.yml. Review and customize before installation.

Many configuration templates are available for reference. You can skip the wizard and directly edit pigsty.yml:

./configure -c ha/full -g       # Use 4-node sandbox template
./configure -c ha/trio -g       # Use 3-node minimal HA template
./configure -c ha/dual -g -v 18 # Use 2-node semi-HA template with PG 18
./configure -c ha/simu -s       # Use 20-node production simulation, skip IP check, no random passwords
Example configure output
vagrant@meta:~/pigsty$ ./configure
configure pigsty v4.5.0 begin
[ OK ] region = china
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = deb,apt
[ OK ] vendor  = ubuntu (Ubuntu)
[ OK ] version = 22 (22.04)
[ OK ] sudo = vagrant ok
[ OK ] ssh = [email protected] ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.38	    inet 192.168.121.38/24 metric 100 brd 192.168.121.255 scope global dynamic eth0
    (2) 10.10.10.10	    inet 10.10.10.10/24 brd 10.10.10.255 scope global eth1
[ OK ] primary_ip = 10.10.10.10 (from demo)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (ubuntu22.04)
[ OK ] locale  = C.UTF-8
[ OK ] ansible = ready
[ OK ] pigsty configured
[WARN] don't forget to check it and change passwords!
proceed with ./deploy.yml

The wizard only replaces the current node’s IP (use -s to skip replacement). For multi-node deployments, replace other node IPs manually. Also customize the config as needed—modify default passwords, add nodes, etc.

Common configure parameters:

ParameterDescription
-c|--confSpecify config template relative to conf/, without .yml suffix
-v|--versionPostgreSQL major version 14 through 19; PG19 is currently Beta
-r|--regionUpstream repo region for faster downloads: default|china|europe
-n|--non-interactiveUse CLI params for primary IP, skip interactive wizard
-x|--proxyConfigure proxy_env from current environment variables

If your machine has multiple IPs, explicitly specify one with -i|--ip <ipaddr> or provide it interactively. The script replaces IP placeholder 10.10.10.10 with the current node’s primary IPv4. Use a static IP; never use public IPs.

Generated config is at ~/pigsty/pigsty.yml. Review and modify before installation.

Change default passwords!

Change default passwords and credentials before installation. See Security Recommendations.


Deploy

Pigsty’s deploy.yml playbook applies the configuration blueprint to all target nodes.

./deploy.yml     # Deploy core modules on all target nodes at once
Example deployment output
......

TASK [pgsql : pgsql init done] *************************************************
ok: [10.10.10.11] => {
    "msg": "postgres://10.10.10.11/postgres | meta  | dbuser_meta dbuser_view "
}
......

TASK [pg_monitor : load grafana datasource meta] *******************************
changed: [10.10.10.11]

PLAY RECAP *********************************************************************
10.10.10.11                : ok=302  changed=232  unreachable=0    failed=0    skipped=65   rescued=0    ignored=1
localhost                  : ok=6    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

When output ends with pgsql init done, PLAY RECAP, etc., installation is complete!

Upstream repo changes may cause online installation failures!

Upstream repos (Linux/PGDG) may break due to improper updates, causing deployment failures (quite common)! For serious production deployments, we strongly recommend using verified offline packages for offline installation.

Avoid running deploy playbook repeatedly!

Warning: Running deploy.yml again on an initialized environment may restart services and overwrite configs. Be careful!


Interface

Assuming the 4-node deployment template, your Pigsty environment should have a structure like:

IDNODEPGSQLINFRAETCD
110.10.10.10pg-meta-1infra-1etcd-1
210.10.10.11pg-test-1--
310.10.10.12pg-test-2--
410.10.10.13pg-test-3--

The INFRA module provides a graphical management interface via browser, accessible through Nginx’s 80/443 ports.

The PGSQL module provides a PostgreSQL database server on port 5432, also accessible via Pgbouncer/HAProxy proxies.

For production multi-node HA PostgreSQL clusters, use service access for automatic traffic routing.

Pigsty online demo homepage


More

After installation, explore the WebUI and access PostgreSQL service via port 5432.

Deploy and monitor more clusters—add definitions to the configuration inventory and run:

bin/node-add   pg-test      # Add pg-test cluster's 3 nodes to Pigsty management
bin/pgsql-add  pg-test      # Initialize a 3-node pg-test HA PG cluster
bin/redis-add  redis-ms     # Initialize Redis cluster: redis-ms

Most modules require the NODE module first. See available modules:

PGSQL, INFRA, NODE, ETCD, MINIO, REDIS, DOCKER

2.2 - Prepare Resources for Serious Deployment

Production deployment preparation including hardware, nodes, disks, network, VIP, domain, software, and filesystem requirements.

Pigsty runs on nodes (physical machines or VMs). This document covers the planning and preparation required for deployment.


Node

Pigsty currently runs on Linux kernel with x86_64 / aarch64 architecture. A “node” refers to an SSH accessible resource that provides a bare Linux OS environment. It can be a physical machine, virtual machine, or a systemd-enabled container equipped with systemd, sudo, and sshd.

Deploying Pigsty requires at least 1 node. You can prepare more and deploy everything in one pass via playbooks, or add nodes later. The minimum spec requirement is 1C1G, but at least 1C2G is recommended. Higher is better—no upper limit. Parameters are auto-tuned based on available resources.

The number of nodes you need depends on your requirements. See Architecture Planning for details. Although a single-node deployment with external backup provides reasonable recovery guarantees, we recommend multiple nodes for production. A functioning HA setup requires at least 3 nodes; 2 nodes provide Semi-HA.


Disk

Pigsty uses /data as the default data directory. If you have a dedicated data disk, mount it there. Use /data1, /data2, /dataN for additional disk drives.

To use a different data directory, configure these parameters:

NameDescriptionDefault
node_dataNode main data directory/data
pg_fs_mainPG main data directory/data/postgres
pg_fs_backupPG backup directory/data/backups
etcd_dataETCD data directory/data/etcd
infra_dataInfra data directory/data/infra
nginx_dataNginx data directory/data/nginx
minio_dataSilo data directory/data/minio
redis_fs_mainRedis data directory/data/redis
kafka_dataKafka data directory/data/kafka

The native MySQL 8.4 pilot module does not currently expose a data-directory parameter and always uses /var/lib/mysql.


Filesystem

You can use any supported Linux filesystem for data disks. For production, we recommend xfs.

xfs is a Linux standard with excellent performance and CoW capabilities for instant large database cluster cloning. Multi-drive Silo deployments require xfs. ext4 is another viable option with a richer data recovery tool ecosystem, but lacks CoW. zfs provides RAID and snapshot features but with significant performance overhead and requires separate installation.

Choose among these three based on your needs. Avoid NFS for database services.

Pigsty assumes /data is owned by root:root with 755 permissions. Admins can assign ownership for first-level directories; each application runs with a dedicated user in its subdirectory. See FHS for the directory structure reference.


Network

Pigsty defaults to online installation mode, requiring outbound Internet access. Offline installation eliminates the Internet requirement.

Internally, Pigsty requires a static network. Assign a fixed IPv4 address to each node.

The IP address serves as the node’s unique identifier—the primary IP bound to the main network interface for internal communications.

For single-node deployment without a fixed IP, use the loopback address 127.0.0.1 as a workaround.

Never use Public IP as identifier

Using public IP addresses as node identifiers can cause security and connectivity issues. Always use internal IP addresses.


VIP

Pigsty supports optional L2 VIP for NODE clusters (keepalived) and PGSQL clusters (vip-manager).

To use L2 VIP, you must explicitly assign an L2 VIP address for each node/database cluster. This is straightforward on your own hardware but may be challenging in public cloud environments.

L2 VIP requires L2 Networking

To use optional Node VIP and PG VIP features, ensure all nodes are on the same L2 network.


CA

Pigsty generates a self-signed CA infrastructure for each deployment, issuing all encryption certificates.

If you have an existing enterprise CA or self-signed CA, you can use it to issue the certificates Pigsty requires.


Domain

Pigsty uses a local static domain i.pigsty by default for WebUI access. This is optional—IP addresses work too.

For production, domain names are recommended to enable HTTPS and encrypted data transmission. Domains also allow multiple services on the same port, differentiated by domain name.

For Internet-facing deployments, use public DNS providers (Cloudflare, AWS Route53, etc.) to manage resolution. Point your domain to the Pigsty node’s public IP address. For LAN/office network deployments, use internal DNS servers with the node’s internal IP address.

For local-only access, add the following to /etc/hosts on machines accessing the Pigsty WebUI:

10.10.10.10 i.pigsty    # Replace with your domain and Pigsty node IP

Linux

Pigsty runs on Linux. It currently targets 16 platform combinations: eight distribution major versions across two architectures. See the Compatible OS List.

We recommend Rocky Linux 9.8 / 10.2, Debian 12.15 / 13.6, or Ubuntu 22.04.5 / 24.04.4 / 26.04.0 as default options.

On macOS and Windows, use VM software or Docker systemd images to run Pigsty.

We strongly recommend a fresh OS installation. If your server already runs Nginx, PostgreSQL, or similar services, consider deploying on new nodes.

Use the same OS version on all nodes

For multi-node deployments, ensure all nodes use the same Linux distribution, architecture, and version. Heterogeneous deployments may work but are unsupported and may cause unpredictable issues.


Locale

We recommend setting en_US as the primary OS language, or at minimum ensuring this locale is available, so PostgreSQL logs are in English.

Some distributions (e.g., Debian) may not provide the en_US locale by default. Enable it with:

localedef -i en_US -f UTF-8 en_US.UTF-8
localectl set-locale LANG=en_US.UTF-8

For PostgreSQL, we strongly recommend using the built-in C.UTF-8 collation (PG 17+) as the default.

The configuration wizard automatically sets C.UTF-8 as the collation when PG version and OS support are detected.


Ansible

Pigsty uses Ansible to control all managed nodes from the admin node. See Installing Ansible for details.

Pigsty installs Ansible on Infra nodes by default, making them usable as admin nodes (or backup admin nodes). For single-node deployment, the installation node serves as both the admin node running Ansible and the INFRA node hosting infrastructure.


Pigsty

You can install the current default Pigsty source with:

pigsty.io (Global)
curl -fsSL https://repo.pigsty.io/get | bash;
pigsty.cc (China)
curl -fsSL https://repo.pigsty.cc/get | bash;

To install a specific version, use the -s <version> parameter:

pigsty.io (Global)
curl -fsSL https://repo.pigsty.io/get | bash -s <version>  # Install a specific version (current stable: v4.5.0)
pigsty.cc (China)
curl -fsSL https://repo.pigsty.cc/get | bash -s <version>  # Install a specific version (current stable: v4.5.0)

To install the latest beta version:

pigsty.io (Global)
curl -fsSL https://repo.pigsty.io/beta | bash;
pigsty.cc (China)
curl -fsSL https://repo.pigsty.cc/beta | bash;

For developers or the latest development version, clone the repository directly:

git clone https://github.com/pgsty/pigsty.git;
cd pigsty; git checkout <tag>  # Use a released version (current stable tag: v4.5.0)

If your environment lacks Internet access, download the source tarball from GitHub Releases or the Pigsty repository:

wget https://repo.pigsty.io/src/pigsty-v<version>.tgz
wget https://repo.pigsty.cc/src/pigsty-v<version>.tgz

2.3 - Planning Architecture and Nodes

How many nodes? Which modules need HA? How to plan based on available resources and requirements?

Pigsty uses a modular architecture. You can combine modules like building blocks and express your intent through declarative configuration.

Common Patterns

Here are common deployment patterns for reference. Customize based on your requirements:

PatternINFRAETCDPGSQLMINIODescription
Single-node (meta)111Single-node deployment default
Slim deploy (slim)11Database only, no monitoring infra
Infra-only (infra)1Monitoring infrastructure only
Rich deploy (rich)1111Single-node + object storage + local repo with all extensions
Multi-node PatternINFRAETCDPGSQLMINIODescription
Two-node (dual)112Semi-HA, tolerates specific node failure
Three-node (trio)333Standard HA, tolerates any one failure
Four-node (full)111+3Demo setup, single INFRA/ETCD
Production (simu)23nn2 INFRA, 3 ETCD
Large-scale (custom)35nn3 INFRA, 5 ETCD

Your architecture choice depends on reliability requirements and available resources. Serious production deployments require at least 3 nodes for HA configuration. With only 2 nodes, use Semi-HA configuration.

Expert Consulting: Architecture Planning

We offer Architecture Consulting Services to help plan your Pigsty configuration.


Trade-offs

  • Pigsty monitoring requires at least 1 INFRA node. Production typically uses 2; large-scale deployments use 3.
  • PostgreSQL HA requires at least 1 ETCD node. Production typically uses 3; large-scale uses 5. Even-member clusters work, but do not tolerate more failures than an odd cluster with one fewer member, so prefer odd sizes.
  • Silo object storage through the MINIO module requires at least 1 MINIO node. Production typically uses 4+ nodes in MNMD clusters.
  • Production PG clusters typically use at least two-node primary-replica configuration; serious deployments use 3 nodes; high read loads can have dozens of replicas.
  • For PostgreSQL, you can also use advanced configurations: offline instances, sync instances, standby clusters, delayed clusters, etc.

Single-Node Setup

The simplest configuration with everything on a single node. Installs four essential modules by default. Typically used for demos, devbox, or testing.

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1infra-1etcd-1

With an external S3/MinIO backup repository providing RTO/RPO guarantees, this configuration works for standard production environments.

Single-node variants:


Two-Node Setup

Two-node configuration enables database replication and Semi-HA capability with better data redundancy and limited failover support:

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1 (replica)infra-1etcd-1
2node-2pg-meta-2 (primary)

Two-node HA auto-failover has limitations. This “Semi-HA” setup only auto-recovers from specific node failures:

  • If node-1 fails: No automatic failover—requires manual promotion of node-2
  • If node-2 fails: Automatic failover works—node-1 auto-promoted

Three-Node Setup

Three-node template provides true baseline HA configuration, tolerating any single node failure with automatic recovery.

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1infra-1etcd-1
2node-2pg-meta-2infra-2etcd-2
3node-3pg-meta-3infra-3etcd-3

Four-Node Setup

Pigsty Sandbox uses the standard four-node configuration.

IDNODEPGSQLINFRAETCD
1node-1pg-meta-1infra-1etcd-1
2node-2pg-test-1
3node-3pg-test-2
4node-4pg-test-3

For demo purposes, INFRA / ETCD modules aren’t configured for HA. You can adjust further:

IDNODEPGSQLINFRAETCDMINIO
1node-1pg-meta-1infra-1etcd-1minio-1
2node-2pg-test-1infra-2etcd-2
3node-3pg-test-2etcd-3
4node-4pg-test-3

More Nodes

With proper virtualization infrastructure or abundant resources, you can use more nodes for dedicated deployment of each module, achieving optimal reliability, observability, and performance.

IDNODEINFRAETCDMINIOPGSQL
110.10.10.10infra-1pg-meta-1
210.10.10.11infra-2pg-meta-2
310.10.10.21etcd-1
410.10.10.22etcd-2
510.10.10.23etcd-3
610.10.10.31minio-1
710.10.10.32minio-2
810.10.10.33minio-3
910.10.10.34minio-4
1010.10.10.40pg-src-1
1110.10.10.41pg-src-2
1210.10.10.42pg-src-3
1310.10.10.50pg-test-1
1410.10.10.51pg-test-2
1510.10.10.52pg-test-3
16……

2.4 - Setup Admin User and Privileges

Admin user, sudo, SSH, accessibility verification, and firewall configuration

Pigsty requires an OS admin user with passwordless SSH and Sudo privileges on all managed nodes.

This user must be able to SSH to all managed nodes and execute sudo commands on them.


User

Typically use names like dba or admin, avoiding root and postgres:

  • Using root for deployment is possible but not a production best practice.
  • Using postgres (pg_dbsu) as admin user is strictly prohibited.

Passwordless

The passwordless requirement is optional if you can accept entering a password for every ssh and sudo command.

Use -k|--ask-pass when running playbooks to prompt for SSH password, and -K|--ask-become-pass to prompt for sudo password.

./deploy.yml -k -K

Some enterprise security policies may prohibit passwordless ssh or sudo. In such cases, use the options above, or consider configuring a sudoers rule with a longer password cache time to reduce password prompts.


Create Admin User

Typically, your server/VM provider creates an initial admin user.

If unsatisfied with that user, Pigsty’s deployment playbook can create a new admin user for you.

Assuming you have root access or an existing admin user on the node, create an admin user with Pigsty itself:

./node.yml -k -K -t node_admin \
  -e ansible_user=[current_login_admin] \
  -e node_admin_username=[new_admin_to_create]

This leverages the existing admin to create a new one—a dedicated dba (uid=88) user described by these parameters, with sudo/ssh properly configured:

NameDescriptionDefault
node_admin_enabledEnable node admin usertrue
node_admin_uidNode admin user UID88
node_admin_usernameNode admin usernamedba

Sudo

All admin users should have sudo privileges on all managed nodes, preferably with passwordless execution.

To configure an admin user with passwordless sudo from scratch, edit/create a sudoers file (assuming username vagrant):

echo '%vagrant ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/vagrant

For admin user dba, the /etc/sudoers.d/dba content should be:

%dba ALL=(ALL) NOPASSWD: ALL

If your security policy prohibits passwordless sudo, remove the NOPASSWD: part:

%dba ALL=(ALL) ALL

Ansible relies on sudo to execute commands with root privileges on managed nodes. In environments where sudo is unavailable (e.g., inside Docker containers), install sudo first.


SSH

Your current user should have passwordless SSH access to all managed nodes as the corresponding admin user.

Your current user can be the admin user itself, but this isn’t required—as long as you can SSH as the admin user.

SSH configuration is Linux 101, but here are the basics:

Generate SSH Key

If you don’t have an SSH key pair, generate one:

ssh-keygen -t rsa -b 2048 -N '' -f ~/.ssh/id_rsa -q

Pigsty will do this for you during the bootstrap stage if you lack a key pair.

Copy SSH Key

Distribute your generated public key to remote (and local) servers, placing it in the admin user’s ~/.ssh/authorized_keys file on all nodes. Use the ssh-copy-id utility:

ssh-copy-id <ip>                        # Interactive password entry
sshpass -p <password> ssh-copy-id <ip>  # Non-interactive (use with caution)

Using Alias

When direct SSH access is unavailable (jumpserver, non-standard port, different credentials), configure SSH aliases in ~/.ssh/config:

Host meta
    HostName 10.10.10.10
    User dba                      # Different user on remote
    IdentityFile /etc/dba/id_rsa  # Non-standard key
    Port 24                       # Non-standard port

Reference the alias in the inventory using ansible_host for the real SSH alias:

nodes:
  hosts:          # If node `10.10.10.10` requires SSH alias `meta`
    10.10.10.10: { ansible_host: meta }  # Access via `ssh meta`

SSH parameters work directly in Ansible. See Ansible Inventory Guide for details. This technique enables accessing nodes in private networks via jumpservers, or using different ports and credentials, or using your local laptop as an admin node.


Check Accessibility

You should be able to passwordlessly ssh from the admin node to all managed nodes as your current user. The remote user (admin user) should have privileges to run passwordless sudo commands.

To verify passwordless ssh/sudo works, run this command on the admin node for all managed nodes:

ssh <ip|alias> 'sudo ls'

If there’s no password prompt or error, passwordless ssh/sudo is working as expected.


Firewall

Production deployments typically require firewall configuration to block unauthorized port access.

By default, block inbound access from office/Internet networks except:

  • SSH port 22 for node access
  • HTTP (80) / HTTPS (443) for WebUI services
  • PostgreSQL port 5432 for database access

If accessing PostgreSQL via other ports, allow them accordingly. See used ports for the complete port list.

  • 5432: PostgreSQL database
  • 6432: Pgbouncer connection pooler
  • 5433: PG primary service
  • 5434: PG replica service
  • 5436: PG default service
  • 5438: PG offline service

2.5 - Sandbox

4-node sandbox environment for learning, testing, and demonstration

Pigsty provides a standard 4-node sandbox environment for learning, testing, and feature demonstration.

The sandbox uses fixed IP addresses and predefined identity identifiers, making it easy to reproduce various demo use cases.


Description

The default sandbox environment consists of 4 nodes, using the ha/full.yml configuration template.

IDIP AddressNodePostgreSQLINFRAETCDMINIO
110.10.10.10metapg-meta-1infra-1etcd-1minio-1
210.10.10.11node-1pg-test-1
310.10.10.12node-2pg-test-2
410.10.10.13node-3pg-test-3

The sandbox configuration can be summarized as the following config:

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq:  1 } }, vars: { etcd_cluster: etcd } }
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:  { pg_cluster: pg-meta }

    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
        10.10.10.12: { pg_seq: 2, pg_role: replica }
        10.10.10.13: { pg_seq: 3, pg_role: replica }
      vars: { pg_cluster: pg-test }

  vars:
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default
    pg_version: 18
pigsty-sandbox

PostgreSQL Clusters

The sandbox comes with a single-instance PostgreSQL cluster pg-meta on the meta node:

10.10.10.10 meta pg-meta-1
10.10.10.2  pg-meta          # Optional L2 VIP

There’s also a 3-instance PostgreSQL HA cluster pg-test deployed on the other three nodes:

10.10.10.11 node-1 pg-test-1
10.10.10.12 node-2 pg-test-2
10.10.10.13 node-3 pg-test-3
10.10.10.3  pg-test          # Optional L2 VIP

Two optional L2 VIPs are bound to the primary instances of pg-meta and pg-test clusters respectively.

Infrastructure

The meta node also hosts:

  • ETCD cluster: Single-node etcd cluster providing DCS service for PostgreSQL HA
  • Silo cluster: A single-node minio cluster managed by the MINIO module, providing S3-compatible object storage
10.10.10.10 etcd-1
10.10.10.10 minio-1

ha/full.yml also declares three Redis example topologies and enables Docker installation on the INFRA node. The standard deploy.yml does not deploy these two optional modules; run ./redis.yml and ./docker.yml separately when needed.


Creating Sandbox

Pigsty provides out-of-the-box templates. You can use Vagrant to create a local sandbox, or use Terraform to create a cloud sandbox.

Local Sandbox (Vagrant)

Local sandbox uses VirtualBox/libvirt to create local virtual machines, running free on your Mac / PC.

To run the full 4-node sandbox, your machine should have at least 4 CPU cores and 8GB memory.

cd ~/pigsty/vagrant
make full       # Create 4-node sandbox with default Ubuntu 24.04 image
make full9      # Create 4-node sandbox with RockyLinux 9
make full12     # Create 4-node sandbox with Debian 12
make full24     # Create 4-node sandbox with Ubuntu 24.04
make full26     # Create 4-node sandbox with Ubuntu 26.04

The current Vagrant configuration uses the cloud-image/* boxes from Vagrant Cloud. See Vagrant: Supported Images for available images, source-pinned versions, and architecture details. Boxes without a version pinned in source are resolved by Vagrant to their currently available version.

Cloud Sandbox (Terraform)

Cloud sandbox uses public cloud API to create virtual machines. Easy to create and destroy, pay-as-you-go, ideal for quick testing.

Use the spec/aliyun-full.tf template to create a 4-node sandbox on Alibaba Cloud:

cd ~/pigsty/terraform
cp spec/aliyun-full.tf terraform.tf
terraform init
terraform apply

For more details, please refer to Terraform documentation.


Other Specs

Besides the standard 4-node sandbox, Pigsty also provides other environment specs:

Run the following Makefile shortcuts from ~/pigsty/vagrant:

cd ~/pigsty/vagrant

Single Node Devbox (meta)

The simplest 1-node environment for quick start, development, and testing:

make meta       # Create single-node devbox

Two Node Environment (dual)

2-node environment for testing primary-replica replication:

make dual       # Create 2-node environment

Three Node Environment (trio)

3-node environment for testing basic high availability:

make trio       # Create 3-node environment

Production Simulation (simu)

20-node large simulation environment for full production environment testing:

make simu       # Create 20-node production simulation environment

This environment includes:

  • 3 infrastructure nodes (meta1, meta2, meta3)
  • 2 HAProxy proxy nodes
  • 4 MINIO (Silo) nodes
  • 5 ETCD nodes
  • 6 PostgreSQL nodes (2 clusters, 3 nodes each)

2.6 - Vagrant

Create local virtual machine environment with Vagrant

Vagrant is a popular local virtualization tool that creates local virtual machines in a declarative manner.

Pigsty requires a Linux environment to run. You can use Vagrant to easily create Linux virtual machines locally for testing.

The currently recommended and validated baselines are Rocky Linux 9.8 / 10.2, Debian 12.15 / 13.6, and Ubuntu 22.04.5 / 24.04.4 / 26.04.0. Major-version Vagrant aliases map to pinned box versions.


Quick Start

Install Dependencies

First, ensure you have Vagrant and a virtual machine provider (such as VirtualBox or libvirt) installed on your system.

On macOS, you can use Homebrew for one-click installation:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install vagrant virtualbox ansible
VirtualBox requires reboot after installation

After installing VirtualBox, you need to restart your system and allow its kernel extensions in System Preferences.

On Linux, you can use VirtualBox or vagrant-libvirt as the VM provider.

Create Virtual Machines

Use the Pigsty-provided make shortcuts to create virtual machines:

cd ~/pigsty/vagrant

make meta       # 1 node devbox for quick start, development, and testing
make full       # 4 node sandbox for HA testing and feature demonstration
make simu       # 20 node simubox for production environment simulation

# Other less common specs
make dual       # 2 node environment
make trio       # 3 node environment
make deci       # 10 node environment

You can use variant aliases to specify different operating system images:

make meta9      # Create single node with Rocky Linux 9.8
make full12     # Create 4-node sandbox with Debian 12.15
make simu24     # Create 20-node simubox with Ubuntu 24.04.4
make full26     # Create 4-node sandbox with Ubuntu 26.04.0

Available OS suffixes: 8 (EL8), 9 (EL9), 10 (EL10), 12 (Debian 12.15), 13 (Debian 13.6), 22 (Ubuntu 22.04.5), 24 (Ubuntu 24.04.4), 26 (Ubuntu 26.04.0)

Build Environment

You can also use the following aliases to create Pigsty build environments. These templates won’t replace the base image:

make oss        # 7 node OSS build environment
make pro        # 7 node PRO build environment
make rpm        # 2 node EL9/10 build environment
make deb        # 5 node Debian12/13 Ubuntu22/24/26 build environment
make all        # 7 node full build environment

Spec Templates

Pigsty provides multiple predefined VM specs in the vagrant/spec/ directory:

TemplateNodesSpecDescriptionAlias
meta.rb1 node2c4g x 1Single-node devboxDevbox
dual.rb2 nodes1c2g x 2Two-node environment
trio.rb3 nodes1c2g x 3Three-node environment
full.rb4 nodes2c4g + 1c2g x 34-node full sandboxSandbox
deci.rb10 nodesMixed10-node environment
simu.rb20 nodesMixed20-node production simuboxSimubox
minio.rb4 nodes1c2g x 4 + diskMinIO test environment
citus.rb13 nodesMixedCitus coordinator and six two-replica worker groups
oss.rb7 nodes2c2g x 77-platform OSS build environment
pro.rb7 nodes2c2g x 77-platform PRO build environment
rpm.rb2 nodes1c2g x 22-node EL build environment
deb.rb5 nodes1c2g x 55-node Deb build environment
all.rb7 nodes1c2g x 77-node full build environment

Each spec file contains a Specs variable describing the VM nodes. For example, full.rb contains the 4-node sandbox definition:

Current Vagrant templates explicitly provision a 32 GB primary system disk for every VM. Regular nodes also receive one data disk whose size comes from the spec’s disk value, defaulting to 128 GB when omitted. Object-storage nodes whose names begin with minio instead receive four 32 GB data disks mounted at /data1 through /data4. These disks depend on Vagrant’s experimental disks feature. The repository Makefile exports VAGRANT_EXPERIMENTAL=disks automatically; set it yourself when invoking vagrant directly.

# full: pigsty full-featured 4-node sandbox for HA-testing & tutorial & practices

Specs = [
  { "name" => "meta"   , "ip" => "10.10.10.10" ,  "cpu" => "2" ,  "mem" => "4096" ,  "image" => "cloud-image/ubuntu-24.04" },
  { "name" => "node-1" , "ip" => "10.10.10.11" ,  "cpu" => "1" ,  "mem" => "2048" ,  "image" => "cloud-image/ubuntu-24.04" },
  { "name" => "node-2" , "ip" => "10.10.10.12" ,  "cpu" => "1" ,  "mem" => "2048" ,  "image" => "cloud-image/ubuntu-24.04" },
  { "name" => "node-3" , "ip" => "10.10.10.13" ,  "cpu" => "1" ,  "mem" => "2048" ,  "image" => "cloud-image/ubuntu-24.04" },
]

simu Spec Details

simu.rb provides a 20-node production environment simulation configuration:

  • 3 x infra nodes (meta1-3): 4c16g
  • 2 x haproxy nodes (proxy1-2): 1c2g
  • 4 x minio nodes (minio1-4): 1c2g
  • 5 x etcd nodes (etcd1-5): 1c2g
  • 6 x pgsql nodes (pg-src-1-3, pg-dst-1-3): 2c4g

Config Script

Use the vagrant/config script to generate the final Vagrantfile based on spec and options:

cd ~/pigsty/vagrant
vagrant/config [spec] [image] [scale] [provider]

# Examples
vagrant/config meta u24            # Use 1-node spec with Ubuntu 24.04.4 image
vagrant/config dual el9            # Use 2-node spec with RockyLinux 9.7 image
vagrant/config trio d12 2          # Use 3-node spec with Debian 12.14, double resources
vagrant/config full u22 4          # Use 4-node spec with Ubuntu 22.04.5, 4x resources
vagrant/config simu u26 1 libvirt  # Use 20-node spec with Ubuntu 26.04.0, libvirt provider

Image Aliases

The config script supports various image aliases:

DistroAliasVagrant Box
Rocky 8el8, rocky8, r8cloud-image/rocky-8
Rocky 9el9, rocky9, el, r9cloud-image/rocky-9
Rocky 10el10, rocky10, r10cloud-image/rocky-10
Debian 12d12, debian12, deb12cloud-image/debian-12
Debian 13d13, debian13, deb13cloud-image/debian-13
Ubuntu 22.04.5u22, ubuntu22, ubuntu2204cloud-image/ubuntu-22.04
Ubuntu 24.04.4u24, ubuntu24, ubuntu2404, ubuntucloud-image/ubuntu-24.04
Ubuntu 26.04.0u26, ubuntu26, ubuntu2604cloud-image/ubuntu-26.04
AlmaLinux 8alma8cloud-image/almalinux-8
AlmaLinux 9alma9cloud-image/almalinux-9
AlmaLinux 10alma10cloud-image/almalinux-10
RHEL 8 / 9rhel8, rhel9generic/rhel8, generic/rhel9
Oracle Linux 8 / 9oracle8, oracle9generic/oracle8, generic/oracle9

The historical d11/debian11/deb11 and u20/ubuntu20/ubuntu2004 aliases remain visible in the script mapping, but the current script explicitly rejects them; they are not supported images.

Resource Scaling

You can use the VM_SCALE environment variable to adjust the resource multiplier (default is 1):

VM_SCALE=2 vagrant/config meta     # Double the CPU/memory resources for meta spec

For example, using VM_SCALE=4 with the meta spec will adjust the default 2c4g to 8c16g:

Specs = [
  { "name" => "meta" , "ip" => "10.10.10.10", "cpu" => "8" , "mem" => "16384" , "image" => "cloud-image/ubuntu-24.04" },
]
simu and deci specs don’t support scaling

The simu and deci specs don’t support resource scaling. The scale parameter is automatically reset to 1 because their resource configurations are already optimized for simulation scenarios.


VM Management

The vagrant/Makefile provides shortcuts for managing virtual machines. Run the following commands from that directory:

cd ~/pigsty/vagrant
make           # Equivalent to make start
make new       # Destroy existing VMs and create new ones
make ssh       # Write VM SSH config to ~/.ssh/ (must run after creation)
make dns       # Write VM DNS records to /etc/hosts (optional)
make start     # Start VMs and configure SSH (up + ssh)
make up        # Start VMs with vagrant up
make halt      # Shutdown VMs (alias: down, dw)
make clean     # Destroy VMs (alias: del, destroy)
make status    # Show VM status (alias: st)
make pause     # Pause VMs (alias: suspend)
make resume    # Resume VMs
make nuke      # Destroy all VMs and volumes with virsh (libvirt only)
make info      # Show libvirt info (VMs, networks, storage volumes)

SSH Keys

Pigsty Vagrant templates use your ~/.ssh/id_rsa[.pub] as the SSH key for VMs by default.

Before starting, ensure you have a valid SSH key pair. If not, generate one with:

ssh-keygen -t rsa -b 2048 -N '' -f ~/.ssh/id_rsa -q

Supported Images

The standard EL, Debian, Ubuntu, and AlmaLinux matrix uses cloud-image/* boxes from Vagrant Cloud. Explicit RHEL and Oracle Linux aliases use generic/* boxes. The current config script applies the same cloud-image/* mapping to VirtualBox, libvirt, amd64, and arm64; actual payload availability is still resolved by Vagrant Cloud at runtime.

VirtualBox and libvirt use the same mapping. vagrant/config writes the validated versions below for every supported cloud-image/* image, making amd64 and arm64 environments reproducible:

OSVagrant BoxSource Version Policy
Rocky 8cloud-image/rocky-88.10.20240528.0
Rocky 9cloud-image/rocky-99.8.20260525.0
Rocky 10cloud-image/rocky-1010.2.20260525.0
Debian 12cloud-image/debian-1220260806.2562.0
Debian 13cloud-image/debian-1320260810.2566.0
Ubuntu 22.04cloud-image/ubuntu-22.0420260810.0.0
Ubuntu 24.04cloud-image/ubuntu-24.0420260801.0.0
Ubuntu 26.04cloud-image/ubuntu-26.0420260731.0.0
AlmaLinux 8cloud-image/almalinux-88.10.20260803
AlmaLinux 9cloud-image/almalinux-99.8.20260810
AlmaLinux 10cloud-image/almalinux-1010.2.20260526.0

The retained but unsupported Debian 11 and Ubuntu 20.04 aliases are pinned to 20260618.2513.0 and 20250624.0.0; experimental generic/* RHEL, Oracle Linux, and CentOS 7 images are pinned to their final 4.3.12 release. These legacy images are outside the current support matrix.


Environment Variables

You can use the following environment variables to control Vagrant behavior:

export VM_SPEC='meta'              # Spec name
export VM_IMAGE='cloud-image/rocky-9' # Image name
export VM_SCALE='1'                # Resource scaling multiplier
export VM_PROVIDER='virtualbox'    # Virtualization provider
export VAGRANT_EXPERIMENTAL=disks  # Enable disks for direct vagrant use; Makefile sets this automatically

Notes

VirtualBox Network Configuration

When using older versions of VirtualBox as Vagrant provider, additional configuration is required to use 10.x.x.x CIDR as Host-Only network:

echo "* 10.0.0.0/8" | sudo tee -a /etc/vbox/networks.conf
First-time image download is slow

The first time you use Vagrant to start a specific operating system, it will download the corresponding Box image file (typically 1-2 GB). After download, the image is cached and reused for subsequent VM creation.

libvirt Provider

If you’re using libvirt as the provider, you can use make info to view VMs, networks, and storage volume information, and make nuke to forcefully destroy all related resources.

2.7 - Terraform

Create virtual machine environment on public cloud with Terraform

Terraform is a popular “Infrastructure as Code” tool that you can use to create virtual machines on public clouds with one click.

Pigsty currently provides example Terraform templates for Alibaba Cloud, AWS (global and China), Azure, GCP, Tencent Cloud, Hetzner, Vultr, DigitalOcean, and Linode. The aliyun-s3.tf template also creates a private OSS bucket and dedicated RAM read/write credentials for S3/pgBackRest scenarios.


Quick Start

Install Terraform

On macOS, you can use Homebrew to install Terraform:

brew install terraform

For other platforms, refer to the Terraform Official Installation Guide.

Initialize and Apply

Enter the Terraform directory, select a template, initialize provider plugins, and apply the configuration:

cd ~/pigsty/terraform
cp spec/aliyun.tf terraform.tf         # Select template
terraform init                         # Install cloud provider plugins (first use)
terraform apply                        # Generate execution plan and create resources

After running the apply command, type yes to confirm when prompted. Terraform will create VMs and related cloud resources for you.

Get IP Address

After creation, print the public IP address of the admin node:

terraform output -raw meta_ip

Configure SSH Access

Global-cloud templates usually also provide an executable ssh_command output:

terraform output -raw ssh_command

The repository’s ./ssh script is a compatibility tool for legacy templates whose outputs are all IP addresses and whose root password is PigstyDemo4. It iterates over every Terraform output, treats it as an IP address, writes it to ~/.ssh/pigsty_config, and distributes keys with sshpass. It is suitable for compatibility templates such as aliyun.tf, aliyun-full.tf, aliyun-oss.tf, and aliyun-pro.tf. Do not run it against modern templates that output ssh_command, private IPs, or access keys.

When using a compatible template:

./ssh       # Write SSH config and distribute keys
ssh meta    # Login using hostname instead of IP
Using SSH Config File

If you want to use the configuration in ~/.ssh/pigsty_config, ensure your ~/.ssh/config includes:

Include ~/.ssh/pigsty_config

Destroy Resources

After testing, you can destroy all created cloud resources with one click:

terraform destroy

Template Specs

Pigsty provides multiple predefined cloud resource templates in the terraform/spec/ directory:

Template FileCloud ProviderDescription
aliyun.tfAlibaba CloudSingle-node meta template, supports all distributions and AMD/ARM (default)
aliyun-s3.tfAlibaba CloudSingle node + private OSS bucket and RAM read/write credentials for S3/pgBackRest
aliyun-full.tfAlibaba CloudFour-node sandbox, supports all distributions and AMD/ARM
aliyun-oss.tfAlibaba CloudSix-node build template, supports all distributions and AMD/ARM
aliyun-pro.tfAlibaba CloudSeven-node multi-distribution test template
aws.tfAWSGlobal AWS single node, Debian 12/13, AMD/ARM
aws-cn.tfAWSLegacy single-node environment for AWS China
azure.tfAzureSingle node, Debian 12/13, AMD/ARM
gcp.tfGCPSingle node, Debian 12/13, AMD/ARM
qcloud.tfTencent CloudTencent Cloud single-node environment
hetzner.tfHetznerSingle node, Debian 12/13, AMD/ARM
vultr.tfVultrSingle node, Debian 12/13, currently AMD only
digitalocean.tfDigitalOceanSingle node, Debian 12/13, currently AMD only
linode.tfLinodeSingle node, Debian 12/13, currently AMD only

When using a template, copy the template file to terraform.tf:

cd ~/pigsty/terraform
cp spec/aliyun-full.tf terraform.tf   # Use Alibaba Cloud 4-node sandbox template
terraform init && terraform apply

Variable Configuration

Variables differ between templates. Alibaba Cloud templates support the full multi-distribution matrix and default to u26. Global AWS, Azure, GCP, Tencent Cloud, and Hetzner support Debian 12/13 with AMD/ARM selection and generally default to d12/amd64. Vultr, DigitalOcean, and Linode currently expose AMD instance choices only.

Architecture and Distribution

variable "architecture" {
  description = "Architecture type (amd64 or arm64)"
  type        = string
  default     = "amd64"    # Comment this line to use arm64
  #default     = "arm64"   # Uncomment to use arm64
}

variable "distro" {
  description = "Distribution code (the exact set depends on the template)"
  type        = string
  default     = "d12"       # Global-cloud templates usually default to Debian 12; Alibaba Cloud defaults to u26
}

Resource Configuration

Alibaba Cloud templates expose the following resource parameters in a locals block. Other cloud templates use provider-specific instance, disk, and network variables or local values; consult the selected .tf file.

locals {
  bandwidth        = 100                    # Public bandwidth (Mbps)
  disk_size        = 40                     # System disk size (GB)
  spot_policy      = "SpotWithPriceLimit"   # Spot policy: NoSpot, SpotWithPriceLimit, SpotAsPriceGo
  spot_price_limit = 5                      # Max spot price (only effective with SpotWithPriceLimit)
}

Alibaba Cloud Configuration

Credential Setup

Add your Alibaba Cloud credentials to environment variables, for example in ~/.bash_profile or ~/.zshrc:

export ALICLOUD_ACCESS_KEY="<your_access_key>"
export ALICLOUD_SECRET_KEY="<your_secret_key>"
export ALICLOUD_REGION="cn-shanghai"

Supported Images

The following are commonly used ECS Public OS Image prefixes in Alibaba Cloud:

The currently recommended and validated baselines are Rocky Linux 9.8 / 10.2, Debian 12.15 / 13.6, and Ubuntu 22.04.5 / 24.04.4 / 26.04.0.

DistroCodex86_64 Image Prefixaarch64 Image Prefix
CentOS 7.9el7centos_7_9_x64-
Rocky 8.10el8rockylinux_8_10_x64rockylinux_8_10_arm64
Rocky 9.8el9rockylinux_9_8_x64rockylinux_9_8_arm64
Rocky 10.2el10rockylinux_10_2_x64rockylinux_10_2_arm64
Debian 11.11d11debian_11_11_x64-
Debian 12.15d12debian_12_15_x64debian_12_15_arm64
Debian 13.6d13debian_13_6_x64debian_13_6_arm64
Ubuntu 22.04.5 LTSu22ubuntu_22_04_x64_20Gubuntu_22_04_arm64_20G
Ubuntu 24.04.4 LTSu24ubuntu_24_04_x64_20Gubuntu_24_04_arm64_20G
Ubuntu 26.04.0 LTSu26ubuntu_26_04_x64_20Gubuntu_26_04_arm64_20G
Anolis 8.10an8anolisos_8_10_x64anolisos_8_10_arm64
Alibaba Cloud Linux 3al3aliyun_3_x64_20G_alibase_[0-9]+aliyun_3_arm64_20G_alibase_[0-9]+

OSS Storage Configuration

The aliyun-s3.tf template additionally creates an OSS bucket and related permissions for PostgreSQL PITR backup:

  • OSS Bucket: Creates a private bucket named pigsty-oss
  • RAM User: Creates a dedicated pigsty-oss-user user
  • Access Key: Generates AccessKey and saves to ~/pigsty.sk
  • RAM Policy: Grants the user oss:* permissions on the bucket and its objects for read/write use

AWS Configuration

Credential Setup

Both global and China-region templates can read standard AWS environment variables or credential files:

export AWS_ACCESS_KEY_ID="<your_access_key>"
export AWS_SECRET_ACCESS_KEY="<your_secret_key>"
export AWS_REGION="us-west-2"

# ~/.aws/config
[default]
region = us-west-2

# ~/.aws/credentials
[default]
aws_access_key_id = <YOUR_AWS_ACCESS_KEY>
aws_secret_access_key = <AWS_ACCESS_SECRET>

aws.tf reads ~/.ssh/id_rsa.pub by default. The legacy China-region aws-cn.tf instead reads this dedicated public key:

~/.aws/pigsty-key.pub
AWS templates may need adjustments

aws.tf uses a rolling lookup for official Debian AMIs. aws-cn.tf uses a hard-coded China-region AMI and ~/.aws/pigsty-key.pub; verify the target region, AMI, and key before deployment.


Tencent Cloud Configuration

Credential Setup

Add Tencent Cloud credentials to environment variables:

export TENCENTCLOUD_SECRET_ID="<your_secret_id>"
export TENCENTCLOUD_SECRET_KEY="<your_secret_key>"
export TENCENTCLOUD_REGION="ap-beijing"
Tencent Cloud templates may need adjustments

Tencent Cloud templates are community-contributed examples and may need adjustments based on your specific requirements.

Other Cloud Credentials

# Azure: az login is recommended; for a service principal, use all four
export ARM_CLIENT_ID="<client_id>"
export ARM_CLIENT_SECRET="<client_secret>"
export ARM_SUBSCRIPTION_ID="<subscription_id>"
export ARM_TENANT_ID="<tenant_id>"

# GCP: gcloud auth application-default login is also supported
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"

# Hetzner / Vultr / DigitalOcean / Linode
export HCLOUD_TOKEN="<api_token>"
export VULTR_API_KEY="<api_key>"
export DIGITALOCEAN_TOKEN="<api_token>"
export LINODE_TOKEN="<api_token>"

The GCP template also requires a project variable, for example terraform apply -var="project=my-project". Except for AWS China, current key-based templates read ~/.ssh/id_rsa.pub by default; edit the selected template to use another public-key path.


Shortcut Commands

Pigsty provides some Makefile shortcuts for Terraform operations:

cd ~/pigsty/terraform

make u          # terraform apply -auto-approve + run legacy ./ssh (compatible templates only)
make d          # terraform destroy -auto-approve
make apply      # terraform apply (interactive confirmation)
make destroy    # terraform destroy (interactive confirmation)
make out        # terraform output
make ssh        # Run ssh script to configure SSH access
make r          # Reset terraform.tf to repository state

For modern templates with ssh_command, private-IP, or other non-IP outputs, run terraform apply directly; do not use make u, which invokes the legacy ./ssh script afterward.


Notes

Cloud Resource Costs

Cloud resources created with Terraform incur costs. After testing, promptly use terraform destroy to destroy resources to avoid unnecessary expenses.

It’s recommended to use pay-as-you-go instance types for testing. Templates default to using Spot Instances to reduce costs.

Default Password

Alibaba Cloud and Tencent Cloud templates set the default root password to PigstyDemo4; Linode uses PigstyDemo4! to satisfy its password-complexity rules. Current AWS, Azure, GCP, Hetzner, Vultr, and DigitalOcean templates primarily use SSH public-key authentication and do not share a default root password. Example passwords are for temporary tests only; change them or disable password login in production.

Security Group Configuration

These templates target demonstration and development. Their current security groups or cloud firewalls allow all or nearly all inbound traffic from 0.0.0.0/0 (some also include ::/0), not just the ports Pigsty requires. Restrict source networks and ports before deployment; do not use these defaults unchanged in production.

SSH Access

After creation, SSH login to the admin node using:

ssh root@<public_ip>

Alibaba Cloud templates that retain the legacy output and password conventions can also use ./ssh or make ssh to write SSH aliases. For other templates, use their ssh_command output.

2.8 - Security Considerations

Credential, network, authentication, encryption, data protection, and audit checks for production Pigsty deployments.

Pigsty defaults target development, testing, and demonstrations on a trusted intranet. A production deployment must configure credentials, network boundaries, authentication, certificates, backup, and audit according to its threat model.

See Security and Compliance for mechanisms and boundaries, and the Launch Hardening Checklist for executable checks. ha/safe is a hardening example, not a substitute for reviewing each control.


Confidentiality

Critical Files

Protect these assets:

  • pigsty.yml and other inventories, which normally contain system and application credentials;
  • files/pki/ca/ca.key, which can issue certificates trusted by the deployment;
  • the administration user’s SSH private key, which can use sudo on managed nodes by default;
  • client-certificate private keys and backup-encryption keys;
  • generated /pg/tmp/pg-user-*.sql files.

Restrict access to the admin node and configuration repository. Do not commit complete inventories or private keys to public repositories. Back up the CA private key and recovery configuration through controlled channels.

Passwords

Replace every public default credential before production. Start with:

./configure -g

This option does not replace the pgBackRest cipher_pass, every Silo example credential in ha/safe, or user-defined values. Review the result against the Default Credentials Checklist.

PostgreSQL stores newly set or updated passwords with SCRAM-SHA-256 by default. To enforce complexity, preload passwordcheck through pg_libs, or configure credcheck. Declare account lifetime with expire_in or expire_at.

Credential rotation must also update database users, the PgBouncer user list, component configuration, and client connection information. Prepare a rollback plan before rotating.


Network Boundaries

IP Addresses

PostgreSQL listens on 0.0.0.0 by default. To constrain listen addresses, set:

pg_listen: '${ip},${vip},${lo}'

A listen address is not the only boundary. Production reviews should also cover:

The demo pigsty.yml inventory also exposes 5432 publicly. Remove that exception in production. If direct database access is required, limit it to explicit application CIDRs.

Network Traffic

  • PostgreSQL enables server-side TLS by default, but default intranet HBA rules do not require it.
  • PgBouncer TLS is disabled by default and controlled by pgbouncer_sslmode.
  • HTTPS for the Patroni REST API is disabled by default and controlled by patroni_ssl_enabled.
  • Nginx and the object-storage backend selected by the MINIO module enable HTTPS by default; etcd uses TLS for client and peer traffic.

HBA auth: ssl requires an encrypted connection only. Clients should also use sslmode=verify-full with a trusted CA to verify the database server; see Encrypted Communication.

Grafana, VictoriaMetrics, and other components may listen on node ports, but the default firewall does not expose them directly to public networks. Prefer Nginx for external access, and restrict management pages by source address and identity.


Authentication and Access Control

  • Use HBA to define the user, database, source address, and authentication method. Avoid broad world rules.
  • Use auth: cert for privileged remote users, with a process for delivering and revoking client certificates.
  • Assign application privileges through built-in roles; do not grant superuser to ordinary application accounts.
  • Set revokeconn: true for multi-tenant shared clusters, and inspect effective database ACLs.
  • Create objects through the declared database owner or a controlled administration role so default privileges apply.
  • To isolate offline queries, set role: offline explicitly on the HBA rule for dbrole_offline.

After changing HBA, users, or roles, compare both the inventory and the effective database state.


Integrity

Pigsty enables page checksums by default to detect page damage after write. Checksums do not detect every memory error, logical error, or incorrect application write.

The CRIT template enables Patroni strict synchronous mode and more detailed connection logging. The synchronous mode targets preservation of acknowledged transactions, but depends on synchronous_commit, synchronous-replica state, and failover conditions. Writes block when no synchronous replica is available.

CRIT configures watchdog as automatic; it activates only when the system has a usable watchdog device. Decide whether required is appropriate according to hardware and availability requirements.


Availability

  • Critical clusters should normally have at least three instances across independent failure domains.
  • Connect through HAProxy, a VIP, or DNS service name instead of binding clients to a fixed primary address.
  • Use an odd number of etcd nodes across independent failure domains.
  • Remove single points of failure in INFRA, DNS, monitoring, and software repositories according to availability requirements.
  • When using pg_rpo and pg_rto, understand their configuration semantics and validate objectives through exercises.

Replicas handle only some node failures; they do not replace backups.


Backup and Recovery

  • The local pgBackRest repository is not encrypted by default and shares a failure domain with the database host.
  • The pgbackrest_method: minio object-storage repository uses AES-256-CBC by default, but cipher_pass: pgBackRest is public and must be replaced.
  • pgBR.${pg_cluster} in ha/safe is also an example and must not be used as the final key.
  • Store important backups in an independent failure domain, and evaluate object locking, versioning, or offline copies.
  • Exercise full restore and PITR regularly to validate WAL, keys, recovery time, and application consistency.

See Data Security and Backup and Recovery for details.


Audit and Response

The default OLTP template logs DDL, slow queries, and PostgreSQL 18 connection-authorization events. CRIT also logs connection and disconnection events.

pgaudit must be installed, preloaded, and configured with an audit policy. Installing the package alone does not produce SQL audit logs. When Vector and VictoriaLogs are enabled, adjust log retention, access, and archive policy to requirements.

Metrics, logs, and alerts are incident inputs only. Production also needs alert classification, on-call ownership, incident determination, response, evidence collection, and post-incident review.


Host and Software Supply Chain

  • Move SELinux from the default permissive to enforcing after compatibility validation.
  • Disable unnecessary SSH password authentication and remote root login; consider a bastion host or multi-factor authentication.
  • Review sudo scope for the administration and database OS users.
  • Keep supported Pigsty and upstream component versions current.
  • Verify the software-repository GPG key fingerprint and enable per-package signature verification where required.

See Compliance: Supply Chain and Vulnerability Response.

3 - Concepts

Understand Pigsty’s core concepts, architecture design, learn how high availability, backup recovery, iac, security works

Pigsty is a portable, extensible open-source PostgreSQL distribution for building production-grade database services in local environments with declarative configuration and automation. It has a vast ecosystem providing a complete set of tools, scripts, and best practices to bring PostgreSQL to enterprise-grade RDS service levels.

Pigsty’s name comes from PostgreSQL In Great STYle, also understood as Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours—a self-hosted PostgreSQL solution with graphical monitoring that’s all yours. You can find the source code on GitHub, visit the official documentation for more information, or experience the Web UI in the online demo.

pigsty-banner


Why Pigsty? What Can It Do?

PostgreSQL is a sufficiently perfect database kernel, but it needs more tools and systems to become a truly excellent database service. In production environments, you need to manage every aspect of your database: high availability, backup recovery, monitoring alerts, access control, parameter tuning, extension installation, connection pooling, load balancing…

Wouldn’t it be easier if all this complex operational work could be automated? This is precisely why Pigsty was created.

Pigsty provides:

  • Out-of-the-Box PostgreSQL Distribution

    Pigsty deeply integrates 576 extensions from the PostgreSQL ecosystem, providing out-of-the-box distributed, time-series, geographic, spatial, graph, vector, search, and other multi-modal database capabilities. From kernel to RDS distribution, providing production-grade database services for versions 14-18 on EL/Debian/Ubuntu.

  • Self-Healing High Availability Architecture

    A high availability architecture built on Patroni, Etcd, and HAProxy enables automatic failover for hardware failures with seamless traffic handoff. Primary failure recovery time RTO < 45s, data recovery point RPO ≈ 0. You can perform rolling maintenance and upgrades on the entire cluster without application coordination.

  • Complete Point-in-Time Recovery Capability

    Based on pgBackRest and an optional Silo object-storage cluster, providing out-of-the-box PITR point-in-time recovery capability. Giving you the ability to quickly return to any point in time, protecting against software defects and accidental data deletion.

  • Flexible Service Access and Traffic Management

    Through HAProxy, Pgbouncer, and VIP, providing flexible service access patterns for read-write separation, connection pooling, and automatic routing. Delivering stable, reliable, auto-routing, transaction-pooled high-performance database services.

  • Stunning Observability

    An observability stack based on VictoriaMetrics and Grafana provides unparalleled monitoring best practices. Over three thousand types of monitoring metrics describe every aspect of the system, from global dashboards to CRUD operations on individual objects.

  • Declarative Configuration Management

    Following the Infrastructure as Code philosophy, using declarative configuration to describe the entire environment. You just tell Pigsty “what kind of database cluster you want” without worrying about how to implement it—the system automatically adjusts to the desired state.

  • Modular Architecture Design

    A modular architecture design that can be freely combined to suit different scenarios. Beyond the core PostgreSQL module, it also provides optional modules for Redis, MINIO (Silo), Etcd, and support for various PG-compatible kernels and modes.

  • Solid Security Best Practices

    Industry-leading security practices: a self-signed CA for encrypted communication, AES-encrypted backups, SCRAM-SHA-256 password hashing, an out-of-the-box ACL model, and least-privilege HBA rules.

  • Simple and Easy Deployment

    All dependencies are pre-packaged for one-click installation in environments without internet access. Local sandbox environments can run on micro VMs with 1 core and 2GB RAM, providing functionality identical to production environments. Provides Vagrant-based local sandboxes and Terraform-based cloud deployments.


What Pigsty Is Not

Pigsty is not a traditional, all-encompassing PaaS (Platform as a Service) system.

  • Pigsty doesn’t provide basic hardware resources. It runs on nodes you provide, whether bare metal, VMs, or cloud instances, but it doesn’t create or manage these resources itself (though it provides Terraform templates to simplify cloud resource preparation).

  • Pigsty is not a container orchestration system. It runs directly on the operating system, not requiring Kubernetes or Docker as infrastructure. Of course, it can coexist with these systems and provides a Docker module for running stateless applications.

  • Pigsty is not a general database management tool. It focuses on PostgreSQL and its ecosystem. While it also supports peripheral components like Redis, Etcd, and Silo, the core is always built around PostgreSQL.

  • Pigsty won’t lock you in. It’s built on open-source components, doesn’t modify the PostgreSQL kernel, and introduces no proprietary protocols. You can continue using your well-managed PostgreSQL clusters anytime without Pigsty.

Pigsty doesn’t restrict how you should or shouldn’t build your database services. For example:

  • Pigsty provides good parameter defaults and configuration templates, but you can override any parameter.
  • Pigsty provides a declarative API, but you can still use underlying tools (Ansible, Patroni, pgBackRest, etc.) for manual management.
  • Pigsty can manage the complete lifecycle, or you can use only its monitoring system to observe existing database instances or RDS.

Pigsty provides a different level of abstraction than the hardware layer—it works at the database service layer, focusing on how to deliver PostgreSQL at its best, rather than reinventing the wheel.


Evolution of PostgreSQL Deployment

To understand Pigsty’s value, let’s review the evolution of PostgreSQL deployment approaches.

Manual Deployment Era

In traditional deployment, DBAs needed to manually install and configure PostgreSQL, manually set up replication, manually configure monitoring, and manually handle failures. The problems with this approach are obvious:

  • Low efficiency: Each instance requires repeating many manual operations, prone to errors.
  • Lack of standardization: Databases configured by different DBAs can vary greatly, making maintenance difficult.
  • Poor reliability: Failure handling depends on manual intervention, with long recovery times and susceptibility to human error.
  • Weak observability: Lack of unified monitoring, making problem discovery and diagnosis difficult.

Managed Database Era

To solve these problems, cloud providers offer managed database services (RDS). Cloud RDS does solve some operational issues, but also brings new challenges:

  • High cost: Managed services typically charge multiples to dozens of times hardware cost as “service fees.”
  • Vendor lock-in: Migration is difficult, tied to specific cloud platforms.
  • Limited functionality: Cannot use certain advanced features, extensions are restricted, parameter tuning is limited.
  • Data sovereignty: Data stored in the cloud, reducing autonomy and control.

Local RDS Era

Pigsty represents a third approach: building database services in local environments that match or exceed cloud RDS.

Pigsty combines the advantages of both approaches:

  • High automation: One-click deployment, automatic configuration, self-healing failures—as convenient as cloud RDS.
  • Complete autonomy: Runs on your own infrastructure, data completely in your own hands.
  • Extremely low cost: Run enterprise-grade database services at near-pure-hardware costs.
  • Complete functionality: Unlimited use of PostgreSQL’s full capabilities and ecosystem extensions.
  • Open architecture: Based on open-source components, no vendor lock-in, free to migrate anytime.

This approach is particularly suitable for:

  • Private and hybrid clouds: Enterprises needing to run databases in local environments.
  • Cost-sensitive users: Organizations looking to reduce database TCO.
  • High-security scenarios: Critical data requiring complete autonomy and control.
  • PostgreSQL power users: Scenarios requiring advanced features and rich extensions.
  • Development and testing: Quickly setting up databases locally that match production environments.

What’s Next

Now that you understand Pigsty’s basic concepts, you can:

3.1 - Architecture

Pigsty’s modular architecture—declarative composition, on-demand customization, flexible deployment.

Pigsty uses a modular architecture with a declarative interface. You can freely combine modules like building blocks as needed.


Modules

Pigsty uses a modular design with six main default modules: PGSQL, INFRA, NODE, ETCD, REDIS, and MINIO.

  • PGSQL: Self-healing HA Postgres clusters powered by Patroni, Pgbouncer, HAproxy, PgBackrest, and more.
  • INFRA: Local software repo, Nginx, Grafana, Victoria, AlertManager, Blackbox Exporter—the complete observability stack.
  • NODE: Tune nodes to desired state—hostname, timezone, NTP, ssh, sudo, haproxy, docker, vector, keepalived.
  • ETCD: Distributed key-value store as DCS for HA Postgres clusters: consensus leader election/config management/service discovery.
  • REDIS: Redis servers supporting standalone primary-replica, sentinel, and cluster modes with full monitoring.
  • MINIO: S3-compatible simple object storage that can serve as an optional backup destination for PG databases.

You can declaratively compose them freely. If you only want host monitoring, installing the INFRA module on infrastructure nodes and the NODE module on managed nodes is sufficient. The ETCD and PGSQL modules are used to build HA PG clusters—installing these modules on multiple nodes automatically forms a high-availability database cluster. You can reuse Pigsty infrastructure and develop your own modules; REDIS and MINIO can serve as examples. Protocol compatibility layers such as PostgreSQL Mongo mode are composed from standard PGSQL and Docker APP workflows.

Note that all modules depend strongly on the NODE module: in Pigsty, nodes must first have the NODE module installed to be managed before deploying other modules. When nodes (by default) use the local software repo for installation, the NODE module has a weak dependency on the INFRA module. Therefore, the admin/infrastructure nodes with the INFRA module complete the bootstrap process in the deploy.yml playbook, resolving the circular dependency.

pigsty-sandbox


Standalone Installation

By default, Pigsty installs on a single node (physical/virtual machine). The deploy.yml playbook installs INFRA, ETCD, PGSQL, and optionally MINIO modules on the current node, giving you a fully-featured observability stack (VictoriaMetrics, VictoriaLogs, VictoriaTraces, Grafana, Alertmanager, Blackbox Exporter, etc.), plus a built-in PostgreSQL standalone instance as a CMDB, ready to use out of the box (cluster name pg-meta, database name meta).

This node now has a complete self-monitoring system, visualization tools, and a Postgres database with PITR auto-configured (HA unavailable since you only have one node). You can use this node as a devbox, for testing, running demos, and data visualization/analysis. Or, use this node as an admin node to deploy and manage more nodes!

pigsty-arch


Monitoring

The installed standalone meta node can serve as an admin node and monitoring center to bring more nodes and database servers under its supervision and control.

Pigsty’s monitoring system can be used independently. If you want to install the VictoriaMetrics/Grafana observability stack, Pigsty provides best practices! It offers rich dashboards for host nodes and PostgreSQL databases. Whether or not these nodes or PostgreSQL servers are managed by Pigsty, with simple configuration, you immediately have a production-grade monitoring and alerting system, bringing existing hosts and PostgreSQL under management.

pigsty-dashboard.jpg


HA PostgreSQL Clusters

Pigsty helps you own your own production-grade HA PostgreSQL RDS service anywhere.

To create such an HA PostgreSQL cluster/RDS service, you simply describe it with a short config and run the playbook to create it:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: replica }
  vars: { pg_cluster: pg-test }
$ bin/pgsql-add pg-test  # Initialize cluster 'pg-test'

In less than 10 minutes, you’ll have a PostgreSQL database cluster with service access, monitoring, backup PITR, and HA fully configured.

pigsty-ha.png

Hardware failures are covered by the self-healing HA architecture provided by patroni, etcd, and haproxy—in case of primary failure, automatic failover executes within 45 seconds by default. Clients don’t need to modify config or restart applications: Haproxy uses patroni health checks for traffic distribution, and read-write requests are automatically routed to the new cluster primary, avoiding split-brain issues. This process is seamless—for example, in case of replica failure or planned switchover, clients experience only a momentary flash of the current query.

Software failures, human errors, and datacenter-level disasters are covered by pgBackRest and the optional Silo cluster. This provides local/cloud PITR capabilities and, in case of datacenter failure, offers cross-region replication and disaster recovery.

3.1.1 - Nodes

A node is an abstraction of hardware/OS resources—physical machines, bare metal, VMs, or containers/pods.

A node is an abstraction of hardware resources and operating systems. It can be a physical machine, bare metal, virtual machine, or container/pod.

Any machine running a Linux OS (with systemd daemon) and standard CPU/memory/disk/network resources can be treated as a node.

Nodes can have modules installed. Pigsty has several node types, distinguished by which modules are deployed:

TypeDescription
Regular NodeA node managed by Pigsty
ADMIN NodeThe node that runs Ansible to issue management commands
INFRA NodeNodes with the INFRA module installed
ETCD NodeNodes with the ETCD module for DCS
MINIO NodeNodes with the MINIO module for object storage
PGSQL NodeNodes with the PGSQL module installed
Nodes with other modules…

In a singleton Pigsty deployment, multiple roles converge on one node: it serves as the regular node, admin node, infra node, ETCD node, and database node simultaneously.


Regular Node

Nodes managed by Pigsty can have modules installed. The node.yml playbook configures nodes to the desired state. A regular node may run the following services:

ComponentPortDescriptionStatus
node_exporter9100Host metrics exporterEnabled
haproxy9101HAProxy load balancer (admin port)Enabled
vector9598Log collection agentEnabled
docker9323Container runtime supportOptional
keepalivedn/aL2 VIP for node clusterOptional
keepalived_exporter9650Keepalived status monitorOptional

Here, node_exporter exposes host metrics, vector sends logs to the collection system, and haproxy provides load balancing. These three are enabled by default. Docker, keepalived, and keepalived_exporter are optional and can be enabled as needed.


ADMIN Node

A Pigsty deployment has exactly one admin node—the node that runs Ansible playbooks and issues control/deployment commands.

This node has ssh/sudo access to all other nodes. Admin node security is critical and access must be strictly controlled; see Security Model: Trust Boundaries for its trust scope and critical assets.

During single-node installation and configuration, the current node becomes the admin node. However, alternatives exist. For example, if your laptop can SSH to all managed nodes and has Ansible installed, it can serve as the admin node—though this isn’t recommended for production.

For instance, you might use your laptop to manage a Pigsty VM in the cloud. In this case, your laptop is the admin node.

In serious production environments, the admin node is typically 1-2 dedicated DBA machines. In resource-constrained setups, INFRA nodes often double as admin nodes since all INFRA nodes have Ansible installed by default.


INFRA Node

A Pigsty deployment may have 1 or more INFRA nodes; large production environments typically have 2-3.

The infra group in the inventory defines which nodes are INFRA nodes. These nodes run the INFRA module with these components:

ComponentPortDescription
nginx80/443Web UI, local software repository
grafana3000Visualization platform
victoriaMetrics8428Time-series database (metrics)
victoriaLogs9428Log collection server
victoriaTraces10428Trace collection server
vmalert8880Alerting and derived metrics
alertmanager9059Alert aggregation and routing
blackbox_exporter9115Blackbox probing (ping nodes/VIPs)
dnsmasq53Internal DNS resolution
chronyd123NTP time server
ansible-Playbook execution

Nginx serves as the module’s entry point, providing the web UI and local software repository. With multiple INFRA nodes, services on each are independent, but you can access all monitoring data sources from any INFRA node’s Grafana.

Pigsty is licensed under Apache-2.0, though embedded Grafana component uses AGPLv3.


ETCD Node

The ETCD module provides Distributed Consensus Service (DCS) for PostgreSQL high availability.

The etcd group in the inventory defines ETCD nodes. These nodes run etcd servers on two ports:

ComponentPortDescription
etcd2379ETCD key-value store (client port)
etcd2380ETCD cluster peer communication

MINIO Node

The MINIO module provides optional backup storage for PostgreSQL.

The minio inventory group defines MINIO module nodes. In v4.5.0, these nodes run Silo servers on:

ComponentPortDescription
silo9000S3 API endpoint
silo9001Silo admin console

PGSQL Node

Nodes with the PGSQL module are called PGSQL nodes. Node and PostgreSQL instance have a 1:1 deployment—one PG instance per node.

PGSQL nodes can borrow identity from their PostgreSQL instance—controlled by node_id_from_pg, defaulting to true, meaning the node name is set to the PG instance name.

PGSQL nodes run these additional components beyond regular node services:

ComponentPortDescriptionStatus
postgres5432PostgreSQL database serverEnabled
pgbouncer6432PgBouncer connection poolEnabled
patroni8008Patroni HA managementEnabled
pg_exporter9630PostgreSQL metrics exporterEnabled
pgbouncer_exporter9631PgBouncer metrics exporterEnabled
pgbackrest_exporter9854pgBackRest metrics exporterEnabled
vip-managern/aBinds L2 VIP to cluster primaryOptional
{{ pg_cluster }}-primary5433HAProxy service: pooled read/writeEnabled
{{ pg_cluster }}-replica5434HAProxy service: pooled read-onlyEnabled
{{ pg_cluster }}-default5436HAProxy service: primary direct connectionEnabled
{{ pg_cluster }}-offline5438HAProxy service: offline readEnabled
{{ pg_cluster }}-<service>543xHAProxy service: custom PostgreSQL servicesCustom

The vip-manager is only enabled when users configure a PG VIP. Additional custom services can be defined in pg_services, exposed via haproxy using additional service ports.


Node Relationships

Regular nodes typically reference an INFRA node via the admin_ip parameter as their infrastructure provider. For example, with global admin_ip = 10.10.10.10, all nodes use infrastructure services at this IP.

Parameters that reference ${admin_ip}:

ParameterModuleDefault ValueDescription
repo_endpointINFRAhttp://${admin_ip}:80Software repo URL
repo_upstream.baseurlINFRAhttp://${admin_ip}/pigstyLocal repo baseurl
infra_portal.endpointINFRA${admin_ip}:<port>Nginx proxy backend
dns_recordsINFRA["${admin_ip} i.pigsty", ...]DNS records
node_default_etc_hostsNODE["${admin_ip} i.pigsty"]Default static DNS
node_etc_hostsNODE-Custom static DNS
node_dns_serversNODE["${admin_ip}"]Dynamic DNS servers
node_ntp_serversNODE-NTP servers (optional)

Typically the admin node and INFRA node coincide. With multiple INFRA nodes, the admin node is usually the first one; others serve as backups.

In large-scale production deployments, you might separate the Ansible admin node from INFRA module nodes. For example, use 1-2 small dedicated hosts under the DBA team as the control hub (ADMIN nodes), and 2-3 high-spec physical machines as monitoring infrastructure (INFRA nodes).

Typical node counts by deployment scale:

ScaleADMININFRAETCDMINIOPGSQL
Single-node11101
3-node13303
Small prod1230N
Large prod2354+N

3.1.2 - Infrastructure

Infrastructure module architecture, components, and functionality in Pigsty.

Running production-grade, highly available PostgreSQL clusters typically requires a comprehensive set of infrastructure services (foundation) for support, such as monitoring and alerting, log collection, time synchronization, DNS resolution, and local software repositories. Pigsty provides the INFRA module to address this—it’s an optional module, but we strongly recommend enabling it.


Overview

The diagram below shows the architecture of a single-node deployment. The right half represents the components included in the INFRA module:

ComponentTypeDescription
NginxWeb ServerUnified entry for WebUI, local repo, reverse proxy for internal services
RepoSoftware RepoAPT/DNF repository with all RPM/DEB packages needed for deployment
GrafanaVisualizationDisplays metrics, logs, and traces; hosts dashboards, reports, and custom data apps
VictoriaMetricsTime Series DBScrapes all metrics, Prometheus API compatible, provides VMUI query interface
VictoriaLogsLog PlatformCentralized log storage; all nodes run Vector by default, pushing logs here
VictoriaTracesTracingCollects slow SQL, service traces, and other tracing data
VMAlertEval Rule/AlertEvaluates alerting rules, pushes events to Alertmanager
AlertManagerAlert ManagerAggregates alerts, dispatches notifications via email, Webhook, etc.
BlackboxExporterBlackbox ProbeProbes reachability of IPs/VIPs/URLs
DNSMASQDNS ServiceProvides DNS resolution for domains used within Pigsty [Optional]
ChronydTime SyncProvides NTP time synchronization to ensure consistent time across nodes [Optional]
CACertificateIssues encryption certificates within the environment
AnsibleOrchestrationBatch, declarative, agentless tool for managing large numbers of servers

pigsty-arch


Nginx

Nginx is the access entry point for all WebUI services in Pigsty, using ports 80 / 443 for HTTP/HTTPS by default. Live Demo

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10http://i.pigstyhttps://i.pigstyhttps://demo.pigsty.io

Infrastructure components with WebUIs can be exposed uniformly through Nginx, such as Grafana, VictoriaMetrics (VMUI), AlertManager, and HAProxy console. Additionally, the local software repository and other static resources are served via Nginx.

Nginx configures local web servers or reverse proxy servers based on definitions in infra_portal.

infra_portal:
  home : { domain: i.pigsty }

By default, it exposes Pigsty’s admin homepage: i.pigsty. Different endpoints on this page proxy different components:

EndpointComponentNative PortNotesPublic Demo
/Nginx80/443Homepage, local repo, file serverdemo.pigsty.io
/ui/Grafana3000Grafana dashboard entrydemo.pigsty.io/ui/
/vmetrics/VictoriaMetrics8428Time series DB Web UIdemo.pigsty.io/vmetrics/
/vlogs/VictoriaLogs9428Log DB Web UIdemo.pigsty.io/vlogs/
/vtraces/VictoriaTraces10428Tracing Web UIdemo.pigsty.io/vtraces/
/vmalert/VMAlert8880Alert rule managementdemo.pigsty.io/vmalert/
/alertmgr/AlertManager9059Alert management Web UIdemo.pigsty.io/alertmgr/
/blackbox/Blackbox9115Blackbox probe

Pigsty online demo homepage

Pigsty allows rich customization of Nginx as a local file server or reverse proxy, with self-signed or real HTTPS certificates.

For more information, see: Tutorial: Nginx—Expose Web Services via Proxy and Tutorial: Certbot—Request and Renew HTTPS Certificates


Repo

Pigsty creates a local software repository on the Infra node during installation to accelerate subsequent software installations. Live Demo

This repository defaults to the /www/pigsty directory, served by Nginx and mounted at the /pigsty path:

Pigsty supports offline installation, which essentially pre-copies a prepared local software repository to the target environment. When Pigsty finds /www/pigsty/repo_complete during deployment, it skips upstream downloads and uses the existing repository directly. The current source has sow generate this file as both a completion marker and a SHA-256 manifest of repository contents. To force a rebuild, run ./infra.yml -t repo_build -e repo_build=true.

repo

For more information, see: Config: INFRA - REPO


Grafana

Grafana is the core component of Pigsty’s monitoring system, used for visualizing metrics, logs, and various information. Live Demo

Grafana listens on port 3000 by default and is proxied via Nginx at the /ui path:

IP Access (replace)Domain (HTTP)Domain (HTTPS)Public Demo
http://10.10.10.10/uihttp://i.pigsty/uihttps://i.pigsty/uihttps://demo.pigsty.io/ui

Pigsty provides pre-built dashboards based on VictoriaMetrics / Logs / Traces, with one-click drill-down and roll-up via URL jumps for rapid troubleshooting.

Grafana can also serve as a low-code visualization platform, so ECharts, victoriametrics-datasource, victorialogs-datasource plugins are installed by default, with Vector / Victoria datasources registered uniformly as vmetrics-*, vlogs-*, vtraces-* for easy custom dashboard extension.

dashboard

For more information, see: Config: INFRA - GRAFANA.


VictoriaMetrics

VictoriaMetrics is Pigsty’s time series database, responsible for scraping and storing all monitoring metrics. Live Demo

It listens on port 8428 by default, mounted at Nginx /vmetrics path, and also accessible via the p.pigsty domain:

VictoriaMetrics is fully compatible with the Prometheus API, supporting PromQL queries, remote read/write protocols, and the Alertmanager API. The built-in VMUI provides an ad-hoc query interface for exploring metrics data directly, and also serves as a Grafana datasource.

vmetrics

For more information, see: Config: INFRA - VMETRICS


VictoriaLogs

VictoriaLogs is Pigsty’s log platform, centrally storing structured logs from all nodes. Live Demo

It listens on port 9428 by default, mounted at Nginx /vlogs path:

All managed nodes run Vector Agent by default, collecting system logs, PostgreSQL logs, Patroni logs, Pgbouncer logs, etc., processing them into structured format and pushing to VictoriaLogs. The built-in Web UI supports log search and filtering, and can be integrated with Grafana’s victorialogs-datasource plugin for visual analysis.

vlogs

For more information, see: Config: INFRA - VLOGS


VictoriaTraces

VictoriaTraces is used for collecting trace data and slow SQL records. Live Demo

It listens on port 10428 by default, mounted at Nginx /vtraces path:

VictoriaTraces provides a Jaeger-compatible interface for analyzing service call chains and database slow queries. Combined with Grafana dashboards, it enables rapid identification of performance bottlenecks and root cause tracing.

For more information, see: Config: INFRA - VTRACES


VMAlert

VMAlert is the alerting rule computation engine, responsible for evaluating alert rules and pushing triggered events to Alertmanager. Live Demo

It listens on port 8880 by default, mounted at Nginx /vmalert path:

VMAlert reads metrics data from VictoriaMetrics and periodically evaluates alerting rules. Pigsty provides pre-built alerting rules for PGSQL, NODE, REDIS, and other modules, covering common failure scenarios out of the box.

vmalert

For more information, see: Config: INFRA - VMALERT


AlertManager

AlertManager handles alert event aggregation, deduplication, grouping, and dispatch. Live Demo

It listens on port 9059 by default, mounted at Nginx /alertmgr path, and also accessible via the a.pigsty domain:

AlertManager supports multiple notification channels: email, Webhook, Slack, PagerDuty, WeChat Work, etc. Through alert routing rules, differentiated dispatch based on severity level and module type is possible, with support for silencing, inhibition, and other advanced features.

alertmanager

For more information, see: Config: INFRA - AlertManager


BlackboxExporter

Blackbox Exporter is used for active probing of target reachability, enabling blackbox monitoring.

It listens on port 9115 by default, mounted at Nginx /blackbox path:

It supports multiple probe methods including ICMP Ping, TCP ports, and HTTP/HTTPS endpoints. Useful for monitoring VIP reachability, service port availability, external dependency health, etc.—an important tool for assessing failure impact scope.

blackbox

For more information, see: Config: INFRA - BLACKBOX


Ansible

Ansible is Pigsty’s core orchestration tool; all deployment, configuration, and management operations are performed through Ansible Playbooks.

Pigsty automatically installs Ansible on the admin node (Infra node) during installation. It adopts a declarative configuration style and idempotent playbook design: the same playbook can be run repeatedly, and the system automatically converges to the desired state without side effects.

Ansible’s core advantages:

  • Agentless: Executes remotely via SSH, no additional software needed on target nodes.
  • Declarative: Describes the desired state rather than execution steps; configuration is documentation.
  • Idempotent: Multiple executions produce consistent results; supports retry after partial failures.

For more information, see: Playbooks: Pigsty Playbook


DNSMASQ

DNSMASQ provides DNS resolution on INFRA nodes, resolving domain names to their corresponding IP addresses.

DNSMASQ listens on port 53 (UDP/TCP) by default, providing DNS resolution for all nodes. Records are stored in the /etc/dnsmasq.d/pigsty directory.

Other modules automatically register their domain names with DNSMASQ during deployment, which you can use as needed. DNS is completely optional—Pigsty works normally without it. Client nodes can configure INFRA nodes as their DNS servers, allowing access to services via domain names without remembering IP addresses.

For more information, see: Config: INFRA - DNS and Tutorial: DNS—Configure Domain Resolution


Chronyd

Chronyd provides NTP time synchronization, ensuring consistent clocks across all nodes. It listens on port 123 (UDP) by default as the time source.

Time synchronization is critical for distributed systems: log analysis requires aligned timestamps, certificate validation depends on accurate clocks, and PostgreSQL streaming replication is sensitive to clock drift. In isolated network environments, the INFRA node can serve as an internal NTP server with other nodes synchronizing to it.

In Pigsty, all nodes run chronyd by default for time sync. The default upstream is pool.ntp.org public NTP servers. Chronyd is essentially managed by the Node module, but in isolated networks, you can use admin_ip to point to the INFRA node’s Chronyd service as the internal time source. In this case, the Chronyd service on the INFRA node serves as the internal time synchronization infrastructure.

For more information, see: Config: NODE - TIME


INFRA Node vs Regular Node

In Pigsty, the relationship between nodes and infrastructure is a weak circular dependency: node_monitor → infra → node

The NODE module itself doesn’t depend on the INFRA module, but the monitoring functionality (node_monitor) requires the monitoring platform and services provided by the infrastructure module.

Therefore, in the infra.yml and deploy playbooks, an “interleaved deployment” technique is used:

  • First, initialize the NODE module on all regular nodes, but skip monitoring config since infrastructure isn’t deployed yet.
  • Then, initialize the INFRA module on the INFRA node—monitoring is now available.
  • Finally, reconfigure monitoring on all regular nodes, connecting to the now-deployed monitoring platform.

If you don’t need “one-shot” deployment of all nodes, you can use phased deployment: initialize INFRA nodes first, then regular nodes.

How Are Nodes Coupled to Infrastructure?

Regular nodes reference an INFRA node via the admin_ip parameter as their infrastructure provider.

For example, when you configure global admin_ip = 10.10.10.10, all nodes will typically use infrastructure services at this IP.

This design allows quick, batch switching of infrastructure providers. Parameters that may reference ${admin_ip}:

ParameterModuleDefault ValueDescription
repo_endpointINFRAhttp://${admin_ip}:80Software repo URL
repo_upstream.baseurlINFRAhttp://${admin_ip}/pigstyLocal repo baseurl
infra_portal.endpointINFRA${admin_ip}:<port>Nginx proxy backend
dns_recordsINFRA["${admin_ip} i.pigsty", ...]DNS records
node_default_etc_hostsNODE["${admin_ip} i.pigsty"]Default static DNS
node_etc_hostsNODE[]Custom static DNS
node_dns_serversNODE["${admin_ip}"]Dynamic DNS servers
node_ntp_serversNODE["pool pool.ntp.org iburst"]NTP servers (optional)

For example, when a node installs software, the local repo points to the Nginx local software repository at admin_ip:80/pigsty. The DNS server also points to DNSMASQ at admin_ip:53. However, this isn’t mandatory—nodes can ignore the local repo and install directly from upstream internet sources (most single-node config templates); DNS servers can also remain unconfigured, as Pigsty has no DNS dependency.


INFRA Node vs ADMIN Node

The management-initiating ADMIN node typically coincides with the INFRA node. In single-node deployment, this is exactly the case. In multi-node deployment with multiple INFRA nodes, the admin node is usually the first in the infra group; others serve as backups. However, exceptions exist. You might separate them for various reasons:

For example, in large-scale production deployments, a classic pattern uses 1-2 dedicated management hosts (tiny VMs suffice) belonging to the DBA team as the control hub, with 2-3 high-spec physical machines (or more!) as monitoring infrastructure. Here, admin nodes are separate from infrastructure nodes. In this case, the admin_ip in your config should point to an INFRA node’s IP, not the current ADMIN node’s IP. This is for historical reasons: initially ADMIN and INFRA nodes were tightly coupled concepts, with separation capabilities evolving later, so the parameter name wasn’t changed.

Another common scenario is managing cloud nodes locally. For example, you can install Ansible on your laptop and specify cloud nodes as “managed targets.” In this case, your laptop acts as the ADMIN node, while cloud servers act as INFRA nodes.

all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 , ansible_host: your_ssh_alias } } }  # <--- Use ansible_host to point to cloud node (fill in ssh alias)
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }    # SSH connection will use: ssh your_ssh_alias
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }
  vars:
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default

Multiple INFRA Nodes

By default, Pigsty only needs one INFRA node for most requirements. Even if the INFRA module goes down, it won’t affect database services on other nodes.

However, in production environments with high monitoring and alerting requirements, you may want multiple INFRA nodes to improve infrastructure availability. A common deployment uses two Infra nodes for redundancy, monitoring each other… or more nodes to deploy a distributed Victoria cluster for unlimited horizontal scaling.

Each Infra node is independent—Nginx points to services on the local machine. VictoriaMetrics independently scrapes metrics from all services in the environment, and logs are pushed to all VictoriaLogs collection endpoints by default. The only exception is Grafana: every Grafana instance registers all VictoriaMetrics / Logs / Traces / PostgreSQL instances as datasources. Therefore, each Grafana instance can see complete monitoring data.

If you modify Grafana—such as adding new dashboards or changing datasource configs—these changes only affect the Grafana instance on that node. To keep Grafana consistent across all nodes, use a PostgreSQL database as shared storage. See Tutorial: Configure Grafana High Availability for details.

INFRA overview dashboard

3.1.3 - PGSQL Arch

PostgreSQL module component interactions and data flow.

The PGSQL module organizes PostgreSQL in production as clusterslogical entities composed of a group of database instances associated by primary-replica relationships.


Overview

The PGSQL module includes the following components, working together to provide production-grade PostgreSQL HA cluster services:

ComponentTypeDescription
postgresDatabaseThe world’s most advanced open-source relational database, PGSQL core
patroniHAManages PostgreSQL, coordinates failover, leader election, config changes
pgbouncerPoolLightweight connection pooling middleware, reduces overhead, adds flexibility
pgbackrestBackupFull/incremental backup and WAL archiving, supports local and object storage
pg_exporterMetricsExports PostgreSQL monitoring metrics in a Prometheus-compatible format
pgbouncer_exporterMetricsExports Pgbouncer connection pool metrics
pgbackrest_exporterMetricsExports backup status metrics
vip-managerVIPBinds L2 VIP to current primary node for transparent failover [Optional]

The vip-manager is an on-demand component. Additionally, PGSQL uses components from other modules:

ComponentModuleTypeDescription
haproxyNODELBExposes service ports, routes traffic to primary or replicas
vectorNODELoggingCollects PostgreSQL, Patroni, Pgbouncer logs and ships to center
etcdETCDDCSDistributed consistent store for cluster metadata and leader info

By analogy, the PostgreSQL database kernel is the CPU, while the PGSQL module packages it as a complete computer. Patroni and Etcd form the HA subsystem, while pgBackRest and optional Silo form the backup subsystem. HAProxy, Pgbouncer, and vip-manager form the access subsystem. Various Exporters and Vector build the observability subsystem; finally, you can swap different kernel CPUs and extension cards.

Pigsty PostgreSQL cluster architecture
SubsystemComponentsFunction
HA SubsystemPatroni + etcdFailure detection, auto-failover, config management
Access SubsystemHAProxy + Pgbouncer + vip-managerService exposure, load balancing, pooling, VIP
Backup SubsystempgBackRest (+ Silo)Full/incremental backup, WAL archiving, PITR
Observability Subsystempg_exporter / pgbouncer_exporter / pgbackrest_exporter + VectorMetrics collection, log aggregation

Component Interaction

pigsty-arch

  • Cluster DNS is resolved by DNSMASQ on infra nodes
  • Cluster VIP is managed by vip-manager, which binds pg_vip_address to the cluster primary node.
  • Cluster services are exposed by HAProxy on nodes, different services distinguished by node ports (543x).
  • Pgbouncer is connection pooling middleware, listening on port 6432 by default, buffering connections, exposing additional metrics, and providing extra flexibility.
  • PostgreSQL listens on port 5432, providing relational database services
    • Installing PGSQL module on multiple nodes with the same cluster name automatically forms an HA cluster via streaming replication
    • PostgreSQL process is managed by patroni by default.
  • Patroni listens on port 8008 by default, supervising PostgreSQL server processes
    • Patroni starts Postgres server as child process
    • Patroni uses etcd as DCS: stores config, failure detection, and leader election.
    • Patroni provides Postgres info (e.g., primary/replica) via health checks, HAProxy uses this to distribute traffic
  • pg_exporter exposes postgres monitoring metrics on port 9630
  • pgbouncer_exporter exposes pgbouncer metrics on port 9631
  • pgBackRest uses local backup repository by default (pgbackrest_method = local)
    • If using local (default), pgBackRest creates local repository under pg_fs_bkup on primary node
    • If using minio, pgBackRest creates the backup repository on dedicated Silo or an external S3 service
  • Vector collects Postgres-related logs (postgres, pgbouncer, patroni, pgbackrest)
    • vector listens on port 9598, also exposes its own metrics to VictoriaMetrics on infra nodes
    • vector sends logs to VictoriaLogs on infra nodes

HA Subsystem

The HA subsystem consists of Patroni and etcd, responsible for PostgreSQL cluster failure detection, automatic failover, and configuration management.

How it works: Patroni runs on each node, managing the local PostgreSQL process and writing cluster state (leader, members, config) to etcd. When the primary fails, Patroni coordinates election via etcd, promoting the healthiest replica to new primary. The entire process is automatic, with RTO typically under 45 seconds.

Key Interactions:

  • PostgreSQL: Starts, stops, reloads PG as parent process, controls its lifecycle
  • etcd: External dependency, writes/watches leader key for distributed consensus and failure detection
  • HAProxy: Provides health checks via REST API (:8008), reporting instance role
  • vip-manager: Watches leader key in etcd, auto-migrates VIP

For more information, see: High Availability and Config: PGSQL - PG_BOOTSTRAP


Access Subsystem

The access subsystem consists of HAProxy, Pgbouncer, and vip-manager, responsible for service exposure, traffic routing, and connection pooling.

There are multiple access methods. A typical traffic path is: Client → DNS/VIP → HAProxy (543x) → Pgbouncer (6432) → PostgreSQL (5432)

LayerComponentPortRole
L2 VIPvip-manager-Binds L2 VIP to primary (optional)
L4 Load BalHAProxy543xService exposure, load balancing, health checks
L7 PoolPgbouncer6432Connection reuse, session management, transaction pooling

Service Ports:

  • 5433 primary: Read-write service, routes to primary Pgbouncer
  • 5434 replica: Read-only service, routes to replica Pgbouncer
  • 5436 default: Default service, direct to primary (bypasses pool)
  • 5438 offline: Offline service, direct to offline replica (ETL/analytics)

Key Features:

  • HAProxy uses Patroni REST API to determine instance role, auto-routes traffic
  • Pgbouncer uses transaction-level pooling, absorbs connection spikes, reduces PG connection overhead
  • vip-manager watches etcd leader key, auto-migrates VIP during failover

For more information, see: Service Access and Config: PGSQL - PG_ACCESS


Backup Subsystem

The backup subsystem consists of pgBackRest (optionally with Silo or external S3 as a remote repository), responsible for data backup and point-in-time recovery (PITR).

Backup Types:

  • Full backup: Complete database copy
  • Incremental/differential backup: Only backs up changed data blocks
  • WAL archiving: Continuous transaction log archiving, enables any point-in-time recovery

Storage Backends:

  • local (default): Local disk, backups stored at pg_fs_bkup mount point
  • minio: S3-compatible object storage, supports centralized backup management and off-site DR

Key Interactions:

  • pgBackRestPostgreSQL: Executes backup commands, manages WAL archiving
  • pgBackRestPatroni: Recovery can bootstrap replicas as new primary or standby
  • pgbackrest_exporter → VictoriaMetrics: Exports backup status metrics through the Prometheus-compatible protocol to monitor backup health

For more information, see: PITR, Backup & Recovery, and Config: PGSQL - PG_BACKUP


Observability Subsystem

The observability subsystem consists of three Exporters and Vector, responsible for metrics collection and log aggregation.

ComponentPortTargetKey Metrics
pg_exporter9630PostgreSQLSessions, transactions, replication lag, buffer hits
pgbouncer_exporter9631PgbouncerPool utilization, wait queue, hit rate
pgbackrest_exporter9854pgBackRestLatest backup time, size, type
vector9598postgres/patroni/pgbouncer logsStructured log stream

Data Flow:

  • Metrics: Exporter → VictoriaMetrics (INFRA) → Grafana dashboards
  • Logs: Vector → VictoriaLogs (INFRA) → Grafana log queries

pg_exporter / pgbouncer_exporter connect to target services via local Unix socket, decoupled from HA topology. In slim install mode, these components can be disabled.

For more information, see: Config: PGSQL - PG_MONITOR


PostgreSQL

PostgreSQL is the PGSQL module core, listening on port 5432 by default for relational database services, deployed 1:1 with nodes.

Pigsty currently supports PostgreSQL 14-18 (lifecycle major versions), installed via binary packages from the PGDG official repo. Pigsty also allows you to use other PG kernel forks to replace the default PostgreSQL kernel, and install up to 576 extension plugins on top of the PG kernel.

PostgreSQL processes are managed by default by the HA agent—Patroni. When a cluster has only one node, that instance is the primary; when the cluster has multiple nodes, other instances automatically join as replicas: through physical replication, syncing data changes from the primary in real-time. Replicas can handle read-only requests and automatically take over when the primary fails.

pigsty-ha.png

You can access PostgreSQL directly, or through HAProxy and Pgbouncer connection pool.

For more information, see: Config: PGSQL - PG_BOOTSTRAP


Patroni

Patroni is the PostgreSQL HA control component, listening on port 8008 by default.

Patroni takes over PostgreSQL startup, shutdown, configuration, and health status, writing leader and member information to etcd. It handles automatic failover, maintains replication factor, coordinates parameter changes, and provides a REST API for HAProxy, monitoring, and administrators.

HAProxy uses Patroni health check endpoints to determine instance roles and route traffic to the correct primary or replica. vip-manager monitors the leader key in etcd and automatically migrates the VIP when the primary changes.

patroni

For more information, see: Config: PGSQL - PG_BOOTSTRAP


Pgbouncer

Pgbouncer is a lightweight connection pooling middleware, listening on port 6432 by default, deployed 1:1 with PostgreSQL database and node.

Pgbouncer runs statelessly on each instance, connecting to PostgreSQL via local Unix socket, using Transaction Pooling by default for pool management, absorbing burst client connections, stabilizing database sessions, reducing lock contention, and significantly improving performance under high concurrency.

Pigsty routes production traffic (read-write service 5433 / read-only service 5434) through Pgbouncer by default, while only the default service (5436) and offline service (5438) bypass the pool for direct PostgreSQL connections.

Pool mode is controlled by pgbouncer_poolmode, defaulting to transaction (transaction-level pooling). Connection pooling can be disabled via pgbouncer_enabled.

pgbouncer.png

For more information, see: Config: PGSQL - PG_ACCESS


pgBackRest

pgBackRest is a professional PostgreSQL backup/recovery tool, one of the strongest in the PG ecosystem, supporting full/incremental/differential backup and WAL archiving.

Pigsty uses pgBackRest for PostgreSQL PITR capability, allowing you to roll back clusters to any point within the backup retention window.

pgBackRest works with PostgreSQL to create backup repositories on the primary, executing backup and archive tasks. By default, it uses local backup repository (pgbackrest_method = local), but can be configured for Silo or external S3 object storage for centralized backup management.

After initialization, pgbackrest_init_backup can automatically trigger the first full backup. Recovery integrates with Patroni, supporting bootstrapping replicas as new primaries or standbys.

pgbackrest

For more information, see: Backup & Recovery and Config: PGSQL - PG_BACKUP


HAProxy

HAProxy is the service entry point and load balancer, exposing multiple database service ports.

PortServiceTargetDescription
9101Admin-HAProxy statistics and admin page
5433primaryPrimary PgbouncerRead-write service, routes to primary pool
5434replicaReplica PgbouncerRead-only service, routes to replica pool
5436defaultPrimary PostgresDefault service, direct to primary (bypasses pool)
5438offlineOffline PostgresOffline service, direct to offline replica (ETL/analytics)

HAProxy uses Patroni REST API health checks to determine instance roles and route traffic to the appropriate primary or replica. Service definitions are composed from pg_default_services and pg_services.

A dedicated HAProxy node group can be specified via pg_service_provider to handle higher traffic; by default, HAProxy on local nodes publishes services.

haproxy

For more information, see: Service Access and Config: PGSQL - PG_ACCESS


vip-manager

vip-manager binds L2 VIP to the current primary node. This is an optional component; enable it if your network supports L2 VIP.

vip-manager runs on each PG node, monitoring the leader key written by Patroni in etcd, and binds pg_vip_address to the current primary node’s network interface. When cluster failover occurs, vip-manager immediately releases the VIP from the old primary and rebinds it on the new primary, switching traffic to the new primary.

This component is optional, enabled via pg_vip_enabled. When enabled, ensure all nodes are in the same VLAN; otherwise, VIP migration will fail. Public cloud networks typically don’t support L2 VIP; it’s recommended only for on-premises and private cloud environments.

node-vip

For more information, see: Tutorial: VIP Configuration and Config: PGSQL - PG_ACCESS


pg_exporter

pg_exporter exports PostgreSQL monitoring metrics, listening on port 9630 by default.

pg_exporter runs on each PG node, connecting to PostgreSQL via local Unix socket, exporting rich metrics covering sessions, buffer hits, replication lag, transaction rates, etc., scraped by VictoriaMetrics on INFRA nodes.

Collection configuration is specified by pg_exporter_config, with support for automatic database discovery (pg_exporter_auto_discovery), and tiered cache strategies via pg_exporter_cache_ttls.

You can disable this component via parameters; in slim install, this component is not enabled.

pg-exporter

For more information, see: Config: PGSQL - PG_MONITOR


pgbouncer_exporter

pgbouncer_exporter exports Pgbouncer connection pool metrics, listening on port 9631 by default.

pgbouncer_exporter uses the same pg_exporter binary but with a dedicated metrics config file, supporting pgbouncer 1.8-1.25+. pgbouncer_exporter reads Pgbouncer statistics views, providing pool utilization, wait queue, and hit rate metrics.

If Pgbouncer is disabled, this component is also disabled. In slim install, this component is not enabled.

For more information, see: Config: PGSQL - PG_MONITOR


pgbackrest_exporter

pgbackrest_exporter exports backup status metrics, listening on port 9854 by default.

pgbackrest_exporter parses pgBackRest status, generating metrics for most recent backup time, size, type, etc. Combined with alerting policies, it quickly detects expired or failed backups, ensuring data safety. Note that when there are many backups or using large network repositories, collection overhead can be significant, so pgbackrest_exporter has a default 2-minute collection interval. In the worst case, you may see the latest backup status in the monitoring system 2 minutes after a backup completes.

For more information, see: Config: PGSQL - PG_MONITOR


etcd

etcd is a distributed consistent store (DCS), providing cluster metadata storage and leader election capability for Patroni.

etcd is deployed and managed by the independent ETCD module, not part of the PGSQL module itself, but critical for PostgreSQL HA. Patroni writes cluster state, leader info, and config parameters to etcd; all nodes reach consensus through etcd. vip-manager also reads the leader key from etcd to enable automatic VIP migration.

For more information, see: ETCD Module


vector

Vector is a high-performance log collection component, deployed by the NODE module, responsible for collecting PostgreSQL-related logs.

Vector runs on nodes, tracking PostgreSQL, Pgbouncer, Patroni, and pgBackRest log directories, sending structured logs to VictoriaLogs on INFRA nodes for centralized storage and querying.

For more information, see: NODE Module

3.2 - ER Model

How Pigsty abstracts different functionality into modules, and the E-R diagrams for these modules.

The largest entity concept in Pigsty is a Deployment. The main entities and relationships (E-R diagram) in a deployment are shown below:

Pigsty full data model ER diagram

A deployment can also be understood as an Environment. For example, Production (Prod), User Acceptance Testing (UAT), Staging, Testing, Development (Devbox), etc. Each environment corresponds to a Pigsty inventory that describes all entities and attributes in that environment.

Typically, an environment includes shared infrastructure (INFRA), which broadly includes ETCD (HA DCS) and MINIO (centralized backup repository), serving multiple PostgreSQL database clusters (and other database module components). (Exception: there are also deployments without infrastructure)

In Pigsty, almost all database modules are organized as “Clusters”. Each cluster is an Ansible group containing several node resources. For example, PostgreSQL HA database clusters, Redis, Etcd, and Silo all exist as clusters. An environment can contain multiple clusters.

3.2.1 - E-R Model of Infra Cluster

Entity-Relationship model for INFRA infrastructure nodes in Pigsty, component composition, and naming conventions.

The INFRA module plays a special role in Pigsty: it’s not a traditional “cluster” but rather a management hub composed of a group of infrastructure nodes, providing core services for the entire Pigsty deployment. Each INFRA node is an autonomous infrastructure service unit running core components like Nginx, Grafana, and VictoriaMetrics, collectively providing observability and management capabilities for managed database clusters.

There are two core entities in Pigsty’s INFRA module:

  • Node: A server running infrastructure components—can be bare metal, VM, container, or Pod.
  • Component: Various infrastructure services running on nodes, such as Nginx, Grafana, VictoriaMetrics, etc.

INFRA nodes typically serve as Admin Nodes, the control plane of Pigsty.


Component Composition

Each INFRA node runs the following core components:

ComponentPortDescription
Nginx80/443Web portal, local repo, unified reverse proxy
Grafana3000Visualization platform, dashboards, data apps
VictoriaMetrics8428Time-series database, Prometheus API compatible
VictoriaLogs9428Log database, receives structured logs from Vector
VictoriaTraces10428Trace storage for slow SQL / request tracing
VMAlert8880Alert rule evaluator based on VictoriaMetrics
Alertmanager9059Alert aggregation and dispatch
Blackbox Exporter9115ICMP/TCP/HTTP black-box probing
DNSMASQ53DNS server for internal domain resolution
Chronyd123NTP time server

These components together form Pigsty’s observability infrastructure.


Examples

Let’s look at a concrete example with a two-node INFRA deployment:

infra:
  hosts:
    10.10.10.10: { infra_seq: 1 }
    10.10.10.11: { infra_seq: 2 }

The above config fragment defines a two-node INFRA deployment:

GroupDescription
infraINFRA infrastructure node group
NodeDescription
infra-110.10.10.10 INFRA node #1
infra-210.10.10.11 INFRA node #2

For production environments, deploying at least two INFRA nodes is recommended for infrastructure component redundancy.


Identity Parameters

Pigsty uses the INFRA_ID parameter group to assign deterministic identities to each INFRA module entity. One parameter is required:

ParameterTypeLevelDescriptionFormat
infra_seqintNodeINFRA node sequence, requiredNatural number, starting from 1, unique within group

With node sequence assigned at node level, Pigsty automatically generates unique identifiers for each entity based on rules:

EntityGeneration RuleExample
Nodeinfra-{{ infra_seq }}infra-1, infra-2

The INFRA module assigns infra-N format identifiers to nodes for distinguishing multiple infrastructure nodes in the monitoring system. However, this doesn’t change the node’s hostname or system identity; nodes still use their existing hostname or IP address for identification.


Service Portal

INFRA nodes provide unified web service entry through Nginx. The infra_portal parameter defines services exposed through Nginx.

The default configuration only defines the home server:

infra_portal:
  home : { domain: i.pigsty }

Pigsty automatically configures reverse proxy endpoints for enabled components (Grafana, VictoriaMetrics, AlertManager, etc.). If you need to access these services via separate domains, you can explicitly add configurations:

infra_portal:
  home         : { domain: i.pigsty }
  grafana      : { domain: g.pigsty, endpoint: "${admin_ip}:3000", websocket: true }
  prometheus   : { domain: p.pigsty, endpoint: "${admin_ip}:8428" }   # VMUI
  alertmanager : { domain: a.pigsty, endpoint: "${admin_ip}:9059" }
DomainServiceDescription
i.pigstyHomePigsty homepage
g.pigstyGrafanaMonitoring dashboard
p.pigstyVictoriaMetricsTSDB Web UI
a.pigstyAlertmanagerAlert management UI

Accessing Pigsty services via domain names is recommended over direct IP + port.


Deployment Scale

The number of INFRA nodes depends on deployment scale and HA requirements:

ScaleINFRA NodesDescription
Dev/Test1Single-node deployment, all on one node
Small Prod1-2Single or dual node, can share with other services
Medium Prod2-3Dedicated INFRA nodes, redundant components
Large Prod3+Multiple INFRA nodes, component separation

In singleton deployment, INFRA components share the same node with PGSQL, ETCD, etc. In small-scale deployments, INFRA nodes typically also serve as “Admin Node” / backup admin node and local software repository (/www/pigsty). In larger deployments, these responsibilities can be separated to dedicated nodes.


Monitoring Label System

Pigsty’s monitoring system collects metrics from INFRA components themselves. Unlike database modules, each component in the INFRA module is treated as an independent monitoring object, distinguished by the cls (class) label.

LabelDescriptionExample
clsComponent type, each forming a “class”nginx
insInstance name, format {component}-{infra_seq}nginx-1
ipINFRA node IP running the component10.10.10.10
jobVictoriaMetrics scrape job, fixed as infrainfra

Using a two-node INFRA deployment (infra_seq: 1 and infra_seq: 2) as example, component monitoring labels are:

Componentclsins ExamplePort
Nginxnginxnginx-1, nginx-29113
Grafanagrafanagrafana-1, grafana-23000
VictoriaMetricsvmetricsvmetrics-1, vmetrics-28428
VictoriaLogsvlogsvlogs-1, vlogs-29428
VictoriaTracesvtracesvtraces-1, vtraces-210428
VMAlertvmalertvmalert-1, vmalert-28880
Alertmanageralertmanageralertmanager-1, alertmanager-29059
Blackboxblackboxblackbox-1, blackbox-29115

All INFRA component metrics use a unified job="infra" label, distinguished by the cls label:

nginx_up{cls="nginx", ins="nginx-1", ip="10.10.10.10", job="infra"}
grafana_info{cls="grafana", ins="grafana-1", ip="10.10.10.10", job="infra"}
vm_app_version{cls="vmetrics", ins="vmetrics-1", ip="10.10.10.10", job="infra"}
vlogs_rows_ingested_total{cls="vlogs", ins="vlogs-1", ip="10.10.10.10", job="infra"}
alertmanager_alerts{cls="alertmanager", ins="alertmanager-1", ip="10.10.10.10", job="infra"}

3.2.2 - E-R Model of PostgreSQL Cluster

Entity-Relationship model for PostgreSQL clusters in Pigsty, including E-R diagram, entity definitions, and naming conventions.

The PGSQL module organizes PostgreSQL in production as clusterslogical entities composed of a group of database instances associated by primary-replica relationships.

Each cluster is an autonomous business unit consisting of at least one primary instance, exposing capabilities through services.

There are four core entities in Pigsty’s PGSQL module:

  • Cluster: An autonomous PostgreSQL business unit serving as the top-level namespace for other entities.
  • Service: A named abstraction that exposes capabilities, routes traffic, and exposes services using node ports.
  • Instance: A single PostgreSQL server consisting of running processes and database files on a single node.
  • Node: A hardware resource abstraction running Linux + Systemd environment—can be bare metal, VM, container, or Pod.

Along with two business entities—“Database” and “Role”—these form the complete logical view as shown below:

er-pgsql

Examples

Let’s look at two concrete examples. Using the four-node Pigsty sandbox, there’s a three-node pg-test cluster:

    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
        10.10.10.12: { pg_seq: 2, pg_role: replica }
        10.10.10.13: { pg_seq: 3, pg_role: replica }
      vars: { pg_cluster: pg-test }

The above config fragment defines a high-availability PostgreSQL cluster with these related entities:

ClusterDescription
pg-testPostgreSQL 3-node HA cluster
InstanceDescription
pg-test-1PostgreSQL instance #1, default primary
pg-test-2PostgreSQL instance #2, initial replica
pg-test-3PostgreSQL instance #3, initial replica
ServiceDescription
pg-test-primaryRead-write service (routes to primary pgbouncer)
pg-test-replicaRead-only service (routes to replica pgbouncer)
pg-test-defaultDirect read-write service (routes to primary postgres)
pg-test-offlineOffline read service (routes to dedicated postgres)
NodeDescription
node-110.10.10.11 Node #1, hosts pg-test-1 PG instance
node-210.10.10.12 Node #2, hosts pg-test-2 PG instance
node-310.10.10.13 Node #3, hosts pg-test-3 PG instance
ha

Identity Parameters

Pigsty uses the PG_ID parameter group to assign deterministic identities to each PGSQL module entity. Three parameters are required:

ParameterTypeLevelDescriptionFormat
pg_clusterstringClusterPG cluster name, requiredValid DNS name, regex [a-zA-Z0-9-]+
pg_seqintInstancePG instance number, requiredNatural number, starting from 0 or 1, unique within cluster
pg_roleenumInstancePG instance role, requiredEnum: primary, replica, offline

With cluster name defined at cluster level and instance number/role assigned at instance level, Pigsty automatically generates unique identifiers for each entity based on rules:

EntityGeneration RuleExample
Instance{{ pg_cluster }}-{{ pg_seq }}pg-test-1, pg-test-2, pg-test-3
Service{{ pg_cluster }}-{{ pg_role }}pg-test-primary, pg-test-replica, pg-test-offline
NodeExplicitly specified or borrowed from PGpg-test-1, pg-test-2, pg-test-3

Because Pigsty adopts a 1:1 exclusive deployment model for nodes and PG instances, by default the host node identifier borrows from the PG instance identifier (node_id_from_pg). You can also explicitly specify nodename to override, or disable nodename_overwrite to use the current default.


Sharding Identity Parameters

When using multiple PostgreSQL clusters (sharding) to serve the same business, two additional identity parameters are used: pg_shard and pg_group.

In this case, this group of PostgreSQL clusters shares the same pg_shard name with their own pg_group numbers, like this Citus cluster:

In this case, pg_cluster cluster names are typically composed of: {{ pg_shard }}{{ pg_group }}, e.g., pg-citus0, pg-citus1, etc.

all:
  children:
    pg-citus0: # citus shard 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus shard 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus shard 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus shard 3
      hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }

Pigsty provides dedicated monitoring dashboards for horizontal sharding clusters, making it easy to compare performance and load across shards, but this requires using the above entity naming convention.

There are also other identity parameters for special scenarios, such as pg_upstream for specifying backup clusters/cascading replication upstream, gp_role for Greenplum cluster identity, pg_exporters for external monitoring instances, pg_offline_query for offline query instances, etc. See PG_ID parameter docs.


Monitoring Label System

Pigsty provides an out-of-box monitoring system that uses the above identity parameters to identify various PostgreSQL entities.

pg_up{cls="pg-test", ins="pg-test-1", ip="10.10.10.11", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-2", ip="10.10.10.12", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-3", ip="10.10.10.13", job="pgsql"}

For example, the cls, ins, ip labels correspond to cluster name, instance name, and node IP—the identifiers for these three core entities. They appear along with the job label in all native monitoring metrics collected by VictoriaMetrics and VictoriaLogs log streams.

The job name for collecting PostgreSQL metrics is fixed as pgsql; The job name for monitoring remote PG instances is fixed as pgrds. The job name for collecting PostgreSQL CSV logs is fixed as postgres; The job name for collecting pgbackrest logs is fixed as pgbackrest, other PG components collect logs via job: syslog.

Additionally, some entity identity labels appear in specific entity-related monitoring metrics, such as:

  • datname: Database name, if a metric belongs to a specific database.
  • relname: Table name, if a metric belongs to a specific table.
  • idxname: Index name, if a metric belongs to a specific index.
  • funcname: Function name, if a metric belongs to a specific function.
  • seqname: Sequence name, if a metric belongs to a specific sequence.
  • query: Query fingerprint, if a metric belongs to a specific query.

3.2.3 - E-R Model of Etcd Cluster

Entity-Relationship model for ETCD clusters in Pigsty, including E-R diagram, entity definitions, and naming conventions.

The ETCD module organizes ETCD in production as clusterslogical entities composed of a group of ETCD instances associated through the Raft consensus protocol.

Each cluster is an autonomous distributed key-value storage unit consisting of at least one ETCD instance, exposing service capabilities through client ports.

There are three core entities in Pigsty’s ETCD module:

  • Cluster: An autonomous ETCD service unit serving as the top-level namespace for other entities.
  • Instance: A single ETCD server process running on a node, participating in Raft consensus.
  • Node: A hardware resource abstraction running Linux + Systemd environment, implicitly declared.

Compared to PostgreSQL clusters, the ETCD cluster model is simpler, without Services or complex Role distinctions. All ETCD instances are functionally equivalent, electing a Leader through the Raft protocol while others become Followers. During scale-out intermediate states, non-voting Learner instance members are also allowed.


Examples

Let’s look at a concrete example with a three-node ETCD cluster:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    10.10.10.12: { etcd_seq: 3 }
  vars:
    etcd_cluster: etcd

The above config fragment defines a three-node ETCD cluster with these related entities:

ClusterDescription
etcdETCD 3-node HA cluster
InstanceDescription
etcd-1ETCD instance #1
etcd-2ETCD instance #2
etcd-3ETCD instance #3
NodeDescription
10.10.10.10Node #1, hosts etcd-1 instance
10.10.10.11Node #2, hosts etcd-2 instance
10.10.10.12Node #3, hosts etcd-3 instance

Identity Parameters

Pigsty uses the ETCD parameter group to assign deterministic identities to each ETCD module entity. Two parameters are required:

ParameterTypeLevelDescriptionFormat
etcd_clusterstringClusterETCD cluster name, requiredValid DNS name, defaults to fixed etcd
etcd_seqintInstanceETCD instance number, requiredNatural number, starting from 1, unique within cluster

With cluster name defined at cluster level and instance number assigned at instance level, Pigsty automatically generates unique identifiers for each entity based on rules:

EntityGeneration RuleExample
Instance{{ etcd_cluster }}-{{ etcd_seq }}etcd-1, etcd-2, etcd-3

The ETCD module does not assign additional identity to host nodes; nodes are identified by their existing hostname or IP address.


Ports & Protocols

Each ETCD instance listens on the following two ports:

PortParameterPurpose
2379etcd_portClient port, accessed by Patroni, vip-manager, etc.
2380etcd_peer_portPeer communication port, used for Raft consensus

ETCD clusters enable TLS-encrypted communication by default and use RBAC authentication. Clients need the correct certificates and passwords to access ETCD services.


Cluster Size

As a distributed coordination service, ETCD cluster size directly affects availability, requiring more than half (quorum) of nodes to be alive to maintain service.

Cluster SizeQuorumFault ToleranceUse Case
1 node10Dev, test, demo
3 nodes21Small-medium production
5 nodes32Large-scale production

Even-member ETCD clusters are technically valid, but they do not tolerate more failures than an odd cluster with one fewer member and add deployment and quorum cost. Production clusters therefore usually have one, three, or five members; clusters larger than five are uncommon.


Monitoring Label System

Pigsty provides an out-of-box monitoring system that uses the above identity parameters to identify various ETCD entities.

etcd_up{cls="etcd", ins="etcd-1", ip="10.10.10.10", job="etcd"}
etcd_up{cls="etcd", ins="etcd-2", ip="10.10.10.11", job="etcd"}
etcd_up{cls="etcd", ins="etcd-3", ip="10.10.10.12", job="etcd"}

For example, the cls, ins, ip labels correspond to cluster name, instance name, and node IP—the identifiers for these three core entities. They appear along with the job label in all ETCD monitoring metrics collected by VictoriaMetrics. The job name for collecting ETCD metrics is fixed as etcd.

3.2.4 - MINIO Cluster Model

The cluster, instance, and node identity model used when Pigsty’s MINIO module deploys Silo.

MINIO is Pigsty’s compatibility module name for object storage. The current v4.5.0 source deploys Silo through minio_type: silo and organizes a group of object-storage instances into a cluster.

Each cluster is an autonomous S3-compatible object-storage unit consisting of at least one instance and exposing service through the S3 API port.

There are three core entities in Pigsty’s MINIO module:

  • Cluster: An autonomous object-storage service unit serving as the top-level namespace for other entities.
  • Instance: A single Silo server process running on a node and managing local disks.
  • Node: A hardware resource abstraction running Linux + Systemd environment, implicitly declared.

Silo also retains the Storage Pool concept for expansion.


Deployment Modes

Silo supports Pigsty’s three inventory deployment modes:

ModeCodeDescriptionUse Case
Single-Node Single-DriveSNSDSingle node, single data directory or diskDev, test, demo
Single-Node Multi-DriveSNMDSingle node, multiple disks, typically 4+Resource-constrained small deployments
Multi-Node Multi-DriveMNMDMultiple nodes, multiple disks per nodeProduction recommended

SNSD mode can use a regular directory for quick experimentation. Multi-drive Silo deployments should use real disk mount points or the service will refuse to start.


Examples

The following example explicitly selects the current default Silo backend and defines a four-node multi-drive cluster:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
    10.10.10.13: { minio_seq: 4 }
  vars:
    minio_cluster: minio
    minio_type: silo
    minio_data: '/data{1...4}'
    minio_node: '${minio_cluster}-${minio_seq}.pigsty'

This config fragment defines a four-node Silo cluster with four disks per node. Instance identifiers retain the MINIO module’s compatibility naming:

ClusterDescription
minioSilo 4-node HA cluster
InstanceDescription
minio-1Object-storage instance #1, managing 4 disks
minio-2Object-storage instance #2, managing 4 disks
minio-3Object-storage instance #3, managing 4 disks
minio-4Object-storage instance #4, managing 4 disks
NodeDescription
10.10.10.10Node #1, hosts minio-1 instance
10.10.10.11Node #2, hosts minio-2 instance
10.10.10.12Node #3, hosts minio-3 instance
10.10.10.13Node #4, hosts minio-4 instance

Identity Parameters

Pigsty uses the MINIO parameter group to assign deterministic identities to each MinIO module entity. Two parameters are required:

ParameterTypeLevelDescriptionFormat
minio_clusterstringClusterObject-storage cluster name, requiredValid non-empty name, no default
minio_seqintInstanceObject-storage instance number, requiredNatural number, starting from 1, unique within cluster

With cluster name defined at cluster level and instance number assigned at instance level, Pigsty automatically generates unique identifiers for each entity based on rules:

EntityGeneration RuleExample
Instance{{ minio_cluster }}-{{ minio_seq }}minio-1, minio-2, minio-3, minio-4

The MINIO module does not assign additional identity to host nodes; nodes are identified by their existing hostname or IP address. The minio_node parameter generates node names for internal Silo cluster use (written to /etc/hosts for cluster discovery), not host-node identity.

Roles locate actual members across the entire inventory by minio_cluster; the Ansible group name does not need to match the cluster name. minio_type is a retained backend selector and currently must be silo.


Core Configuration Parameters

Beyond identity parameters, the following parameters are critical for Silo cluster configuration:

ParameterTypeDescription
minio_typeenumRetained selector; currently only silo
minio_datapathData directory, use {x...y} for multi-drive
minio_nodestringNode name pattern for multi-node deployment
minio_domainstringService domain, defaults to sss.pigsty

These parameters determine minio_volumes, which the role writes to Silo’s MINIO_VOLUMES:

  • SNSD: Direct minio_data value, e.g., /data/minio
  • SNMD: Expanded minio_data directories, e.g., /data{1...4}
  • MNMD: Combined minio_node and minio_data, e.g., https://minio-{1...4}.pigsty:9000/data{1...4}

Ports & Services

Each object-storage instance listens on the following ports:

PortParameterPurpose
9000minio_portS3 API service port
9001minio_admin_portWeb admin console port

The MINIO module enables HTTPS by default, controlled by minio_https. Keep HTTPS enabled with the default pgBackRest S3 repository configuration and install the Pigsty CA correctly.

Clients can reach a multi-node Silo cluster through any member. For a stable entry point, use a load balancer such as HAProxy with a VIP.


Resource Provisioning

After Silo cluster deployment, Pigsty automatically creates the following resources (controlled by minio_provision):

Default Buckets (defined by minio_buckets):

BucketPurpose
pgsqlPostgreSQL pgBackREST backup storage
metaMetadata storage, versioning enabled
dataGeneral data storage

Default Users (defined by minio_users):

UserDefault PasswordPolicyPurpose
pgbackrestS3User.BackuppgsqlPostgreSQL backup dedicated user
s3user_metaS3User.MetametaAccess meta bucket
s3user_dataS3User.DatadataAccess data bucket

These passwords are publicly documented default credentials, intended only for demonstrations and local development. Replace them before production deployment.

pgbackrest is used for PostgreSQL cluster backups; s3user_meta and s3user_data are reserved users not actively used.


Monitoring Label System

Pigsty uses the identity parameters above to identify object-storage entities. A Silo availability series looks like this:

minio_up{cls="minio", ins="minio-1", ip="10.10.10.10", job="minio"}
minio_up{cls="minio", ins="minio-2", ip="10.10.10.11", job="minio"}
minio_up{cls="minio", ins="minio-3", ip="10.10.10.12", job="minio"}
minio_up{cls="minio", ins="minio-4", ip="10.10.10.13", job="minio"}

Here cls, ins, and ip identify the cluster name, instance name, and node IP. Compatible monitoring naming keeps job="minio", while the current backend label is flavor=silo. See the metric list for details.

3.2.5 - E-R Model of Redis Cluster

Entity-Relationship model for Redis clusters in Pigsty, including E-R diagram, entity definitions, and naming conventions.

The Redis module organizes Redis in production as clusterslogical entities composed of a group of Redis instances deployed on one or more nodes.

Each cluster is an autonomous high-performance cache/storage unit consisting of at least one Redis instance, exposing service capabilities through ports.

There are three core entities in Pigsty’s Redis module:

  • Cluster: An autonomous Redis service unit serving as the top-level namespace for other entities.
  • Instance: A single Redis server process running on a specific port on a node.
  • Node: A hardware resource abstraction running Linux + Systemd environment, can host multiple Redis instances, implicitly declared.

Unlike PostgreSQL, Redis uses a single-node multi-instance deployment model: one physical/virtual machine node typically deploys multiple Redis instances to fully utilize multi-core CPUs. Therefore, nodes and instances have a 1:N relationship. Additionally, production typically advises against Redis instances with memory > 12GB.


Operating Modes

Redis has three different operating modes, specified by the redis_mode parameter:

ModeCodeDescriptionHA Mechanism
StandalonestandaloneClassic master-replica, default modeRequires Sentinel
SentinelsentinelHA monitoring and auto-failover for standaloneMulti-node quorum
Native ClusterclusterRedis native distributed cluster, no sentinel neededBuilt-in auto-failover
  • Standalone: Default mode, replication via replica_of parameter. Requires additional Sentinel cluster for HA.
  • Sentinel: Stores no business data, dedicated to monitoring standalone Redis clusters for auto-failover; multi-node itself provides HA.
  • Native Cluster: Data auto-sharded across multiple primaries, each can have multiple replicas, built-in HA, no sentinel needed.

Examples

Let’s look at concrete examples for each mode:

Standalone Cluster

Classic master-replica on a single node:

redis-ms:
  hosts:
    10.10.10.10:
      redis_node: 1
      redis_instances:
        6379: { }
        6380: { replica_of: '10.10.10.10 6379' }
  vars:
    redis_cluster: redis-ms
    redis_password: 'redis.ms'
    redis_max_memory: 64MB
ClusterDescription
redis-msRedis standalone cluster
NodeDescription
redis-ms-110.10.10.10 Node #1, hosts 2 instances
InstanceDescription
redis-ms-1-6379Primary instance, listening on port 6379
redis-ms-1-6380Replica instance, port 6380, replicates from 6379

Sentinel Cluster

Three sentinel instances on a single node for monitoring standalone clusters. Sentinel clusters specify monitored standalone clusters via redis_sentinel_monitor:

redis-sentinel:
  hosts:
    10.10.10.11:
      redis_node: 1
      redis_instances: { 26379: {}, 26380: {}, 26381: {} }
  vars:
    redis_cluster: redis-sentinel
    redis_password: 'redis.sentinel'
    redis_mode: sentinel
    redis_max_memory: 16MB
    redis_sentinel_monitor:
      - { name: redis-ms, host: 10.10.10.10, port: 6379, password: redis.ms, quorum: 2 }

Native Cluster

A Redis native distributed cluster with two nodes and six instances (minimum spec: 3 primaries, 3 replicas):

redis-test:
  hosts:
    10.10.10.12: { redis_node: 1, redis_instances: { 6379: {}, 6380: {}, 6381: {} } }
    10.10.10.13: { redis_node: 2, redis_instances: { 6379: {}, 6380: {}, 6381: {} } }
  vars:
    redis_cluster: redis-test
    redis_password: 'redis.test'
    redis_mode: cluster
    redis_max_memory: 32MB

This creates a 3 primary 3 replica native Redis cluster.

ClusterDescription
redis-testRedis native cluster (3P3R)
InstanceDescription
redis-test-1-6379Instance on node 1, port 6379
redis-test-1-6380Instance on node 1, port 6380
redis-test-1-6381Instance on node 1, port 6381
redis-test-2-6379Instance on node 2, port 6379
redis-test-2-6380Instance on node 2, port 6380
redis-test-2-6381Instance on node 2, port 6381
NodeDescription
redis-test-110.10.10.12 Node #1, hosts 3 instances
redis-test-210.10.10.13 Node #2, hosts 3 instances

Identity Parameters

Pigsty uses the REDIS parameter group to assign deterministic identities to each Redis module entity. Three parameters are required:

ParameterTypeLevelDescriptionFormat
redis_clusterstringClusterRedis cluster name, requiredValid DNS name, regex [a-z][a-z0-9-]*
redis_nodeintNodeRedis node number, requiredNatural number, starting from 1, unique within cluster
redis_instancesdictNodeRedis instance definition, requiredJSON object, key is port, value is instance config

With cluster name defined at cluster level and node number/instance definition assigned at node level, Pigsty automatically generates unique identifiers for each entity:

EntityGeneration RuleExample
Instance{{ redis_cluster }}-{{ redis_node }}-{{ port }}redis-ms-1-6379, redis-ms-1-6380

The Redis module does not assign additional identity to host nodes; nodes are identified by their existing hostname or IP address. redis_node is used for instance naming, not host node identity.


Instance Definition

redis_instances is a JSON object with port number as key and instance config as value:

redis_instances:
  6379: { }                                      # Primary instance, no extra config
  6380: { replica_of: '10.10.10.10 6379' }       # Replica, specify upstream primary
  6381: { replica_of: '10.10.10.10 6379' }       # Replica, specify upstream primary

Each Redis instance listens on a unique port within the node. You can choose any port number, but avoid system reserved ports (< 1024) or conflicts with Pigsty used ports. The replica_of parameter sets replication relationship in standalone mode, format '<ip> <port>', specifying upstream primary address and port.

Additionally, each Redis node runs a Redis Exporter collecting metrics from all local instances:

PortParameterPurpose
9121redis_exporter_portRedis Exporter port

Redis’s single-node multi-instance deployment model has some limitations:

  • Node Exclusive: A node can only belong to one Redis cluster, not assigned to different clusters simultaneously.
  • Port Unique: Redis instances on the same node must use different ports to avoid conflicts.
  • Password Shared: Multiple instances on the same node cannot have different passwords (redis_exporter limitation).
  • Manual HA: Standalone Redis clusters require additional Sentinel configuration for auto-failover.

Monitoring Label System

Pigsty provides an out-of-box monitoring system that uses the above identity parameters to identify various Redis entities.

redis_up{cls="redis-ms", ins="redis-ms-1-6379", ip="10.10.10.10", job="redis"}
redis_up{cls="redis-ms", ins="redis-ms-1-6380", ip="10.10.10.10", job="redis"}

For example, the cls, ins, ip labels correspond to cluster name, instance name, and node IP—the identifiers for these three core entities. They appear along with the job label in all Redis monitoring metrics collected by VictoriaMetrics. The job name for collecting Redis metrics is fixed as redis.

3.3 - Infra as Code

Pigsty uses Infrastructure as Code (IaC) philosophy to manage all components, providing declarative management for large-scale clusters.

Pigsty follows the IaC and GitOPS philosophy: use a declarative config inventory to describe the entire environment, and materialize it through idempotent playbooks.

Users describe their desired state declaratively through parameters, and playbooks idempotently adjust target nodes to reach that state. This is similar to Kubernetes CRDs & Operators, but Pigsty implements this functionality on bare metal and virtual machines through Ansible.

Pigsty was born to solve the operational management problem of ultra-large-scale PostgreSQL clusters. The idea behind it is simple — we need the ability to replicate the entire infrastructure (100+ database clusters + PG/Redis + observability) on ready servers within ten minutes. No GUI + ClickOps can complete such a complex task in such a short time, making CLI + IaC the only choice — it provides precise, efficient control.

The config inventory pigsty.yml file describes the state of the entire deployment. Whether it’s production (prod), staging, test, or development (devbox) environments, the difference between infrastructures lies only in the config inventory, while the deployment delivery logic is exactly the same.

You can use git for version control and auditing of this deployment “seed/gene”, and Pigsty even supports storing the config inventory as database tables in PostgreSQL CMDB, further achieving Infra as Data capability. Seamlessly integrate with your existing workflows.

IaC is designed for professional users and enterprise scenarios but is also deeply optimized for individual developers and SMBs. Even if you’re not a professional DBA, you don’t need to understand these hundreds of adjustment knobs and switches. All parameters come with well-performing default values. You can get an out-of-the-box single-node database with zero configuration; Simply add two more IP addresses to get an enterprise-grade high-availability PostgreSQL cluster.


Declare Modules

Take the following default config snippet as an example. This config describes a node 10.10.10.10 with INFRA, NODE, ETCD, and PGSQL modules installed.

# monitoring, alerting, DNS, NTP and other infrastructure cluster...
infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

# minio cluster, s3 compatible object storage
minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

# etcd cluster, used as DCS for PostgreSQL high availability
etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

# PGSQL example cluster: pg-meta
pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }

To actually install these modules, execute the following playbooks:

./infra.yml -l 10.10.10.10  # Initialize infra module on node 10.10.10.10
./etcd.yml  -l 10.10.10.10  # Initialize etcd module on node 10.10.10.10
./minio.yml -l 10.10.10.10  # Initialize minio module on node 10.10.10.10
./pgsql.yml -l 10.10.10.10  # Initialize pgsql module on node 10.10.10.10

Declare Clusters

You can declare PostgreSQL database clusters by installing the PGSQL module on multiple nodes, making them a service unit:

For example, to deploy a three-node high-availability PostgreSQL cluster using streaming replication on the following three Pigsty-managed nodes, you can add the following definition to the all.children section of the config file pigsty.yml:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: offline }
  vars:  { pg_cluster: pg-test }

After defining, you can use playbooks to create the cluster:

bin/pgsql-add pg-test   # Create the pg-test cluster
pigsty-iac.jpg

You can use different instance roles such as primary, replica, offline, delayed, sync standby; as well as different clusters: such as standby clusters, Citus clusters, and even Redis / MINIO (Silo) / Etcd clusters


Customize Cluster Content

Not only can you define clusters declaratively, but you can also define databases, users, services, and HBA rules within the cluster. For example, the following config file deeply customizes the content of the default pg-meta single-node database cluster:

Including: declaring six business databases and seven business users, adding an extra standby service (synchronous standby, providing read capability with no replication delay), defining some additional pg_hba rules, an L2 VIP address pointing to the cluster primary, and a customized backup strategy.

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
  vars:
    pg_cluster: pg-meta
    pg_databases:                       # define business databases on this cluster, array of database definition
      - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
        baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g files/)
        pgbouncer: true                 # optional, add this database to pgbouncer database list? true by default
        schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
        extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
          - { name: postgis , schema: public }
          - { name: timescaledb }
        comment: pigsty meta database   # optional, comment string for this database
        owner: postgres                # optional, database owner, postgres by default
        template: template1            # optional, which template to use, template1 by default
        encoding: UTF8                 # optional, database encoding, UTF8 by default. (MUST same as template database)
        locale: C                      # optional, database locale, C by default.  (MUST same as template database)
        lc_collate: C                  # optional, database collate, C by default. (MUST same as template database)
        lc_ctype: C                    # optional, database ctype, C by default.   (MUST same as template database)
        tablespace: pg_default         # optional, default tablespace, 'pg_default' by default.
        allowconn: true                # optional, allow connection, true by default. false will disable connect at all
        revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
        register_datasource: true      # optional, register this database to grafana datasources? true by default
        connlimit: -1                  # optional, database connection limit, default -1 disable limit
        pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
        pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
        pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
        pool_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
        pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
        pool_connlimit: 100          # optional, max database connections at database level, default 100
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
    pg_users:                           # define business users/roles on this cluster, array of user definition
      - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
        password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
        login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
        superuser: false                # optional, is superuser? false by default
        createdb: false                 # optional, can create database? false by default
        createrole: false               # optional, can create role? false by default
        inherit: true                   # optional, can this role use inherited privileges? true by default
        replication: false              # optional, can this role do replication? false by default
        bypassrls: false                # optional, can this role bypass row level security? false by default
        pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
        connlimit: -1                   # optional, user connection limit, default -1 disable limit
        expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
        expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
        comment: pigsty admin user      # optional, comment string for this user/role
        roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
        parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
        pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
        pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database}
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database   }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database  }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway   }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service      }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service    }
    pg_services:                        # extra services in addition to pg_default_services, array of service definition
      # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
      - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
        port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
        ip: "*"                         # optional, service bind ip address, `*` for all ip by default
        selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
        dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
        check: /sync                    # optional, health check url path, / by default
        backup: "[? pg_role == `primary`]"  # backup server selector
        maxconn: 3000                   # optional, max allowed front-end connection
        balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
        options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.2/24
    pg_vip_interface: eth1
    pg_crontab:  # full backup daily at 1am (installed in the postgres user crontab)
      - '00 01 * * * /pg/bin/pg-backup full'

Declare Access Control

You can also customize Pigsty’s access control through declarative configuration. For example, the following config file provides deep security customization for the pg-meta cluster:

Uses the three-node core cluster template: crit.yml, to ensure data consistency is prioritized with zero data loss during failover. Enables L2 VIP and restricts database and connection pool listening addresses to local loopback IP + internal network IP + VIP three specific addresses. The template enables TLS for the Patroni API and PgBouncer, and requires SSL for database access through HBA. It also enables $libdir/passwordcheck in pg_libs to enforce a password-strength policy.

Finally, a separate pg-meta-delay cluster is declared as pg-meta’s delayed replica from one hour ago, for emergency data deletion recovery.

pg-meta:      # 3 instance postgres cluster `pg-meta`
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
    10.10.10.11: { pg_seq: 2, pg_role: replica }
    10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
  vars:
    pg_cluster: pg-meta
    pg_conf: crit.yml
    pg_users:
      - { name: dbuser_meta , password: DBUser.Meta   , pgbouncer: true , roles: [ dbrole_admin ] , comment: pigsty admin user }
      - { name: dbuser_view , password: DBUser.Viewer , pgbouncer: true , roles: [ dbrole_readonly ] , comment: read-only viewer for meta database }
    pg_databases:
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
    pg_default_service_dest: postgres
    pg_services:
      - { name: standby ,src_ip: "*" ,port: 5435 , dest: default ,selector: "[]" , backup: "[? pg_role == `primary`]" }
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.2/24
    pg_vip_interface: eth1
    pg_listen: '${ip},${vip},${lo}'
    patroni_ssl_enabled: true
    pgbouncer_sslmode: require
    pgbackrest_method: minio
    pg_libs: 'timescaledb, $libdir/passwordcheck, pg_stat_statements, auto_explain' # add passwordcheck extension to enforce strong password
    pg_default_roles:                 # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly]               ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite]  ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,expire_in: 7300                        ,comment: system superuser }
      - { name: replicator ,replication: true  ,expire_in: 7300 ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,expire_in: 7300 ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor] ,expire_in: 7300 ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_hba_rules:             # postgres host-based auth rules by default
      - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
      - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
      - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: ssl   ,title: 'replicator replication from localhost'}
      - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: ssl   ,title: 'replicator replication from intranet' }
      - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: ssl   ,title: 'replicator postgres db from intranet' }
      - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
      - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: ssl   ,title: 'monitor from infra host with password'}
      - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: cert  ,title: 'admin @ everywhere with ssl & cert'   }
      - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: ssl   ,title: 'pgbouncer read/write via local socket'}
      - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: ssl   ,title: 'read/write biz user via password'     }
      - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: ssl   ,title: 'allow etl offline tasks from intranet'}
    pgb_default_hba_rules:            # pgbouncer host-based authentication rules
      - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
      - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
      - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: ssl   ,title: 'monitor access via intranet with pwd' }
      - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: ssl   ,title: 'admin access via intranet with pwd'   }
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
      - {user: 'all'        ,db: all         ,addr: intra     ,auth: ssl   ,title: 'allow all user intra access with pwd' }

# OPTIONAL delayed cluster for pg-meta
pg-meta-delay:                    # delayed instance for pg-meta (1 hour ago)
  hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.10, pg_delay: 1h } }
  vars: { pg_cluster: pg-meta-delay }

Citus Distributed Cluster

Below is a declarative configuration for a four-node Citus distributed cluster:

all:
  children:
    pg-citus0: # citus coordinator, pg_group = 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus data node 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus data node 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus data node 3, with an extra replica
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }
  vars:                               # global parameters for all citus clusters
    pg_mode: citus                    # pgsql cluster mode: citus
    pg_shard: pg-citus                # citus shard name: pg-citus
    patroni_citus_db: meta            # citus distributed database name
    pg_dbsu_password: DBUser.Postgres # all dbsu password access for citus cluster
    pg_users: [ { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [ dbrole_admin ] } ]
    pg_databases: [ { name: meta ,extensions: [ { name: citus }, { name: postgis }, { name: timescaledb } ] } ]
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra        ,auth: ssl ,title: 'all user ssl access from intranet'  }

Redis Clusters

Below are declarative configuration examples for Redis primary-replica cluster, sentinel cluster, and Redis Cluster:

redis-ms: # redis classic primary & replica
  hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
  vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

redis-meta: # redis sentinel x 3
  hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
  vars:
    redis_cluster: redis-meta
    redis_password: 'redis.meta'
    redis_mode: sentinel
    redis_max_memory: 16MB
    redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
      - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

redis-test: # redis native cluster: 3m x 3s
  hosts:
    10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
    10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
  vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }

ETCD Cluster

Below is a declarative configuration example for a three-node Etcd cluster:

etcd: # dcs service for postgres/patroni ha consensus
  hosts:  # 1 node for testing, 3 or 5 for production
    10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
    10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
    10.10.10.12: { etcd_seq: 3 }  # three-member cluster keeps an odd voter count
  vars: # cluster level parameter override roles/etcd
    etcd_cluster: etcd  # mark etcd cluster name etcd
    etcd_safeguard: false # safeguard against purging
    etcd_clean: true # purge etcd during init process

MINIO (Silo) Cluster

Below is a declarative configuration example for a three-node Silo cluster. The inventory group and parameters retain the MINIO module’s compatibility names:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
  vars:
    minio_cluster: minio
    minio_type: silo
    minio_data: '/data{1...2}'          # use two disks per node
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # node name pattern
    haproxy_services:
      - name: minio                     # [required] service name, must be unique
        port: 9002                      # [required] service port, must be unique
        options:
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

3.3.1 - Inventory

Describe your infrastructure and clusters using declarative configuration files

Every Pigsty deployment corresponds to an Inventory that describes key properties of the infrastructure and database clusters.


Configuration File

Pigsty uses Ansible YAML configuration format by default, with a single YAML configuration file pigsty.yml as the inventory.

~/pigsty
  ^---- pigsty.yml   # <---- Default configuration file

You can directly edit this configuration file to customize your deployment, or use the configure wizard script provided by Pigsty to automatically generate an appropriate configuration file.


Configuration Structure

The inventory uses standard Ansible YAML configuration format, consisting of two parts: global parameters (all.vars) and multiple groups (all.children).

You can define new clusters in all.children and describe the infrastructure using global variables: all.vars, which looks like this:

all:                  # Top-level object: all
  vars: {...}         # Global parameters
  children:           # Group definitions
    infra:            # Group definition: 'infra'
      hosts: {...}        # Group members: 'infra'
      vars:  {...}        # Group parameters: 'infra'
    etcd:    {...}    # Group definition: 'etcd'
    pg-meta: {...}    # Group definition: 'pg-meta'
    pg-test: {...}    # Group definition: 'pg-test'
    redis-test: {...} # Group definition: 'redis-test'
    # ...

Cluster Definition

Each Ansible group may represent a cluster, which can be a node cluster, PostgreSQL cluster, Redis cluster, Etcd cluster, Silo cluster, etc.

A cluster definition consists of two parts: cluster members (hosts) and cluster parameters (vars). You can define cluster members in <cls>.hosts and describe the cluster using configuration parameters in <cls>.vars. Here’s an example of a 3-node high-availability PostgreSQL cluster definition:

all:
  children:    # Ansible group list
    pg-test:   # Ansible group name
      hosts:   # Ansible group instances (cluster members)
        10.10.10.11: { pg_seq: 1, pg_role: primary } # Host 1
        10.10.10.12: { pg_seq: 2, pg_role: replica } # Host 2
        10.10.10.13: { pg_seq: 3, pg_role: offline } # Host 3
      vars:    # Ansible group variables (cluster parameters)
        pg_cluster: pg-test

Cluster-level vars (cluster parameters) override global parameters, and instance-level vars override both cluster parameters and global parameters.


Splitting Configuration

If your deployment is large or you want to better organize configuration files, you can split the inventory into multiple files for easier management and maintenance.

inventory/
├── hosts.yml              # Host and cluster definitions
├── group_vars/
│   ├── all.yml            # Global default variables (corresponds to all.vars)
│   ├── infra.yml          # infra group variables
│   ├── etcd.yml           # etcd group variables
│   └── pg-meta.yml        # pg-meta cluster variables
└── host_vars/
    ├── 10.10.10.10.yml    # Specific host variables
    └── 10.10.10.11.yml

You can place cluster member definitions in the hosts.yml file and put cluster-level configuration parameters in corresponding files under the group_vars directory.


Switching Configuration

You can temporarily specify a different inventory file when running playbooks using the -i parameter.

./pgsql.yml -i another_config.yml
./infra.yml -i nginx_config.yml

Additionally, Ansible supports multiple configuration methods. You can use local yaml|ini configuration files, or use CMDB and any dynamic configuration scripts as configuration sources.

In Pigsty, we specify pigsty.yml in the same directory as the default inventory through ansible.cfg in the Pigsty home directory. You can modify it as needed.

[defaults]
inventory = pigsty.yml

Additionally, Pigsty supports using a CMDB metabase to store the inventory, facilitating integration with existing systems.

3.3.2 - Configure

Use the configure script to automatically generate recommended configuration files based on your environment.

Pigsty provides a configure script as a configuration wizard that automatically generates an appropriate pigsty.yml configuration file based on your current environment.

This is an optional script: if you already understand how to configure Pigsty, you can directly edit the pigsty.yml configuration file and skip the wizard.


Quick Start

Enter the pigsty source home directory and run ./configure to automatically start the configuration wizard. Without any arguments, it defaults to the meta single-node configuration template:

cd ~/pigsty
./configure          # Interactive configuration wizard, auto-detect environment and generate config

This command will use the selected template as a base, detect the current node’s IP address and region, and generate a pigsty.yml configuration file suitable for the current environment.

demo/configure.cast

Features

The configure script performs the following adjustments based on environment and input, generating pigsty.yml in the Pigsty directory by default.

  • Detects the current node IP address; if multiple IPs exist, prompts the user to input a primary IP address as the node’s identity
  • Uses the IP address to replace the placeholder 10.10.10.10 in the configuration template and sets it as the admin_ip parameter value
  • Detects the current region, setting region to default (global default repos) or china (using Chinese mirror repos)
  • For micro instances (vCPU < 4), uses the tiny parameter template for node_tune and pg_conf to optimize resource usage
  • If -v is specified, switches pg_version and pg18-* package-group aliases in the template to that major version; fixed-kernel templates mssql, polar, and pg19 are excluded from this replacement
  • If -g is specified, replaces default passwords recognized by the configuration wizard with randomly generated strong passwords; review uncovered values against the Default Credentials Checklist (strongly recommended)
  • When PG major version ≥ 17, prioritizes the built-in C.UTF-8 locale, or the OS-supported C.UTF-8
  • Checks if the core dependency ansible for deployment is available in the current environment
  • Also checks if the deployment target node is SSH-reachable and can execute commands with sudo (-s to skip)

Usage Examples

# Basic usage
./configure                       # Interactive configuration wizard
./configure -i 10.10.10.10        # Specify primary IP address

# Specify configuration template
./configure -c meta               # Use default single-node template (default)
./configure -c rich               # Use feature-rich single-node template
./configure -c slim               # Use minimal template (PGSQL + ETCD only)
./configure -c ha/full            # Use 4-node HA sandbox template
./configure -c ha/trio            # Use 3-node HA template
./configure -c supabase           # Use Supabase self-hosted template
./configure -c app/immich         # Use Immich photo-management template

# Specify PostgreSQL version
./configure -v 18                 # Use PostgreSQL 18
./configure -v 16                 # Use PostgreSQL 16
./configure -c rich -v 15         # rich template + PG 15
./configure -c pg19               # Use the dedicated PostgreSQL 19 Beta template

# Region and proxy
./configure -r china              # Use Chinese mirrors
./configure -r europe             # Use European mirrors
./configure -x                    # Import current proxy environment variables

# Skip and automation
./configure -s                    # Skip IP detection, keep placeholder
./configure -n -i 10.10.10.10     # Non-interactive mode with specified IP
./configure -c ha/full -s         # 4-node template, skip IP replacement

# Security enhancement
./configure -g                    # Generate random passwords
./configure -c meta -g -i 10.10.10.10  # Complete production configuration

# Specify output and SSH port
./configure -o prod.yml           # Output to prod.yml
./configure -p 2222               # Use SSH port 2222

Command Arguments

./configure
    [-c|--conf <template>]      # Configuration template name (meta|rich|slim|ha/full|...)
    [-i|--ip <ipaddr>]          # Specify primary IP address
    [-v|--version <pgver>]      # PostgreSQL major version (14|15|16|17|18|19)
    [-r|--region <region>]      # Upstream software repo region (default|china|europe)
    [-o|--output <file>]        # Output configuration file path (default: pigsty.yml)
    [-s|--skip]                 # Skip IP address detection and replacement
    [-x|--proxy]                # Import proxy settings from environment variables
    [-n|--non-interactive]      # Non-interactive mode (don't ask any questions)
    [-p|--port <port>]          # Specify SSH port
    [-g|--generate]             # Generate random passwords
    [-h|--help]                 # Display help information

Argument Details

ArgumentDescription
-c, --confGenerate config from conf/<template>.yml, supports subdirectories like ha/full
-i, --ipReplace placeholder 10.10.10.10 in config template with specified IP
-v, --versionSpecify PostgreSQL major version (14-19); PG19 is Beta, so prefer the dedicated pg19 template
-r, --regionSet software repo mirror region: default, china (Chinese mirrors), europe (European)
-o, --outputOutput path, default pigsty.yml; relative paths use Pigsty home, absolute paths are used as given
-s, --skipSkip IP probing, target SSH/Sudo checks, and effective IP replacement; keep 10.10.10.10
-x, --proxyWrite current environment proxy variables (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY) to config
-n, --non-interactiveNon-interactive mode; a single/demo IP is auto-selected, while ambiguous multi-IP hosts require -i
-p, --portSSH port used by readiness checks only; it does not write ansible_port into the generated config
-g, --generateGenerate random values for passwords in config file, improving security (strongly recommended)

Execution Flow

The configure script executes detection and configuration in the following order:

┌─────────────────────────────────────────────────────────────┐
│                  configure Execution Flow                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. check_region          Detect network region (GFW check) │
│         ↓                                                   │
│  2. check_version         Validate PostgreSQL version       │
│         ↓                                                   │
│  3. check_kernel          Detect OS kernel (Linux/Darwin)   │
│         ↓                                                   │
│  4. check_machine         Detect CPU arch (x86_64/aarch64)  │
│         ↓                                                   │
│  5. check_package_manager Detect package manager (dnf/yum/apt) │
│         ↓                                                   │
│  6. check_vendor_version  Detect OS distro and version      │
│         ↓                                                   │
│  7. check_sudo            Detect passwordless sudo          │
│         ↓                                                   │
│  8. check_ssh             Detect passwordless SSH to self   │
│         ↓                                                   │
│  9. check_proxy_env       Handle proxy environment vars     │
│         ↓                                                   │
│ 10. check_ipaddr          Detect/input primary IP address   │
│         ↓                                                   │
│ 11. check_admin           Validate admin SSH + Sudo access  │
│         ↓                                                   │
│ 12. check_conf            Select configuration template     │
│         ↓                                                   │
│ 13. check_config          Generate configuration file       │
│         ↓                                                   │
│ 14. check_utils           Check if Ansible etc. installed   │
│         ↓                                                   │
│     ✓ Configuration complete, output pigsty.yml             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Automatic Behaviors

Region Detection

The script automatically detects the network environment to determine if you’re in mainland China (behind GFW):

# The actual probe uses HTTPS with a two-second total timeout
curl -I -s --max-time 2 https://www.google.com
  • If Google is reachable, uses the region: default repositories
  • If Google is unreachable but https://pigsty.cc is reachable, sets region: china
  • If neither endpoint is reachable, falls back to region: default and emits an internet-unreachable warning
  • Can manually specify region via -r argument

IP Address Handling

The script determines the primary IP address in the following priority:

  1. Command line argument: If IP is specified via -i, use it directly
  2. Single IP detection: If the current node has only one IP, use it automatically
  3. Demo IP detection: If 10.10.10.10 is detected, select it automatically (for sandbox environments)
  4. Interactive input: When multiple IPs exist, prompt user to choose or input
[WARN] Multiple IP address candidates found:
    (1) 192.168.1.100   inet 192.168.1.100/24 scope global eth0
    (2) 10.10.10.10     inet 10.10.10.10/24 scope global eth1
[ IN ] INPUT primary_ip address (of current meta node, e.g 10.10.10.10):
=> 10.10.10.10

Low-End Hardware Optimization

When fewer than 4 CPU cores are detected (1-3 cores), the script automatically adjusts configuration:

[WARN] replace oltp template with tiny due to cpu < 4

This ensures smooth operation on low-spec virtual machines.

Locale Settings

The script automatically enables C.UTF-8 as the default locale when:

  • PostgreSQL version ≥ 17 (built-in Locale Provider support)
  • Or the current system supports C.UTF-8 / C.utf8 locale
pg_locale: C.UTF-8
pg_lc_collate: C.UTF-8
pg_lc_ctype: C.UTF-8

China Region Special Handling

When region is set to china, the script automatically:

  • Enables docker_registry_mirrors Docker mirror acceleration
  • Enables PIP_MIRROR_URL Python mirror acceleration

Password Generation

When using the -g argument, the script generates 24-character random strings for the following passwords:

Password ParameterDescription
grafana_admin_passwordGrafana admin password
pg_admin_passwordPostgreSQL admin password
pg_monitor_passwordPostgreSQL monitor user password
pg_replication_passwordPostgreSQL replication user password
patroni_passwordPatroni API password
haproxy_admin_passwordHAProxy admin password
minio_secret_keySilo Root Secret
etcd_root_passwordETCD Root password

It also replaces the following placeholder passwords:

  • DBUser.Meta → random password
  • DBUser.Viewer → random password
  • S3User.Backup → random password
  • S3User.Meta → random password
  • S3User.Data → random password
  • DBUser.Supa → random password
  • Vibe.Coding → random password
$ ./configure -g
[INFO] generating random passwords...
    grafana_admin_password   : xK9mL2nP4qR7sT1vW3yZ5bD8
    pg_admin_password        : aB3cD5eF7gH9iJ1kL2mN4oP6
    ...
[INFO] random passwords generated, check and save them

Configuration Templates

The script reads templates from conf/. The value of -c is a path relative to that directory without the .yml suffix, such as ha/full or app/immich.

Core Templates

TemplateDescription
metaDefault template: Single-node installation with INFRA + NODE + ETCD + PGSQL
richFeature-rich version: Includes almost all extensions, Silo, local repo
slimMinimal version: PostgreSQL + ETCD only, no monitoring infrastructure
fatComplete version: rich base with more extensions installed
pgsqlPure PostgreSQL template
pg19Single-node PostgreSQL 19 Beta evaluation template
infraPure infrastructure template

HA Templates (ha/)

TemplateDescription
ha/dual2-node HA cluster
ha/trio3-node HA cluster
ha/full4-node complete sandbox environment
ha/safeSecurity-hardened HA configuration
ha/octoCompact 8-node HA simulation
ha/simu20-node production simulation environment
ha/citus13-node Citus distributed cluster

Application Templates

TemplateDescription
supabaseSupabase self-hosted configuration
app/difyDify AI platform configuration
app/odooOdoo ERP configuration
app/electricElectric sync engine configuration
app/insforgeInsforge backend platform configuration
app/hindsightHindsight application configuration
app/teableTeable table database configuration
app/mattermostMattermost collaboration platform configuration
app/maybeMaybe finance application configuration
app/registryDocker Registry configuration
app/immichImmich photo and video management
app/jumpserverJumpServer bastion host

Special Kernel Templates

TemplateDescription
ivoryIvorySQL: Oracle-compatible PostgreSQL
mssqlBabelfish: SQL Server-compatible PostgreSQL
polarPolarDB: Alibaba Cloud open-source distributed PostgreSQL
ha/citusCitus: Distributed PostgreSQL HA cluster
mysqlOpenHalo: MySQL protocol-compatible PostgreSQL
pgtdePercona PostgreSQL Server: transparent encryption
orioleOrioleDB: Next-generation storage engine
agensAgensGraph: graph database kernel
pgedgepgEdge: distributed PostgreSQL kernel
mongoMongoDB-compatible stack template

Demo and Build Templates

TemplateDescription
vibeVibe Coding development environment
dockerRun Pigsty inside a Docker container
demo/bareMinimal readable single-node example
demo/elFull parameter example for EL distributions
demo/debianFull parameter example for Debian/Ubuntu
demo/demoMulti-module demo environment
demo/kernelTen-node database-kernel matrix
demo/redisRedis replica, Sentinel, and native Cluster demo
demo/minioMulti-node, multi-drive Silo demo (source default)
demo/kafkaKafka KRaft development and secure-cluster demo
demo/mysqlNative MySQL 8.4 pilot demo
demo/remoteRemote PostgreSQL/RDS monitoring example
demo/saasLegacy single-node SaaS component bundle
demo/woolSmall cloud-instance example for China
build/ossCross-distribution open-source package build env
build/devThree-node development and build environment

Output Example

$ ./configure
configure pigsty v4.5.0 begin
[ OK ] region = china
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = rpm,dnf
[ OK ] vendor  = rocky (Rocky Linux)
[ OK ] version = 9 (9.5)
[ OK ] sudo = vagrant ok
[ OK ] ssh = [email protected] ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.193	    inet 192.168.121.193/24 brd 192.168.121.255 scope global dynamic noprefixroute eth0
    (2) 10.10.10.10	    inet 10.10.10.10/24 brd 10.10.10.255 scope global noprefixroute eth1
[ OK ] primary_ip = 10.10.10.10 (from demo)
[ OK ] admin = [email protected] ok
[ OK ] mode = meta (el9)
[ OK ] locale  = C.UTF-8
[ OK ] ansible = ready
[ OK ] pigsty configured
[WARN] don't forget to check it and change passwords!
proceed with ./deploy.yml

Environment Variables

The script supports the following environment variables:

Environment VariableDescriptionDefault
PIGSTY_HOMEPigsty installation directory~/pigsty
METADB_URLMetabase connection URLservice=meta
HTTP_PROXYHTTP proxy-
HTTPS_PROXYHTTPS proxy-
ALL_PROXYUniversal proxy-
NO_PROXYProxy whitelistBuilt-in default

Notes

  1. Passwordless access: Before running configure, ensure the current user has passwordless sudo privileges and passwordless SSH to localhost. This can be automatically configured via the bootstrap script.

  2. IP address selection: Choose an internal IP as the primary IP address, not a public IP or 127.0.0.1.

  3. Password security: In production, always change default passwords in the configuration file. Use -g to randomize recognized credentials, then review the Default Credentials Checklist for remaining values.

  4. Configuration review: After the script completes, it’s recommended to review the generated pigsty.yml file to confirm the configuration meets expectations.

  5. Multiple executions: You can run configure multiple times to regenerate configuration; each run will overwrite the existing pigsty.yml.

  6. macOS limitations: When running on macOS, the script skips some Linux-specific checks and uses placeholder IP 10.10.10.10. macOS can only serve as an admin node.


FAQ

How to use a custom configuration template?

Place your configuration file in the conf/ directory, then specify it with the -c argument:

cp my-config.yml ~/pigsty/conf/myconf.yml
./configure -c myconf

How to generate different configurations for multiple clusters?

Use the -o argument to specify different output files:

./configure -c ha/full -o cluster-a.yml
./configure -c ha/trio -o cluster-b.yml

Then specify the configuration file when running playbooks:

./deploy.yml -i cluster-a.yml

How to handle multiple IPs in non-interactive mode?

You must explicitly specify the IP address using the -i argument:

./configure -n -i 10.10.10.10

How to keep the placeholder IP in the template?

Use the -s argument to skip IP replacement:

./configure -c ha/full -s   # Keep 10.10.10.10 placeholder

  • Inventory: Understand the Ansible inventory structure
  • Parameters: Understand Pigsty parameter hierarchy and priority
  • Templates: View all available configuration templates
  • Installation: Understand the complete installation process
  • Metabase: Use PostgreSQL as a dynamic configuration source

3.3.3 - Parameters

Fine-tune Pigsty customization using configuration parameters

In the inventory, you can use various parameters to fine-tune Pigsty customization. These parameters cover everything from infrastructure settings to database configuration.


Parameter List

According to the current source and parameter reference pages, Pigsty’s 10 official modules expose 373 public parameters for fine-grained control. See Reference - Parameter List for the complete list. The native MySQL 8.4 pilot module exposes 13 additional public parameters that are listed separately and excluded from this total.

ModuleGroupsParamsDescription
PGSQL9124PostgreSQL high-availability cluster configuration
INFRA1073Software repositories and Victoria observability infrastructure
NODE1173Node initialization, system tuning, and operations baseline
ETCD213ETCD cluster and removal protection parameters
MINIO222Silo deployment, observability, and removal parameters
REDIS222Redis/Valkey deployment and removal parameters
DOCKER18Docker engine parameters
JUICE12JuiceFS instance and cache parameters
VIBE118Code/Jupyter/Node.js/Claude/Codex configuration
KAFKA218Kafka deployment and removal-protection parameters

Parameter Form

Parameters are key-value pairs that describe entities. The Key is a string, and the Value can be one of five types: boolean, string, number, array, or object.

all:                            # <------- Top-level object: all
  vars:
    admin_ip: 10.10.10.10       # <------- Global configuration parameter
  children:
    pg-meta:                    # <------- pg-meta group
      vars:
        pg_cluster: pg-meta     # <------- Cluster-level parameter
      hosts:
        10.10.10.10:            # <------- Host node IP
          pg_seq: 1
          pg_role: primary      # <------- Instance-level parameter

Parameter Priority

Parameters can be set at different levels with the following priority:

LevelLocationDescriptionPriority
CLI-e command line argumentPassed via command lineHighest (5)
Host/Instance<group>.hosts.<host>Parameters specific to a single hostHigher (4)
Group/Cluster<group>.varsParameters shared by hosts in group/clusterMedium (3)
Globalall.varsParameters shared by all hostsLower (2)
Default<roles>/default/main.ymlRole implementation defaultsLowest (1)

Here are some examples of parameter priority:

  • Use command line parameter -e grafana_clean=true when running playbooks to wipe Grafana data
  • Use instance-level parameter pg_role on host variables to override pg instance role
  • Use cluster-level parameter pg_cluster on group variables to override pg cluster name
  • Use global parameter node_ntp_servers on global variables to specify global NTP servers
  • If pg_version is not set, Pigsty will use the default value from the pgsql role implementation (default is 18)

Except for identity parameters, every parameter has an appropriate default value, so explicit setting is not required.


Identity Parameters

Identity parameters are special parameters that serve as entity ID identifiers, therefore they have no default values and must be explicitly set.

ModuleIdentity Parameters
PGSQLpg_cluster, pg_seq, pg_role, …
NODEnodename, node_cluster
ETCDetcd_cluster, etcd_seq
MINIOminio_cluster, minio_seq
REDISredis_cluster, redis_node, redis_instances
INFRAinfra_seq

The exception is etcd_cluster, which still defaults to etcd. Object storage minio_cluster no longer has a default and must be defined explicitly in each object-storage cluster’s variables. Do not place it in all.vars, or every host will be marked as a MINIO module member.

3.3.4 - Conf Templates

Use pre-made configuration templates to quickly generate configuration files adapted to your environment

In Pigsty, deployment blueprint details are defined by the inventory, which is the pigsty.yml configuration file. You can customize it through declarative configuration.

However, writing configuration files directly can be daunting for new users. To address this, we provide some ready-to-use configuration templates covering common usage scenarios.

Each template is a predefined pigsty.yml configuration file containing reasonable defaults suitable for specific scenarios.

You can choose a template as your customization starting point, then modify it as needed to meet your specific requirements.


Using Templates

Pigsty provides the configure script as an optional configuration wizard that generates an inventory with good defaults based on your environment and input.

Use ./configure -c <conf> to specify a configuration template, where <conf> is the path relative to the conf directory (the .yml suffix can be omitted).

./configure                     # Default to meta.yml configuration template
./configure -c meta             # Explicitly specify meta.yml single-node template
./configure -c rich             # Use feature-rich template with all extensions and Silo
./configure -c slim             # Use minimal single-node template

# Use different database kernels
./configure -c pgsql            # Native PostgreSQL kernel, basic features (14~18)
./configure -c pg19             # PostgreSQL 19 Beta trial template
./configure -c mssql            # Babelfish kernel, SQL Server protocol compatible (17/18)
./configure -c polar            # PolarDB PG kernel, Aurora/RAC style (17)
./configure -c ivory            # IvorySQL kernel, Oracle syntax compatible (18)
./configure -c mysql            # OpenHalo kernel, MySQL compatible (14)
./configure -c pgtde            # Percona PostgreSQL Server transparent encryption (18)
./configure -c oriole           # OrioleDB kernel, OLTP enhanced (16~18)
./configure -c agens            # AgensGraph graph database kernel (17)
./configure -c pgedge           # pgEdge distributed database kernel (15~18, default 18)
./configure -c ha/citus         # Citus distributed HA PostgreSQL (14~18)
./configure -c supabase         # Supabase self-hosted configuration (15~18)

# Use multi-node HA templates
./configure -c ha/dual          # Use 2-node HA template
./configure -c ha/trio          # Use 3-node HA template
./configure -c ha/full          # Use 4-node HA template

If no template is specified, Pigsty defaults to the meta.yml single-node configuration template.


Template List

Main Templates

The following are single-node configuration templates for installing Pigsty on a single server:

TemplateDescription
meta.ymlDefault template, single-node PostgreSQL online installation
rich.ymlFeature-rich template with local repo, Silo, and more examples
slim.ymlMinimal template, PostgreSQL only without monitoring and infrastructure

Database Kernel Templates

Templates for various database management systems and kernels:

TemplateDescription
pgsql.ymlNative PostgreSQL kernel, basic features (14~18)
pg19.ymlPostgreSQL 19 Beta trial template
mssql.ymlBabelfish kernel, SQL Server protocol compatible (17/18)
polar.ymlPolarDB PG kernel, Aurora/RAC style (17)
ivory.ymlIvorySQL kernel, Oracle syntax compatible (18)
mysql.ymlOpenHalo kernel, MySQL compatible (14)
pgtde.ymlPercona PostgreSQL Server transparent encryption (18)
oriole.ymlOrioleDB kernel, OLTP enhanced (16~18)
agens.ymlAgensGraph graph database kernel (17)
pgedge.ymlpgEdge distributed database kernel (15~18, default 18)
supabase.ymlSupabase self-hosted configuration (15~18)

You can add more nodes later or use HA templates to plan your cluster from the start.


HA Templates

You can configure Pigsty to run on multiple nodes, forming a high-availability (HA) cluster:

TemplateDescription
dual.yml2-node semi-HA deployment
trio.yml3-node standard HA deployment
full.yml4-node standard deployment
safe.yml4-node security-enhanced deployment with delayed replica
octo.ymlCompact 8-node HA simulation
simu.yml20-node production environment simulation
ha/citus.ymlCitus distributed HA PostgreSQL (14~18)

Application Templates

You can use the following templates to run Docker applications/software:

TemplateDescription
supabase.ymlStart single-node Supabase
odoo.ymlStart Odoo ERP system
dify.ymlStart Dify AI workflow system
electric.ymlStart Electric sync engine
insforge.ymlStart Insforge backend platform
hindsight.ymlStart Hindsight application
mattermost.ymlStart Mattermost collaboration platform
teable.ymlStart Teable spreadsheet database
maybe.ymlStart Maybe finance app
registry.ymlStart Docker Registry

Demo Templates

Besides main templates, Pigsty provides a set of demo templates for different scenarios:

TemplateDescription
el.ymlFull-parameter config file for EL 8/9 systems
debian.ymlFull-parameter config file for Debian/Ubuntu systems
remote.ymlExample config for monitoring remote PostgreSQL clusters or RDS
redis.ymlRedis cluster example configuration
minio.yml4-node multi-drive Silo cluster example (source default)
kafka.ymlKafka dynamic KRaft example with a single-node dev cluster and a three-node secure cluster
mysql.ymlNative MySQL 8.4 single-node/three-node pilot example; distinct from OpenHalo conf/mysql.yml
demo.ymlConfiguration file for Pigsty public demo site
fat.ymlSingle-node config with local repo and full feature set
infra.ymlDeploy only the infrastructure modules
vibe.ymlVibe Coding / AI application development template
mongo.ymlFerretDB / MongoDB-compatible example
docker.ymlDocker application host template

Build Templates

The following configuration templates are for development and testing purposes:

TemplateDescription
build/oss.ymlOpen source build config for EL 9/10, Debian 12/13, Ubuntu 22.04/24.04/26.04
build/dev.ymlDevelopment and testing build config

3.3.5 - Use CMDB as Config Inventory

Use PostgreSQL as a CMDB metabase to store Ansible inventory.

Pigsty allows you to use a PostgreSQL metabase as a dynamic configuration source, replacing static YAML configuration files for more powerful configuration management capabilities.


Overview

CMDB (Configuration Management Database) is a method of storing configuration information in a database for management.

In Pigsty, the default configuration source is a static YAML file pigsty.yml, which serves as Ansible’s inventory.

This approach is simple and direct, but when infrastructure scales and requires complex, fine-grained management and external integration, a single static file becomes insufficient.

FeatureStatic YAML FileCMDB Metabase
QueryingManual search/grepSQL queries with any conditions, aggregation analysis
VersioningDepends on Git or manual backupDatabase transactions, audit logs, time-travel snapshots
Access ControlFile system permissions, coarse-grainedPostgreSQL fine-grained access control
Concurrent EditingRequires file locking or merge conflictsDatabase transactions naturally support concurrency
External IntegrationRequires YAML parsingStandard SQL interface, easy integration with any language
ScalabilityDifficult to maintain when file becomes too largeScales to physical limits
Dynamic GenerationStatic file, changes require manual applicationImmediate effect, real-time configuration changes

Pigsty provides the CMDB database schema in the sample database pg-meta.meta schema baseline definition.


How It Works

The core idea of CMDB is to replace the static configuration file with a dynamic script. Ansible supports using executable scripts as inventory, as long as the script outputs inventory data in JSON format. When you enable CMDB, Pigsty creates a dynamic inventory script named inventory.sh:

#!/bin/bash
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'

This script’s function is simple: every time Ansible needs to read the inventory, it queries configuration data from the PostgreSQL database’s pigsty.inventory view and returns it in JSON format.

The overall architecture is as follows:

flowchart LR
    conf["bin/inventory_conf"]
    tocmdb["bin/inventory_cmdb"]
    load["bin/inventory_load"]
    ansible["🚀 Ansible"]

    subgraph static["📄 Static Config Mode"]
        yml[("pigsty.yml")]
    end

    subgraph dynamic["🗄️ CMDB Dynamic Mode"]
        sh["inventory.sh"]
        cmdb[("PostgreSQL CMDB")]
    end

    conf -->|"switch"| yml
    yml -->|"load config"| load
    load -->|"write"| cmdb
    tocmdb -->|"switch"| sh
    sh --> cmdb

    yml --> ansible
    cmdb --> ansible

Data Model

The CMDB database schema is defined in files/cmdb.sql, with all objects in the pigsty schema.

Core Tables

TableDescriptionPrimary Key
pigsty.groupCluster/group definitions, corresponds to Ansible groupscls
pigsty.hostHost definitions, belongs to a group(cls, ip)
pigsty.global_varGlobal variables, corresponds to all.varskey
pigsty.group_varGroup variables, corresponds to all.children.<cls>.vars(cls, key)
pigsty.host_varHost variables, host-level variables(cls, ip, key)
pigsty.default_varDefault variable definitions, stores parameter metadatakey
pigsty.jobJob records table, records executed tasksid

Table Structure Details

Cluster Table pigsty.group

CREATE TABLE pigsty.group (
    cls     TEXT PRIMARY KEY,        -- Cluster name, primary key
    ctime   TIMESTAMPTZ DEFAULT now(), -- Creation time
    mtime   TIMESTAMPTZ DEFAULT now()  -- Modification time
);

Host Table pigsty.host

CREATE TABLE pigsty.host (
    cls    TEXT NOT NULL REFERENCES pigsty.group(cls),  -- Parent cluster
    ip     INET NOT NULL,                               -- Host IP address
    ctime  TIMESTAMPTZ DEFAULT now(),
    mtime  TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, ip)
);

Global Variables Table pigsty.global_var

CREATE TABLE pigsty.global_var (
    key   TEXT PRIMARY KEY,           -- Variable name
    value JSONB NULL,                 -- Variable value (JSON format)
    mtime TIMESTAMPTZ DEFAULT now()   -- Modification time
);

Group Variables Table pigsty.group_var

CREATE TABLE pigsty.group_var (
    cls   TEXT NOT NULL REFERENCES pigsty.group(cls),
    key   TEXT NOT NULL,
    value JSONB NULL,
    mtime TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, key)
);

Host Variables Table pigsty.host_var

CREATE TABLE pigsty.host_var (
    cls   TEXT NOT NULL,
    ip    INET NOT NULL,
    key   TEXT NOT NULL,
    value JSONB NULL,
    mtime TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, ip, key),
    FOREIGN KEY (cls, ip) REFERENCES pigsty.host(cls, ip)
);

Core Views

CMDB provides a series of views for querying and displaying configuration data:

ViewDescription
pigsty.inventoryCore view: Generates Ansible dynamic inventory JSON
pigsty.raw_configRaw configuration in JSON format
pigsty.global_configGlobal config view, merges defaults and global vars
pigsty.group_configGroup config view, includes host list and group vars
pigsty.host_configHost config view, merges group and host-level vars
pigsty.pg_clusterPostgreSQL cluster view
pigsty.pg_instancePostgreSQL instance view
pigsty.pg_databasePostgreSQL database definition view
pigsty.pg_usersPostgreSQL user definition view
pigsty.pg_servicePostgreSQL service definition view
pigsty.pg_hbaPostgreSQL HBA rules view
pigsty.pg_remoteRemote PostgreSQL instance view

pigsty.inventory is the core view that converts database configuration data to the JSON format required by Ansible:

SELECT text FROM pigsty.inventory;

Utility Scripts

Pigsty provides three convenience scripts for managing CMDB:

ScriptFunction
bin/inventory_loadLoad YAML configuration file into PostgreSQL database
bin/inventory_cmdbSwitch configuration source to CMDB (dynamic inventory script)
bin/inventory_confSwitch configuration source to static config file pigsty.yml

inventory_load

Parse and import YAML configuration file into CMDB:

bin/inventory_load                     # Load default pigsty.yml to default CMDB
bin/inventory_load -p /path/to/conf.yml  # Specify configuration file path
bin/inventory_load -d "postgres://..."   # Specify database connection URL
bin/inventory_load -n myconfig           # Specify configuration name

The script performs the following operations:

  1. Clears existing data in the pigsty schema
  2. Parses the YAML configuration file
  3. Writes global variables to the global_var table
  4. Writes cluster definitions to the group table
  5. Writes cluster variables to the group_var table
  6. Writes host definitions to the host table
  7. Writes host variables to the host_var table

Environment Variables

  • PIGSTY_HOME: Pigsty installation directory, defaults to ~/pigsty
  • METADB_URL: Database connection URL, defaults to service=meta

inventory_cmdb

Switch Ansible to use CMDB as the configuration source:

bin/inventory_cmdb

The script performs the following operations:

  1. Creates dynamic inventory script ${PIGSTY_HOME}/inventory.sh
  2. Modifies ansible.cfg to set inventory to inventory.sh

The generated inventory.sh contents:

#!/bin/bash
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'

inventory_conf

Switch back to using static YAML configuration file:

bin/inventory_conf

The script modifies ansible.cfg to set inventory back to pigsty.yml.


Usage Workflow

First-time CMDB Setup

  1. Initialize CMDB schema (usually done automatically during Pigsty installation):
psql -f ~/pigsty/files/cmdb.sql
  1. Load configuration to database:
bin/inventory_load
  1. Switch to CMDB mode:
bin/inventory_cmdb
  1. Verify configuration:
ansible all --list-hosts          # List all hosts
ansible-inventory --list          # View complete inventory

Query Configuration

After enabling CMDB, you can flexibly query configuration using SQL:

-- View all clusters
SELECT cls FROM pigsty.group;

-- View all hosts in a cluster
SELECT ip FROM pigsty.host WHERE cls = 'pg-meta';

-- View global variables
SELECT key, value FROM pigsty.global_var;

-- View cluster variables
SELECT key, value FROM pigsty.group_var WHERE cls = 'pg-meta';

-- View all PostgreSQL clusters
SELECT cls, name, pg_databases, pg_users FROM pigsty.pg_cluster;

-- View all PostgreSQL instances
SELECT cls, ins, ip, seq, role FROM pigsty.pg_instance;

-- View all database definitions
SELECT cls, datname, owner, encoding FROM pigsty.pg_database;

-- View all user definitions
SELECT cls, name, login, superuser FROM pigsty.pg_users;

Modify Configuration

You can modify configuration directly via SQL:

-- Add new cluster
INSERT INTO pigsty.group (cls) VALUES ('pg-new');

-- Add cluster variable
INSERT INTO pigsty.group_var (cls, key, value)
VALUES ('pg-new', 'pg_cluster', '"pg-new"');

-- Add host
INSERT INTO pigsty.host (cls, ip) VALUES ('pg-new', '10.10.10.20');

-- Add host variables
INSERT INTO pigsty.host_var (cls, ip, key, value)
VALUES ('pg-new', '10.10.10.20', 'pg_seq', '1'),
       ('pg-new', '10.10.10.20', 'pg_role', '"primary"');

-- Modify global variable
UPDATE pigsty.global_var SET value = '"new-value"' WHERE key = 'some_param';

-- Delete cluster (cascades to hosts and variables)
DELETE FROM pigsty.group WHERE cls = 'pg-old';

Changes take effect immediately without reloading or restarting any service.

Switch Back to Static Configuration

To switch back to static configuration file mode:

bin/inventory_conf

Advanced Usage

Export Configuration

Export CMDB configuration to YAML format:

psql service=meta -AXtwc "SELECT jsonb_pretty(jsonb_build_object('all', jsonb_build_object('children', children, 'vars', vars))) FROM pigsty.raw_config;"

Or use the ansible-inventory command:

ansible-inventory --list --yaml > exported_config.yml

Configuration Auditing

Track configuration changes using the mtime field:

-- View recently modified global variables
SELECT key, value, mtime FROM pigsty.global_var
ORDER BY mtime DESC LIMIT 10;

-- View changes after a specific time
SELECT * FROM pigsty.group_var
WHERE mtime > '2024-01-01'::timestamptz;

Integration with External Systems

CMDB uses standard PostgreSQL, making it easy to integrate with other systems:

  • Web Management Interface: Expose configuration data through REST API (e.g., PostgREST)
  • CI/CD Pipelines: Read/write database directly in deployment scripts
  • Monitoring & Alerting: Generate monitoring rules based on configuration data
  • ITSM Systems: Sync with enterprise CMDB systems

Considerations

  1. Data Consistency: After modifying configuration, you need to re-run the corresponding Ansible playbooks to apply changes to the actual environment

  2. Backup: Configuration data in CMDB is critical, ensure regular backups

  3. Permissions: Configure appropriate database access permissions for CMDB to avoid accidental modifications

  4. Transactions: When making batch configuration changes, perform them within a transaction for rollback on errors

  5. Connection Pooling: The inventory.sh script creates a new connection on each execution; if Ansible runs frequently, consider using connection pooling


Summary

CMDB is Pigsty’s advanced configuration management solution, suitable for scenarios requiring large-scale cluster management, complex queries, external integration, or fine-grained access control. By storing configuration data in PostgreSQL, you can fully leverage the database’s powerful capabilities to manage infrastructure configuration.

FeatureDescription
StoragePostgreSQL pigsty schema
Dynamic Inventoryinventory.sh script
Config Loadbin/inventory_load
Switch to CMDBbin/inventory_cmdb
Switch to YAMLbin/inventory_conf
Core Viewpigsty.inventory

3.4 - High Availability

Pigsty uses Patroni to implement PostgreSQL high availability, ensuring automatic failover when the primary becomes unavailable.

Overview

Pigsty’s PostgreSQL clusters come with out-of-the-box high availability, with core capabilities provided by Patroni, Etcd, and HAProxy.

When your PostgreSQL cluster has two or more instances, you automatically have self-healing database high availability without any additional configuration — as long as any instance in the cluster survives, the cluster can provide complete service. Clients only need to connect to any node in the cluster to get full service without worrying about primary-replica topology changes.

The default norm mode targets an RTO under 45 seconds. With asynchronous replication, pg_rpo=1MiB is Patroni’s sampled lag threshold for failover candidates, not a hard upper bound on actual data loss. Strict synchronous mode with crit.yml keeps acknowledged transactions at RPO = 0 during failover. These behaviors can be configured for your hardware and reliability requirements.

Pigsty includes built-in HAProxy load balancers for automatic traffic switching, providing DNS/VIP/LVS and other access methods for clients. Failover and switchover are almost transparent to the business side except for brief interruptions - applications don’t need to modify connection strings or restart. The minimal maintenance window requirements bring great flexibility and convenience: you can perform rolling maintenance and upgrades on the entire cluster without application coordination. The feature that hardware failures can wait until the next day to handle lets developers, operations, and DBAs sleep well during incidents.

pigsty-ha

Many large organizations and core institutions have been using Pigsty in production for extended periods. The largest deployment has 25K CPU cores and 220+ PostgreSQL ultra-large instances (64c / 512g / 3TB NVMe SSD). In this deployment case, dozens of hardware failures and various incidents occurred over five years, yet overall availability of over 99.999% was maintained.


What problems does High Availability solve?

  • Elevates availability in the data security C/IA model: RPO ≈ 0, RTO < 45s.
  • Gains seamless rolling maintenance capability, minimizing maintenance window requirements and bringing great convenience.
  • Hardware failures can self-heal immediately without human intervention, allowing operations and DBAs to sleep well.
  • Replicas can handle read-only requests, offloading primary load and fully utilizing resources.

What are the costs of High Availability?

  • Infrastructure dependency: HA requires DCS (etcd/zk/consul) for consensus.
  • Higher starting threshold: A meaningful HA deployment requires at least three nodes.
  • Extra resource consumption: Each new replica consumes additional resources, though this is usually not a major concern.
  • Significantly increased complexity: Backup costs increase significantly, requiring tools to manage complexity.

Limitations of High Availability

Since replication happens in real-time, all changes are immediately applied to replicas. Therefore, streaming replication-based HA solutions cannot handle data deletion or modification caused by human errors and software defects. (e.g., DROP TABLE or DELETE data) Such failures require using delayed clusters or performing point-in-time recovery using previous base backups and WAL archives.

Configuration StrategyRTORPO
Standalone + Nothing Data permanently lost, unrecoverable All data lost
Standalone + Base Backup Depends on backup size and bandwidth (hours) Lose data since last backup (hours to days)
Standalone + Base Backup + WAL Archive Depends on backup size and bandwidth (hours) Lose unarchived data (tens of MB)
Primary-Replica + Manual Failover ~10 minutes Lose data in replication lag (~100KB)
Primary-Replica + Auto Failover Within 1 minute Lose data in replication lag (~100KB)
Primary-Replica + Auto Failover + Sync Commit Within 1 minute No data loss

How It Works

In Pigsty, the high availability architecture works as follows:

  • PostgreSQL uses standard streaming replication to build physical replicas; replicas take over when the primary fails.
  • Patroni manages PostgreSQL server processes and handles high availability matters.
  • Etcd provides distributed configuration storage (DCS) capability and is used for leader election after failures.
  • Patroni relies on Etcd to reach cluster leader consensus and provides health check interfaces externally.
  • HAProxy exposes cluster services externally and uses Patroni health check interfaces to automatically distribute traffic to healthy nodes.
  • vip-manager provides an optional Layer 2 VIP, retrieves leader information from Etcd, and binds the VIP to the node where the cluster primary resides.

When the primary fails, a new round of leader election is triggered. The healthiest replica in the cluster (highest LSN position, minimum data loss) wins and is promoted to the new primary. After the winning replica is promoted, read-write traffic is immediately routed to the new primary. The impact of primary failure is brief write service unavailability: write requests will be blocked or fail directly from primary failure until new primary promotion, with unavailability typically lasting 15 to 30 seconds, usually not exceeding 1 minute.

When a replica fails, read-only traffic is routed to other replicas. Only when all replicas fail will read-only traffic ultimately be handled by the primary. The impact of replica failure is partial read-only query interruption: queries currently running on that replica will abort due to connection reset and be immediately taken over by other available replicas.

Failure detection is performed jointly by Patroni and Etcd. The cluster leader holds a lease; if it fails to renew the lease within its TTL (30 seconds in the default norm mode), the lease expires, triggering a Failover and a new election.

Even without any failures, you can proactively change the cluster primary through Switchover. In this case, write queries on the primary will experience a brief interruption and be immediately routed to the new primary. This operation is typically used for rolling maintenance/upgrades of database servers.

3.4.1 - RPO Trade-offs

Trade-off analysis for RPO (Recovery Point Objective), finding the optimal balance between availability and data loss.

RPO (Recovery Point Objective) defines the maximum amount of data loss allowed when the primary fails.

For scenarios where data integrity is critical, such as financial transactions, RPO = 0 is typically required, meaning no data loss is allowed.

However, stricter RPO targets come at a cost: higher write latency, reduced system throughput, and the risk that replica failures may cause primary unavailability. For typical scenarios, some data loss is acceptable in exchange for higher availability and performance.


Trade-offs

In asynchronous replication scenarios, there is typically some replication lag between replicas and the primary (depending on network and throughput, normally in the range of 10KB-100KB / 100µs-10ms). This means when the primary fails, replicas may not have fully synchronized with the latest data. If a failover occurs, the new primary may lose some unreplicated data.

The pg_rpo parameter is written to Patroni’s maximum_lag_on_failover and defaults to 1048576 (1MiB). It is the sampled lag threshold that permits a replica to participate as a failover candidate, not a hard upper bound on actual data loss.

When the cluster primary fails, if any replica has replication lag within this threshold, Pigsty will automatically promote that replica to be the new primary. However, when all replicas exceed this threshold, Pigsty will refuse [automatic failover] to prevent data loss. Manual intervention is then required to decide whether to wait for the primary to recover (which may never happen) or accept the data loss and force-promote a replica.

Because the primary’s WAL position is not sampled continuously, the worst-case loss under asynchronous replication can also include WAL generated during the most recent ttl window (on average, roughly another loop_wait/2 of WAL). Configure this threshold with your workload’s write rate in mind. Increasing it improves the chance of automatic failover but also broadens candidate eligibility.

When you set pg_rpo = 0, Pigsty enables synchronous replication, ensuring the primary only returns write success after at least one replica has persisted the data. This configuration ensures zero replication lag but introduces significant write latency and reduces overall throughput.

flowchart LR
    A([Primary Failure]) --> B{Synchronous<br/>Replication?}

    B -->|No| C{Lag < RPO?}
    B -->|Yes| D{Sync Replica<br/>Available?}

    C -->|Yes| E[Lossy Auto Failover<br/>Sampled candidate lag is within threshold]
    C -->|No| F[Refuse Auto Failover<br/>Wait for Primary Recovery<br/>or Manual Intervention]

    D -->|Yes| G[Lossless Auto Failover<br/>RPO = 0]
    D -->|No| H{Strict Mode?}

    H -->|No| C
    H -->|Yes| F

    style A fill:#dc3545,stroke:#b02a37,color:#fff
    style E fill:#F0AD4E,stroke:#146c43,color:#fff
    style G fill:#198754,stroke:#146c43,color:#fff
    style F fill:#BE002F,stroke:#565e64,color:#fff

Protection Modes

Pigsty provides three protection modes to help users make trade-offs under different RPO requirements, similar to Oracle Data Guard protection modes.

Maximum Performance
  • Default mode, asynchronous replication, transactions commit with only local WAL persistence, no waiting for replicas, replica failures are completely transparent to the primary
  • Primary failure may lose unsent/unreceived WAL. The default sampled candidate-lag threshold is 1MiB, but this is not a hard upper bound on actual loss
  • Optimized for performance, suitable for typical business scenarios that tolerate minor data loss during failures
Maximum Availability
  • Configured with pg_rpo = 0, enables Patroni synchronous commit mode: synchronous_mode: true
  • Under normal conditions, waits for at least one replica confirmation, achieving zero data loss. When all sync replicas fail, automatically degrades to async mode to continue service
  • Balances data safety and service availability, recommended configuration for production critical business
Maximum Protection
  • Uses crit.yml template, enables Patroni strict synchronous mode: synchronous_mode: true / synchronous_mode_strict: true
  • When all sync replicas fail, primary refuses writes to prevent data loss, transactions must be persisted on at least one replica before returning success
  • Suitable for financial transactions, medical records, and other scenarios with extremely high data integrity requirements
NameMaximum PerformanceMaximum AvailabilityMaximum Protection
ReplicationAsynchronousSynchronousStrict Synchronous
Data LossPossible (replication lag)Zero normally, minor when degradedZero
Write LatencyLowestMedium (+1 network RTT)Medium (+1 network RTT)
ThroughputHighestReducedReduced
Replica Failure ImpactNoneAuto degrade, service continuesPrimary stops writes
RPOPossible loss; 1MiB default candidate threshold= 0 normally / possible loss after degradation= 0
Use CaseTypical business, performance firstCritical business, safety firstFinancial core, compliance first
ConfigurationDefault configpg_rpo = 0pg_conf: crit.yml

Implementation

The three protection modes differ in how two core Patroni parameters are configured: synchronous_mode and synchronous_mode_strict:

  • synchronous_mode: Whether Patroni enables synchronous replication. If enabled, check if synchronous_mode_strict enables strict synchronous mode.
  • synchronous_mode_strict = false: Default configuration, allows degradation to async mode when replicas fail, primary continues service (Maximum Availability)
  • synchronous_mode_strict = true: Degradation forbidden, primary stops writes until sync replica recovers (Maximum Protection)
Modesynchronous_modesynchronous_mode_strictReplication ModeReplica Failure Behavior
Max Performancefalse-AsyncNo impact
Max AvailabilitytruefalseSynchronousAuto degrade to async
Max ProtectiontruetrueStrict SynchronousPrimary refuses writes

Typically, you only need to set the pg_rpo parameter to 0 to enable the synchronous_mode switch, activating Maximum Availability mode. If you use pg_conf = crit.yml template, it additionally enables the synchronous_mode_strict strict mode switch, activating Maximum Protection mode. Additionally, you can enable watchdog to fence the primary directly during node/Patroni freeze scenarios instead of degrading, achieving behavior equivalent to Oracle Maximum Protection mode.

You can also directly configure these Patroni parameters as needed. Refer to Patroni and PostgreSQL documentation to achieve stronger data protection, such as:

  • Specify the synchronous replica list, configure more sync replicas to improve disaster tolerance, use quorum synchronous commit, or even require all replicas to perform synchronous commit.
  • Configure synchronous_commit: 'remote_apply' to strictly ensure primary-replica read-write consistency. (Oracle Maximum Protection mode is equivalent to remote_write)

Recommendations

Maximum Performance mode (asynchronous replication) is the default mode used by Pigsty and is sufficient for the vast majority of workloads. It tolerates some loss during a failure in exchange for higher throughput and availability. In this mode, pg_rpo adjusts the sampled lag threshold for failover candidates; actual worst-case loss also depends on write rate, ttl, and sampling timing.

Maximum Availability mode (synchronous replication) is suitable for scenarios with high data-integrity requirements. Acknowledged transactions have zero loss while a synchronous replica is healthy, but the cluster can degrade when all synchronous replicas are unavailable. In this mode, a minimum of two-node PostgreSQL cluster (one primary, one replica) is required. Set pg_rpo to 0 to enable this mode.

Maximum Protection mode (strict synchronous replication) is suitable for financial transactions, medical records, and other scenarios with extremely high data integrity requirements. We recommend using at least a three-node cluster (one primary, two replicas), because with only two nodes, if the replica fails, the primary will stop writes, causing service unavailability, which reduces overall system reliability. With three nodes, if only one replica fails, the primary can continue to serve.

3.4.2 - Failure Model

Detailed analysis of worst-case, best-case, and average RTO calculation logic and results across three classic failure detection/recovery paths

Patroni failures can be classified into 10 categories by failure target, and further consolidated into five categories based on detection path, which are detailed in this section.

#Failure ScenarioDescriptionFinal Path
1PG process crashcrash, OOM killedActive Detection
2PG connection refusedmax_connectionsActive Detection
3PG zombieProcess alive but unresponsiveActive Detection (timeout)
4Patroni process crashkill -9, OOMPassive Detection
5Patroni zombieProcess alive but stuckWatchdog
6Node downPower outage, hardware failurePassive Detection
7Node zombieIO hang, CPU starvationWatchdog
8Primary ↔ DCS network failureFirewall, switch failureNetwork Partition
9Storage failureDisk failure, disk full, mount failureActive Detection or Watchdog
10Manual switchoverSwitchover/FailoverManual Trigger

However, for RTO calculation purposes, all failures ultimately converge to two paths. This section explores the upper bound, lower bound, and average RTO for these two scenarios.

flowchart LR
    A([Primary Failure]) --> B{Patroni<br/>Detected?}

    B -->|PG Crash| C[Attempt Local Restart]
    B -->|Node Down| D[Wait TTL Expiration]

    C -->|Success| E([Local Recovery])
    C -->|Fail/Timeout| F[Release Leader Lock]

    D --> F
    F --> G[Replica Election]
    G --> H[Execute Promote]
    H --> I[HAProxy Detects]
    I --> J([Service Restored])

    style A fill:#dc3545,stroke:#b02a37,color:#fff
    style E fill:#198754,stroke:#146c43,color:#fff
    style J fill:#198754,stroke:#146c43,color:#fff

3.4.2.1 - Model of Patroni Passive Failure

Failover path triggered by node crash causing leader lease expiration and cluster election
infographic list-row-simple-horizontal-arrow
data

  desc Lease Expiration Stages
  items
    - label Lease Expiration
    - label Replica Detect
    - label Elect & Promote
    - label Haproxy Up
theme light
  palette antv

RTO Timeline

tooltip: { trigger: axis, axisPointer: { type: shadow }, formatter: $fn:fmt }
legend: { top: 0, itemGap: 12, data: [Lease Expiration, Replica Detection, Lock Contest & Promote, Health Check] }
grid: { left: 64, right: 24, bottom: 32, top: 40 }
xAxis: { type: value, name: Seconds, nameLocation: end, max: 160, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: true, lineStyle: { type: dashed, opacity: 0.5 } }, minorTick: { show: true, splitNumber: 5 }, minorSplitLine: { show: true, lineStyle: { type: dotted, opacity: 0.2 } } }
yAxis: { type: category, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: false }, axisLabel: { fontSize: 10, fontFamily: monospace }, data: [wide-max, wide-avg, wide-min, "", safe-max, safe-avg, safe-min, "", norm-max, norm-avg, norm-min, "", fast-max, fast-avg, fast-min] }
series:
  - { name: Lease Expire, type: bar, stack: main, barWidth: 20, z: 2, emphasis: { focus: series }, itemStyle: { color: "#e15759" }, data: [120, 110, 100, "-", 60, 55, 50, "-", 30, 27, 25, "-", 20, 17, 15] }
  - { name: Replica Detect, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#edc949" }, data: [20, 10, 0, "-", 10, 5, 0, "-", 5, 3, 0, "-", 5, 3, 0] }
  - { name: Elect & Promote, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#59a14f" }, data: [2, 1, 0, "-", 2, 1, 0, "-", 2, 1, 0, "-", 2, 1, 0] }
  - { name: HAProxy Check, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#4e79a7" }, data: [8, 6, 4, "-", 6, 5, 3, "-", 4, 3, 2, "-", 2, 2, 1] }
  - { name: Total RTO, type: bar, barGap: "-100%", barWidth: 20, z: 1, itemStyle: { color: "#888", opacity: 0 }, emphasis: { itemStyle: { opacity: 0 } }, data: [150, 127, 104, "-", 78, 66, 53, "-", 41, 34, 27, "-", 29, 23, 16] }
  - { name: RTO Budget, type: bar, barGap: "-100%", barWidth: 20, z: 0, itemStyle: { color: "rgba(0,0,0,0.08)" }, emphasis: { itemStyle: { color: "rgba(0,0,0,0.12)" } }, data: [150, 150, 150, "-", 90, 90, 90, "-", 45, 45, 45, "-", 30, 30, 30] }

Failure Model

PhaseBestWorstAverageDescription
Lease Expirationttl - loopttlttl - loop/2Best: crash just before refresh
Worst: crash right after refresh
Replica Detect0looploop / 2Best: exactly at check point
Worst: just missed check point
Election Promote021Best: direct lock and promote
Worst: API timeout + Promote
HAProxy Check(rise-1) × fastinter(rise-1) × fastinter + inter(rise-1) × fastinter + inter/2Best: state change before check
Worst: state change right after check

Key Difference Between Passive and Active Failover:

ScenarioPatroni StatusLease HandlingPrimary Wait Time
Active Failover (PG crash)Alive, healthyActively tries to restart PG, releases lease on timeoutprimary_start_timeout
Passive Failover (Node crash)Dies with nodeCannot actively release, must wait for TTL expirationttl

In passive failover scenarios, Patroni dies along with the node and cannot actively release the Leader Key. The lease in DCS can only trigger cluster election after TTL naturally expires.


Timeline Analysis

Phase 1: Lease Expiration

The Patroni primary refreshes the Leader Key every loop_wait cycle, resetting TTL to the configured value.

Timeline:
     t-loop        t          t+ttl-loop    t+ttl
       |           |              |           |
    Last Refresh  Failure      Best Case   Worst Case
       |←── loop ──→|              |           |
       |←──────────── ttl ─────────────────────→|
  • Best case: Failure occurs just before lease refresh (elapsed loop since last refresh), remaining TTL = ttl - loop
  • Worst case: Failure occurs right after lease refresh, must wait full ttl
  • Average case: ttl - loop/2
Texpire={ttlloopBestttlloop/2AveragettlWorstT_{expire} = \begin{cases} ttl - loop & \text{Best} \\ ttl - loop/2 & \text{Average} \\ ttl & \text{Worst} \end{cases}

Phase 2: Replica Detection

Replicas wake up on loop_wait cycles and check the Leader Key status in DCS.

Timeline:
    Lease Expired   Replica Wakes
       |            |
       |←── 0~loop ─→|
  • Best case: Replica happens to wake when lease expires, wait 0
  • Worst case: Replica just entered sleep when lease expires, wait loop
  • Average case: loop/2
Tdetect={0Bestloop/2AverageloopWorstT_{detect} = \begin{cases} 0 & \text{Best} \\ loop/2 & \text{Average} \\ loop & \text{Worst} \end{cases}

Phase 3: Lock Contest & Promote

When replicas detect Leader Key expiration, they start the election process. The replica that acquires the Leader Key executes pg_ctl promote to become the new primary.

  1. Via REST API, parallel queries to check each replica’s replication position, typically 10ms, hardcoded 2s timeout.
  2. Compare WAL positions to determine the best candidate, replicas attempt to create Leader Key (CAS atomic operation)
  3. Execute pg_ctl promote to become primary (very fast, typically negligible)
Election Flow:
  ReplicaA ──→ Query replication position ──→ Compare ──→ Contest lock ──→ Success
  ReplicaB ──→ Query replication position ──→ Compare ──→ Contest lock ──→ Fail
  • Best case: Single replica or immediate lock acquisition and promotion, constant overhead 0.1s
  • Worst case: DCS API call timeout: 2s
  • Average case: 1s constant overhead
Telect={0.1Best1Average2WorstT_{elect} = \begin{cases} 0.1 & \text{Best} \\ 1 & \text{Average} \\ 2 & \text{Worst} \end{cases}

Phase 4: Health Check

HAProxy detects the new primary online, requiring rise consecutive successful health checks.

Detection Timeline:
  New Primary    First Check   Second Check  Third Check (UP)
     |          |           |           |
     |←─ 0~inter ─→|←─ fast ─→|←─ fast ─→|
  • Best case: New primary promoted just before check, (rise-1) × fastinter
  • Worst case: New primary promoted right after check, (rise-1) × fastinter + inter
  • Average case: (rise-1) × fastinter + inter/2
Thaproxy={(rise1)×fastinterBest(rise1)×fastinter+inter/2Average(rise1)×fastinter+interWorstT_{haproxy} = \begin{cases} (rise-1) \times fastinter & \text{Best} \\ (rise-1) \times fastinter + inter/2 & \text{Average} \\ (rise-1) \times fastinter + inter & \text{Worst} \end{cases}

RTO Formula

Sum all phase times to get total RTO:

Best Case

RTOmin=ttlloop+0.1+(rise1)×fastinterRTO_{min} = ttl - loop + 0.1 + (rise-1) \times fastinter

Average Case

RTOavg=ttl+1+inter/2+(rise1)×fastinterRTO_{avg} = ttl + 1 + inter/2 + (rise-1) \times fastinter

Worst Case

RTOmax=ttl+loop+2+inter+(rise1)×fastinterRTO_{max} = ttl + loop + 2 + inter + (rise-1) \times fastinter

Model Calculation

Substitute the four RTO model parameters into the formulas above:

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

Four Mode Calculation Results (unit: seconds, format: min / avg / max)

Phasefastnormsafewide
Lease Expiration15 / 17 / 2025 / 27 / 3050 / 55 / 60100 / 110 / 120
Replica Detection0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
Lock Contest & Promote0 / 1 / 20 / 1 / 20 / 1 / 20 / 1 / 2
Health Check1 / 2 / 22 / 3 / 43 / 5 / 64 / 6 / 8
Total16 / 23 / 2927 / 34 / 4153 / 66 / 78104 / 127 / 150

3.4.2.2 - Model of Patroni Active Failure

PostgreSQL primary process crashes while Patroni stays alive and attempts restart, triggering failover after timeout
infographic list-row-simple-horizontal-arrow
data
  desc When Patroni is healthy but PostgreSQL crashes
  items
    - label Crash Found
    - label Restart Timeout
    - label Replica Detect
    - label Elect Promote
    - label HAProxy Check
theme light
  palette antv

RTO Timeline

tooltip: { trigger: axis, axisPointer: { type: shadow }, formatter: $fn:fmt }
legend: { top: 0, itemGap: 12, data: [ Crash Found, Restart Timeout, Replica Detection, Elect Promote, HAProxy Check] }
grid: { left: 64, right: 24, bottom: 32, top: 40 }
xAxis: { type: value, name: Seconds, nameLocation: end, max: 160, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: true, lineStyle: { type: dashed, opacity: 0.5 } }, minorTick: { show: true, splitNumber: 5 }, minorSplitLine: { show: true, lineStyle: { type: dotted, opacity: 0.2 } } }
yAxis: { type: category, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: false }, axisLabel: { fontSize: 10, fontFamily: monospace }, data: [wide-max, wide-avg, wide-min, "", safe-max, safe-avg, safe-min, "", norm-max, norm-avg, norm-min, "", fast-max, fast-avg, fast-min] }
series:
  - { name: Crash Found, type: bar, stack: main, barWidth: 20, z: 2, emphasis: { focus: series }, itemStyle: { color: "#b07aa1" }, data: [20, 10, 0, "-", 10, 5, 0, "-", 5, 3, 0, "-", 5, 3, 0] }
  - { name: Restart Timeout, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#f28e2c" }, data: [95, 95, 0, "-", 45, 45, 0, "-", 25, 25, 0, "-", 15, 15, 0] }
  - { name: Replica Detect, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#edc949" }, data: [20, 10, 0, "-", 10, 5, 0, "-", 5, 3, 0, "-", 5, 3, 0] }
  - { name: Elect Promote, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#59a14f" }, data: [2, 1, 0, "-", 2, 1, 0, "-", 2, 1, 0, "-", 2, 1, 0] }
  - { name: HAProxy Check, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#4e79a7" }, data: [8, 6, 4, "-", 6, 5, 3, "-", 4, 3, 2, "-", 2, 2, 1] }
  - { name: RTO Total, type: bar, barGap: "-100%", barWidth: 20, z: 1, itemStyle: { color: "#888", opacity: 0 }, emphasis: { itemStyle: { opacity: 0 } }, data: [145, 122, 4, "-", 73, 61, 3, "-", 41, 35, 2, "-", 29, 24, 1] }
  - { name: RTO Budget, type: bar, barGap: "-100%", barWidth: 20, z: 0, itemStyle: { color: "rgba(0,0,0,0.08)" }, emphasis: { itemStyle: { color: "rgba(0,0,0,0.12)" } }, data: [150, 150, 150, "-", 90, 90, 90, "-", 45, 45, 45, "-", 30, 30, 30] }

Failure Model

ItemBestWorstAverageDescription
Crash Found0looploop/2Best: PG crashes right before check
Worst: PG crashes right after check
Restart Timeout0startstartBest: PG recovers instantly
Worst: Wait full start timeout before releasing lease
Replica Detect0looploop/2Best: Right at check point
Worst: Just missed check point
Elect Promote021Best: Acquire lock and promote directly
Worst: API timeout + Promote
HAProxy Check(rise-1) × fastinter(rise-1) × fastinter + inter(rise-1) × fastinter + inter/2Best: State changes before check
Worst: State changes right after check

Key Difference Between Active and Passive Failure:

ScenarioPatroni StatusLease HandlingMain Wait Time
Active Failure (PG crash)Alive, healthyActively tries to restart PG, releases lease after timeoutprimary_start_timeout
Passive Failure (node down)Dies with nodeCannot actively release, must wait for TTL expiryttl

In active failure scenarios, Patroni remains alive and can actively detect PG crash and attempt restart. If restart succeeds, service self-heals; if timeout expires without recovery, Patroni actively releases the Leader Key, triggering cluster election.


Timing Analysis

Phase 1: Failure Detection

Patroni checks PostgreSQL status every loop_wait cycle (via pg_isready or process check).

Timeline:
    Last check      PG crash      Next check
       |              |              |
       |←── 0~loop ──→|              |
  • Best case: PG crashes right before Patroni check, detected immediately, wait 0
  • Worst case: PG crashes right after check, wait for next cycle, wait loop
  • Average case: loop/2
Tdetect={0Bestloop/2AverageloopWorstT_{detect} = \begin{cases} 0 & \text{Best} \\ loop/2 & \text{Average} \\ loop & \text{Worst} \end{cases}

Phase 2: Restart Timeout

After Patroni detects PG crash, it attempts to restart PostgreSQL. This phase has two possible outcomes:

Timeline:
  Crash detected     Restart attempt     Success/Timeout
      |                  |                    |
      |←──── 0 ~ start ─────────────────────→|

Path A: Self-healing Success (Best case)

  • PG restarts successfully, service recovers
  • No failover triggered, extremely short RTO
  • Wait time: 0 (relative to Failover path)

Path B: Failover Required (Average/Worst case)

  • PG still not recovered after primary_start_timeout
  • Patroni actively releases Leader Key
  • Wait time: start
Trestart={0Best (self-healing success)startAverage (failover required)startWorstT_{restart} = \begin{cases} 0 & \text{Best (self-healing success)} \\ start & \text{Average (failover required)} \\ start & \text{Worst} \end{cases}

Note: Average case assumes failover is required. If PG can quickly self-heal, overall RTO will be significantly lower.

Phase 3: Standby Detection

Standbys wake up on loop_wait cycle and check Leader Key status in DCS. When primary Patroni releases the Leader Key, standbys discover this and begin election.

Timeline:
    Lease released    Standby wakes
       |                  |
       |←── 0~loop ──────→|
  • Best case: Standby wakes right when lease is released, wait 0
  • Worst case: Standby just went to sleep when lease released, wait loop
  • Average case: loop/2
Tstandby={0Bestloop/2AverageloopWorstT_{standby} = \begin{cases} 0 & \text{Best} \\ loop/2 & \text{Average} \\ loop & \text{Worst} \end{cases}

Phase 4: Lock & Promote

After standbys discover Leader Key vacancy, election begins. The standby that acquires the Leader Key executes pg_ctl promote to become the new primary.

  1. Via REST API, parallel queries to check each standby’s replication position, typically 10ms, hardcoded 2s timeout.
  2. Compare WAL positions to determine best candidate, standbys attempt to create Leader Key (CAS atomic operation)
  3. Execute pg_ctl promote to become primary (very fast, typically negligible)
Election process:
  StandbyA ──→ Query replication position ──→ Compare ──→ Try lock ──→ Success
  StandbyB ──→ Query replication position ──→ Compare ──→ Try lock ──→ Fail
  • Best case: Single standby or direct lock acquisition and promote, constant overhead 0.1s
  • Worst case: DCS API call timeout: 2s
  • Average case: 1s constant overhead
Telect={0.1Best1Average2WorstT_{elect} = \begin{cases} 0.1 & \text{Best} \\ 1 & \text{Average} \\ 2 & \text{Worst} \end{cases}

Phase 5: Health Check

HAProxy detects new primary online, requires rise consecutive successful health checks.

Check timeline:
  New primary    First check    Second check   Third check (UP)
     |              |               |               |
     |←─ 0~inter ──→|←─── fast ────→|←─── fast ────→|
  • Best case: New primary comes up right at check time, (rise-1) × fastinter
  • Worst case: New primary comes up right after check, (rise-1) × fastinter + inter
  • Average case: (rise-1) × fastinter + inter/2
Thaproxy={(rise1)×fastinterBest(rise1)×fastinter+inter/2Average(rise1)×fastinter+interWorstT_{haproxy} = \begin{cases} (rise-1) \times fastinter & \text{Best} \\ (rise-1) \times fastinter + inter/2 & \text{Average} \\ (rise-1) \times fastinter + inter & \text{Worst} \end{cases}

RTO Formula

Sum all phase times to get total RTO:

Best Case (PG instant self-healing)

RTOmin=0+0+0+0.1+(rise1)×fastinter(rise1)×fastinterRTO_{min} = 0 + 0 + 0 + 0.1 + (rise-1) \times fastinter \approx (rise-1) \times fastinter

Average Case (Failover required)

RTOavg=loop+start+1+inter/2+(rise1)×fastinterRTO_{avg} = loop + start + 1 + inter/2 + (rise-1) \times fastinter

Worst Case

RTOmax=loop×2+start+2+inter+(rise1)×fastinterRTO_{max} = loop \times 2 + start + 2 + inter + (rise-1) \times fastinter

Model Calculation

Substituting the four RTO model parameters into the formulas above:

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

Calculation Results for Four Modes (unit: seconds, format: min / avg / max)

Phasefastnormsafewide
Failure Detection0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
Restart Timeout0 / 15 / 150 / 25 / 250 / 45 / 450 / 95 / 95
Standby Detection0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
Lock & Promote0 / 1 / 20 / 1 / 20 / 1 / 20 / 1 / 2
Health Check1 / 2 / 22 / 3 / 43 / 5 / 64 / 6 / 8
Total1 / 24 / 292 / 35 / 413 / 61 / 734 / 122 / 145

Comparison with Passive Failure

PhaseActive Failure (PG crash)Passive Failure (node down)Description
Detection MechanismPatroni active detectionTTL passive expiryActive detection discovers failure faster
Core Waitstartttlstart is usually less than ttl, but requires additional failure detection time
Lease HandlingActive releasePassive expiryActive release is more timely
Self-healing PossibleYesNoActive detection can attempt local recovery

RTO Comparison (Average case):

ModeActive Failure (PG crash)Passive Failure (node down)Difference
fast24s23s+1s
norm35s34s+1s
safe61s66s-5s
wide122s127s-5s

Analysis: In fast and norm modes, active failure RTO is slightly higher than passive failure because it waits for primary_start_timeout (start); but in safe and wide modes, since start < ttl - loop, active failure is actually faster. However, active failure has the possibility of self-healing, with potentially extremely short RTO in best case scenarios.

3.4.2.3 - Network Partition

Primary loses DCS connectivity, causing lease expiration and triggering split-brain protection and failover
infographic list-row-simple-horizontal-arrow
data
  title Network Partition Failover Flow
  desc Primary partitioned from DCS, Patroni proactively demotes to prevent split-brain, waits for TTL expiration before switchover
  items
    - label Primary Demote
      desc Patroni demotes PG after retry timeout
      icon mingcute/shield-fill
    - label Lease Expiration
      desc Leader Key TTL expires
      icon mingcute/close-circle-fill
    - label Replica Detection
      desc Replica detects lease expiration, starts election
      icon mingcute/key-2-fill
    - label Lock & Promote
      desc Replica acquires lock and promotes to new primary
      icon mingcute/radar-fill
    - label Health Check
      desc HAProxy detects new primary online
      icon mingcute/arrow-up-circle-fill
theme light
  palette antv

RTO Timeline

tooltip: { trigger: axis, axisPointer: { type: shadow }, formatter: $fn:fmt }
legend: { top: 0, itemGap: 12, data: [Primary Demote, Lease Expiration, Replica Detection, Lock & Promote, Health Check] }
grid: { left: 64, right: 24, bottom: 32, top: 40 }
xAxis: { type: value, name: sec, nameLocation: end, max: 160, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: true, lineStyle: { type: dashed, opacity: 0.5 } }, minorTick: { show: true, splitNumber: 5 }, minorSplitLine: { show: true, lineStyle: { type: dotted, opacity: 0.2 } } }
yAxis: { type: category, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: false }, axisLabel: { fontSize: 10, fontFamily: monospace }, data: [wide-max, wide-avg, wide-min, "", safe-max, safe-avg, safe-min, "", norm-max, norm-avg, norm-min, "", fast-max, fast-avg, fast-min] }
series:
  - { name: Primary Demote, type: bar, stack: main, barWidth: 20, z: 2, emphasis: { focus: series }, itemStyle: { color: "#76b7b2" }, data: [50, 40, 30, "-", 30, 25, 20, "-", 15, 13, 10, "-", 10, 8, 5] }
  - { name: Lease Expiration, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#e15759" }, data: [70, 70, 70, "-", 30, 30, 30, "-", 15, 15, 15, "-", 10, 10, 10] }
  - { name: Replica Detection, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#edc949" }, data: [20, 10, 0, "-", 10, 5, 0, "-", 5, 3, 0, "-", 5, 3, 0] }
  - { name: Lock & Promote, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#59a14f" }, data: [2, 1, 0, "-", 2, 1, 0, "-", 2, 1, 0, "-", 2, 1, 0] }
  - { name: Health Check, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#4e79a7" }, data: [8, 6, 4, "-", 6, 5, 3, "-", 4, 3, 2, "-", 2, 2, 1] }
  - { name: RTO Total, type: bar, barGap: "-100%", barWidth: 20, z: 1, itemStyle: { color: "#888", opacity: 0 }, emphasis: { itemStyle: { opacity: 0 } }, data: [150, 127, 104, "-", 78, 66, 53, "-", 41, 34, 27, "-", 29, 23, 16] }
  - { name: RTO Budget, type: bar, barGap: "-100%", barWidth: 20, z: 0, itemStyle: { color: "rgba(0,0,0,0.08)" }, emphasis: { itemStyle: { color: "rgba(0,0,0,0.12)" } }, data: [150, 150, 150, "-", 90, 90, 90, "-", 45, 45, 45, "-", 30, 30, 30] }

Failure Model

PhaseBestWorstAverageNotes
Demoteretryloop + retryloop/2 + retryPatroni retries after detecting partition, demotes after timeout
Lease Expirationttl - loop - retryttl - loop - retryttl - loop - retryRemaining TTL time after demotion (approximately constant)
Replica Detection0looploop/2Best: Right at detection point
Worst: Just missed detection
Lock & Promote021Best: Direct lock and promote
Worst: API timeout + Promote
Health Check(rise-1) × fastinter(rise-1) × fastinter + inter(rise-1) × fastinter + inter/2Best: State changes before check
Worst: State changes right after check

Key difference between network partition and node crash:

ScenarioPatroni StatePostgreSQL StateLease HandlingSplit-brain Risk
Node Crash (Expire)Dies with nodeCompletely unavailablePassive wait for TTL expirationNone
Network Partition (This scenario)Alive but cannot access DCSMay still be running (needs active demotion)Passive wait for TTL expirationYes, needs protection

In network partition scenarios, the primary PostgreSQL may still be running and accepting writes, causing split-brain issues. Patroni solves this through active demotion: when unable to refresh Leader Key, proactively demotes PostgreSQL to read-only or shuts it down.


Timeline Analysis

Phase 1: Primary Demotion

When primary Patroni is network-partitioned from DCS, it cannot refresh Leader Key and starts retrying.

Timeline:
  Partition      Detect partition      Retry timeout      Primary demotes
     |               |                    |                    |
     |←── loop ──→|←── retry ──→|
  • Detection delay: After partition occurs, must wait for next loop_wait cycle to detect
  • Retry phase: Patroni continuously retries DCS operations during retry_timeout
  • Active demotion: After retry timeout, Patroni proactively demotes PostgreSQL (prevents split-brain)
Tdemote={retrybest (partition right before detection)loop/2+retryaverageloop+retryworst (partition right after refresh)T_{demote} = \begin{cases} retry & \text{best (partition right before detection)} \\ loop/2 + retry & \text{average} \\ loop + retry & \text{worst (partition right after refresh)} \end{cases}

Key design: Patroni requires constraint loop_wait + 2 × retry_timeout ≤ ttl to ensure primary demotes before TTL expires.

Phase 2: Lease Expiration

After primary demotion, Leader Key still exists in DCS, must wait for TTL to naturally expire.

Timeline:
  Primary demoted                   TTL expires
     |                                 |
     |←── ttl - (loop + retry) ──→|

Since the primary has demoted, waiting time during this phase is the remaining TTL time. Since partition detection and remaining TTL are negatively correlated (earlier partition means slower detection but longer remaining TTL), their sum is constant:

Texpire=ttlloopretry(approximately constant)T_{expire} = ttl - loop - retry \quad \text{(approximately constant)}

Note: Primary demotion + lease expiration total time still approximately equals ttl, same as expire failure.

Phase 3: Replica Detection

Replica wakes up in loop_wait cycle and checks Leader Key status in DCS.

Timeline:
    Lease expired      Replica wakes
       |                  |
       |←── 0~loop ─→|
  • Best case: Replica wakes right when lease expires, wait 0
  • Worst case: Replica just entered sleep when lease expires, wait loop
  • Average case: loop/2
Tdetect={0bestloop/2averageloopworstT_{detect} = \begin{cases} 0 & \text{best} \\ loop/2 & \text{average} \\ loop & \text{worst} \end{cases}

Phase 4: Lock & Promote

After replica discovers Leader Key expired, it starts the election process.

Election flow:
  ReplicaA ──→ Query replication position ──→ Compare ──→ Try lock ──→ Success
  ReplicaB ──→ Query replication position ──→ Compare ──→ Try lock ──→ Fail
  • Best case: Single replica or directly acquires lock and promotes, ≈ 0
  • Worst case: DCS API call timeout, 2s
  • Average case: 1s
Telect={0best1average2worstT_{elect} = \begin{cases} 0 & \text{best} \\ 1 & \text{average} \\ 2 & \text{worst} \end{cases}

Phase 5: Health Check

HAProxy detects new primary coming online, requires rise consecutive successful health checks.

Detection timeline:
  New primary    First check    Second check   Third check (UP)
     |              |               |               |
     |←─ 0~inter ─→|←─ fast ─→|←─ fast ─→|
  • Best case: (rise-1) × fastinter
  • Worst case: (rise-1) × fastinter + inter
  • Average case: (rise-1) × fastinter + inter/2
Thaproxy={(rise1)×fastinterbest(rise1)×fastinter+inter/2average(rise1)×fastinter+interworstT_{haproxy} = \begin{cases} (rise-1) \times fastinter & \text{best} \\ (rise-1) \times fastinter + inter/2 & \text{average} \\ (rise-1) \times fastinter + inter & \text{worst} \end{cases}

RTO Formula

Sum all phase times to get total RTO.

Since primary demotion + lease expiration ≈ ttl, network partition RTO formula is same as expire failure:

Best Case

RTOmin=ttlloop+0.1+(rise1)×fastinterRTO_{min} = ttl - loop + 0.1 + (rise-1) \times fastinterRTOminttlloop+(rise1)×fastinterRTO_{min} \approx ttl - loop + (rise-1) \times fastinter

Average Case

RTOavg=ttl+1+inter/2+(rise1)×fastinterRTO_{avg} = ttl + 1 + inter/2 + (rise-1) \times fastinterRTOavg=ttl+1+inter/2+(rise1)×fastinterRTO_{avg} = ttl + 1 + inter/2 + (rise-1) \times fastinter

Worst Case

RTOmax=ttl+loop+2+inter+(rise1)×fastinterRTO_{max} = ttl + loop + 2 + inter + (rise-1) \times fastinterRTOmax=ttl+loop+2+inter+(rise1)×fastinterRTO_{max} = ttl + loop + 2 + inter + (rise-1) \times fastinter

Model Calculation

Substituting the four RTO model parameters into the formulas:

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

Patroni constraint validation (loop + 2×retry ≤ ttl):

ModeloopretryTTLloop + 2×retryMeets constraint?
fast5520s15s✓ Safe
norm51030s25s✓ Safe
safe102060s50s✓ Safe
wide2030120s80s✓ Safe

Four mode calculation results (seconds, format: min / avg / max)

Phasefastnormsafewide
Primary Demote5 / 8 / 1010 / 13 / 1520 / 25 / 3030 / 40 / 50
Lease Expiration10153070
Replica Detection0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
Lock & Promote0 / 1 / 20 / 1 / 20 / 1 / 20 / 1 / 2
Health Check1 / 2 / 22 / 3 / 43 / 5 / 64 / 6 / 8
Total16 / 23 / 2927 / 34 / 4153 / 66 / 78104 / 127 / 150

Conclusion: Network partition RTO is same as expire failure (node crash), as the bottleneck is TTL expiration time.


Split-brain Protection

The biggest risk of network partition is split-brain: old primary may still be running and accepting writes. Patroni provides multiple protection mechanisms:

1. Primary Self-Demotion

Patroni’s core protection mechanism: when unable to refresh Leader Key, proactively demotes PostgreSQL.

# Patroni pseudo-code logic
if not can_refresh_leader_key():
    retry_until(retry_timeout)
    if still_cannot_refresh():
        demote_postgresql()  # Demote to read-only or shut down

2. Linux Watchdog

If Patroni process hangs and cannot execute demotion, Linux watchdog will force system restart.

# patroni.yml configuration
watchdog:
  mode: required  # Require watchdog available
  device: /dev/watchdog
  safety_margin: 5

3. Fencing Mechanism

Can configure fencing scripts to forcibly isolate old primary (e.g., disable network interface, stop service, etc.).


Special Scenarios

Scenario A: Primary partitioned from DCS, replicas normal

This is the most common network partition scenario, the main focus of this article.

┌─────────┐         ╳         ┌─────────┐
│ Primary │ ←── Partition ──→ │   DCS   │
│ Patroni │                   │  etcd   │
└─────────┘                   └─────────┘
                              Normal connection
                              ┌─────────┐
                              │ Replica │
                              │ Patroni │
                              └─────────┘
  • Primary Patroni cannot refresh Leader Key → Active demotion
  • Replica normally detects TTL expiration → Elected as new primary
  • RTO ≈ Expire failure RTO

Scenario B: Primary normal, replica partitioned from DCS

┌─────────┐                   ┌─────────┐
│ Primary │ ←── Normal ──→    │   DCS   │
│ Patroni │                   │  etcd   │
└─────────┘                   └─────────┘
                              Partition
                              ┌─────────┐
                              │ Replica │
                              │ Patroni │
                              └─────────┘
  • Primary normally refreshes Leader Key
  • Replica cannot participate in election (but replication can continue)
  • No failover triggered, service continues normally

Scenario C: All nodes partitioned from DCS

┌─────────┐         ╳         ┌─────────┐
│ Primary │ ←── Partition ──→ │   DCS   │
│ Patroni │                   │  etcd   │
└─────────┘                   └─────────┘
┌─────────┐         ╳             │
│ Replica │ ←── Partition ────────┘
│ Patroni │
└─────────┘
  • Primary demotes, replica cannot elect
  • Cluster completely unavailable
  • Requires manual intervention to restore DCS connectivity

Comparison with Other Failures

Failure TypePrimary StateLease HandlingRTOSplit-brain Risk
Expire FailureNode crashPassive wait TTL expiration16s ~ 150sNone
Crash FailurePG crash, Patroni aliveRelease after restart timeout1s ~ 111sNone
Network PartitionAlive but isolated from DCSPassive wait TTL expiration16s ~ 150sYes, needs protection
Manual SwitchoverNormal or failedDirect release/acquire1s ~ 11sNone

Key Insight: Network partition RTO is same as expire failure, but requires additional split-brain protection mechanisms. Ensuring loop_wait + 2 × retry_timeout ≤ ttl constraint is the key design to prevent split-brain.

3.4.3 - RTO Trade-offs

Trade-off analysis for RTO (Recovery Time Objective), finding the optimal balance between recovery speed and false failover risk.

RTO (Recovery Time Objective) defines the maximum time required for the system to restore write capability when the primary fails.

For critical transaction systems where availability is paramount, the shortest possible RTO is typically required, such as under one minute.

However, shorter RTO comes at a cost: increased false failover risk. Network jitter may be misinterpreted as a failure, leading to unnecessary failovers. For cross-datacenter/cross-region deployments, RTO requirements are typically relaxed (e.g., 1-2 minutes) to reduce false failover risk.


Trade-offs

The upper limit of unavailability during failover is controlled by the pg_rto parameter. Pigsty provides four preset RTO modes: fast, norm, safe, wide, each optimized for different network conditions and deployment scenarios. The default is norm mode (~45 seconds).

When the primary fails, the entire recovery process involves multiple phases: Patroni detects the failure, DCS lock expires, new primary election, promote execution, HAProxy detects the new primary. Reducing RTO means shortening the timeout for each phase, which makes the cluster more sensitive to network jitter, thereby increasing false failover risk.

You need to choose the appropriate mode based on actual network conditions, balancing recovery speed and false failover risk. The worse the network quality, the more conservative mode you should choose; the better the network quality, the more aggressive mode you can choose.

flowchart LR
    A([Primary Failure]) --> B{Patroni<br/>Detected?}

    B -->|PG Crash| C[Attempt Local Restart]
    B -->|Node Down| D[Wait TTL Expiration]

    C -->|Success| E([Local Recovery])
    C -->|Fail/Timeout| F[Release Leader Lock]

    D --> F
    F --> G[Replica Election]
    G --> H[Execute Promote]
    H --> I[HAProxy Detects]
    I --> J([Service Restored])

    style A fill:#dc3545,stroke:#b02a37,color:#fff
    style E fill:#198754,stroke:#146c43,color:#fff
    style J fill:#198754,stroke:#146c43,color:#fff

Four Modes

Pigsty provides four RTO modes to help users make trade-offs under different network conditions.

Namefastnormsafewide
Use CaseSame rackSame datacenter (default)Same region, cross-DCCross-region/continent
Network< 1ms, very stable1-5ms, normal10-50ms, cross-DC100-200ms, public network
Target RTO30s45s90s150s
False Failover RiskHigherMediumLowerVery Low
Configurationpg_rto: fastpg_rto: normpg_rto: safepg_rto: wide
fast: Same Rack/Switch
  • Suitable for scenarios with extremely low network latency (< 1ms) and very stable networks, such as same-rack or same-switch deployments
  • Average RTO: 14s, worst case: 29s, TTL only 20s, check interval 5s
  • Highest network quality requirements, any jitter may trigger failover, higher false failover risk
norm: Same Datacenter (Default)
  • Default mode, suitable for same-datacenter deployment, network latency 1-5ms, normal quality, reasonable packet loss rate
  • Average RTO: 21s, worst case: 43s, TTL is 30s, provides reasonable tolerance window
  • Balances recovery speed and stability, suitable for most production environments
safe: Same Region, Cross-Datacenter
  • Suitable for same-region/same-area cross-datacenter deployment, network latency 10-50ms, occasional jitter possible
  • Average RTO: 43s, worst case: 91s, TTL is 60s, longer tolerance window
  • Primary restart wait time is longer (60s), gives more local recovery opportunities, lower false failover risk
wide: Cross-Region/Continent
  • Suitable for cross-region or even cross-continent deployment, network latency 100-200ms, possible public-network-level packet loss
  • Average RTO: 92s, worst case: 207s, TTL is 120s, very wide tolerance window
  • Sacrifices recovery speed for extremely low false failover rate, suitable for geo-disaster recovery scenarios

RTO Timeline

Patroni / PG HA has two key failure paths: active failure detection (Patroni detects a PG crash and attempts restart) and passive lease expiration (node down waits for TTL expiration to trigger election).

tooltip: { trigger: axis, axisPointer: { type: shadow }, formatter: $fn:fmt }
legend: { top: 0, itemGap: 10, data: [Lease Expiration, Failure Detection, Restart Timeout, Replica Detection, Lock & Promote, Health Check] }
grid: { left: 110, right: 24, bottom: 32, top: 40 }
xAxis: { type: value, name: Seconds, nameLocation: end, max: 160, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: true, lineStyle: { type: dashed, opacity: 0.5 } }, minorTick: { show: true, splitNumber: 5 }, minorSplitLine: { show: true, lineStyle: { type: dotted, opacity: 0.2 } } }
yAxis: { type: category, axisLine: { show: true }, axisTick: { show: true }, splitLine: { show: false }, axisLabel: { fontSize: 9, fontFamily: monospace }, data: [wide-passive-max, wide-passive-avg, wide-passive-min, wide-active-max, wide-active-avg, wide-active-min, "", safe-passive-max, safe-passive-avg, safe-passive-min, safe-active-max, safe-active-avg, safe-active-min, "", norm-passive-max, norm-passive-avg, norm-passive-min, norm-active-max, norm-active-avg, norm-active-min, "", fast-passive-max, fast-passive-avg, fast-passive-min, fast-active-max, fast-active-avg, fast-active-min] }
series:
  - { name: Lease Expiration, type: bar, stack: main, barWidth: 16, z: 2, emphasis: { focus: series }, itemStyle: { color: "#e15759" }, data: [120, 110, 100, "-", "-", "-", "-", 60, 55, 50, "-", "-", "-", "-", 30, 27, 25, "-", "-", "-", "-", 20, 17, 15, "-", "-", "-"] }
  - { name: Failure Detection, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#b07aa1" }, data: ["-", "-", "-", 20, 10, 0, "-", "-", "-", "-", 10, 5, 0, "-", "-", "-", "-", 5, 3, 0, "-", "-", "-", "-", 5, 3, 0] }
  - { name: Restart Timeout, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#f28e2c" }, data: ["-", "-", "-", 95, 95, 0, "-", "-", "-", "-", 45, 45, 0, "-", "-", "-", "-", 25, 25, 0, "-", "-", "-", "-", 15, 15, 0] }
  - { name: Replica Detection, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#edc949" }, data: [20, 10, 0, 20, 10, 0, "-", 10, 5, 0, 10, 5, 0, "-", 5, 3, 0, 5, 3, 0, "-", 5, 3, 0, 5, 3, 0] }
  - { name: Lock & Promote, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#59a14f" }, data: [2, 1, 0, 2, 1, 0, "-", 2, 1, 0, 2, 1, 0, "-", 2, 1, 0, 2, 1, 0, "-", 2, 1, 0, 2, 1, 0] }
  - { name: Health Check, type: bar, stack: main, z: 2, emphasis: { focus: series }, itemStyle: { color: "#4e79a7" }, data: [8, 6, 4, 8, 6, 4, "-", 6, 5, 3, 6, 5, 3, "-", 4, 3, 2, 4, 3, 2, "-", 2, 2, 1, 2, 2, 1] }
  - { name: RTO Total, type: bar, barGap: "-100%", barWidth: 16, z: 1, itemStyle: { color: "#888", opacity: 0 }, emphasis: { itemStyle: { opacity: 0 } }, data: [150, 127, 104, 145, 122, 4, "-", 78, 66, 53, 73, 61, 3, "-", 41, 34, 27, 41, 35, 2, "-", 29, 23, 16, 29, 24, 1] }
  - { name: RTO Budget, type: bar, barGap: "-100%", barWidth: 16, z: 0, itemStyle: { color: "rgba(0,0,0,0.08)" }, emphasis: { itemStyle: { color: "rgba(0,0,0,0.12)" } }, data: [150, 150, 150, 150, 150, 150, "-", 90, 90, 90, 90, 90, 90, "-", 45, 45, 45, 45, 45, 45, "-", 30, 30, 30, 30, 30, 30] }

Implementation

The four RTO modes differ in how the following 10 Patroni and HAProxy HA-related parameters are configured.

ComponentParameterfastnormsafewideDescription
patronittl203060120Leader lock TTL (seconds)
loop_wait551020HA loop check interval (seconds)
retry_timeout5102030DCS operation retry timeout (seconds)
primary_start_timeout15254595Primary restart wait time (seconds)
safety_margin551015Watchdog safety margin (seconds)
haproxyinter1s2s3s4sNormal state check interval
fastinter0.5s1s1.5s2sState transition check interval
downinter1s2s3s4sDOWN state check interval
rise3333Consecutive successes to mark UP
fall3333Consecutive failures to mark DOWN

Patroni Parameters

  • ttl: Leader lock TTL. Primary must renew within this time, otherwise lock expires and triggers election. Directly determines passive failure detection delay.
  • loop_wait: Patroni main loop interval. Each loop performs one health check and state sync, affects failure discovery timeliness.
  • retry_timeout: DCS operation retry timeout. During network partition, Patroni retries continuously within this period; after timeout, primary actively demotes to prevent split-brain.
  • primary_start_timeout: Wait time for Patroni to attempt local restart after PG crash. After timeout, releases Leader lock and triggers failover.
  • safety_margin: Watchdog safety margin. Ensures sufficient time to trigger system restart during failures, avoiding split-brain.

HAProxy Parameters

  • inter: Health check interval in normal state, used when service status is stable.
  • fastinter: Check interval during state transition, uses shorter interval to accelerate confirmation when state change detected.
  • downinter: Check interval in DOWN state, uses this interval to probe recovery after service marked DOWN.
  • rise: Consecutive successes required to mark UP. After new primary comes online, must pass rise consecutive checks before receiving traffic.
  • fall: Consecutive failures required to mark DOWN. Service must fail fall consecutive times before being marked DOWN.

Key Constraint

Patroni core constraint: Ensures primary can complete demotion before TTL expires, preventing split-brain.

loop_wait+2×retry_timeoutttlloop\_wait + 2 \times retry\_timeout \leq ttl

Data Summary


Recommendations

fast mode is suitable for scenarios with extremely high RTO requirements, but requires sufficiently good network quality (latency < 1ms, very low packet loss). Recommended only for same-rack or same-switch deployments, and should be thoroughly tested in production before enabling.

norm mode (default) is Pigsty’s default configuration, sufficient for the vast majority of same-datacenter deployments. In the model used by this page, the passive and active paths average about 34 and 35 seconds, while still providing a reasonable tolerance window against false failovers caused by network jitter.

safe mode is suitable for same-city cross-datacenter deployments with higher network latency or occasional jitter. The longer tolerance window effectively prevents false failovers from network jitter, making it the recommended configuration for cross-datacenter disaster recovery.

wide mode is suitable for cross-region or even cross-continent deployments with high network latency and possible public-network-level packet loss. In such scenarios, stability is more important than recovery speed, so an extremely wide tolerance window ensures very low false failover rate.

ModeTarget RTOPassive RTOActive RTOScenario
fast3016 / 23 / 291 / 24 / 29Same switch, high-quality network
norm4527 / 34 / 412 / 35 / 41Default, same DC, standard network
safe9053 / 66 / 783 / 61 / 73Same-city active-active / cross-DC DR
wide150104 / 127 / 1504 / 122 / 145Geo-DR / cross-country
default32622 / 34 / 462 / 314 / 326Patroni default params

Typically you only need to set pg_rto to the mode name, and Pigsty will automatically configure Patroni and HAProxy parameters. The current template looks up pg_rto with pg_rto in pg_rto_plan; a numeric or unknown key falls back directly to norm. Do not treat that fallback as a supported “RTO in seconds” configuration.

The mode configuration actually loads the corresponding parameter set from pg_rto_plan. You can modify or override this configuration to implement custom RTO strategies.

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

3.4.4 - Service Access

Pigsty uses HAProxy to provide service access, with optional pgBouncer for connection pooling, and optional L2 VIP and DNS access.

Split read and write operations, route traffic correctly, and deliver PostgreSQL cluster capabilities reliably.

Service is an abstraction: it represents the form in which database clusters expose their capabilities externally, encapsulating underlying cluster details.

Services are crucial for stable access in production environments, showing their value during automatic failover in high availability clusters. Personal users typically don’t need to worry about this concept.


Personal Users

The concept of “service” is for production environments. Personal users with single-node clusters can skip the complexity and directly use instance names or IP addresses to access the database.

For example, Pigsty’s default single-node pg-meta.meta database can be connected directly using three different users:

psql postgres://dbuser_dba:[email protected]/meta     # Connect directly with DBA superuser
psql postgres://dbuser_meta:[email protected]/meta   # Connect with default business admin user
psql postgres://dbuser_view:DBUser.Viewer@pg-meta/meta     # Connect with default read-only user via instance domain name

Service Overview

In real-world production environments, we use primary-replica database clusters based on replication. Within a cluster, one and only one instance serves as the leader (primary) that can accept writes. Other instances (replicas) continuously fetch change logs from the cluster leader to stay synchronized. Replicas can also handle read-only requests, significantly offloading the primary in read-heavy, write-light scenarios. Therefore, distinguishing write requests from read-only requests is a common practice.

Additionally, for production environments with high-frequency, short-lived connections, we pool requests through connection pool middleware (Pgbouncer) to reduce connection and backend process creation overhead. However, for scenarios like ETL and change execution, we need to bypass the connection pool and directly access the database. Meanwhile, high-availability clusters may undergo failover during failures, causing cluster leadership changes. Therefore, high-availability database solutions require write traffic to automatically adapt to cluster leadership changes. These varying access needs (read-write separation, pooled vs. direct connections, failover auto-adaptation) ultimately lead to the abstraction of the Service concept.

Typically, database clusters must provide this most basic service:

  • Read-write service (primary): Can read from and write to the database

For production database clusters, at least these two services should be provided:

  • Read-write service (primary): Write data: Can only be served by the primary.
  • Read-only service (replica): Read data: Can be served by replicas; falls back to primary when no replicas are available

Additionally, depending on specific business scenarios, there may be other services, such as:

  • Default direct service (default): Allows (admin) users to bypass the connection pool and directly access the database
  • Offline replica service (offline): Dedicated replica not serving online read traffic, used for ETL and analytical queries
  • Sync replica service (standby): Read-only service with no replication delay, handled by synchronous standby/primary for read queries
  • Delayed replica service (delayed): Access data from the same cluster as it was some time ago, handled by delayed replicas

Access Services

Pigsty’s service delivery boundary stops at the cluster’s HAProxy. Users can access these load balancers through various means.

The typical approach is to use DNS or VIP access, binding them to all or any number of load balancers in the cluster.

pigsty-access.jpg

You can use different host & port combinations, which provide PostgreSQL service in different ways.

Host

TypeSampleDescription
Cluster Domain Namepg-testResolved by dnsmasq on INFRA nodes; with pg_dns_target: auto, points to the VIP when enabled, otherwise to the primary IP
Cluster VIP Address10.10.10.3When pg_vip_enabled is enabled, an L2 VIP managed by vip-manager and bound to the primary node
Instance Hostnamepg-test-1Access via any instance hostname (resolved by dnsmasq @ infra nodes)
Instance IP Address10.10.10.11Access any instance’s IP address

Port

Pigsty uses different ports to distinguish pg services

PortServiceTypeDescription
5432postgresDatabaseDirect access to postgres server
6432pgbouncerMiddlewareAccess postgres through connection pool middleware
5433primaryServiceAccess primary pgbouncer (or postgres)
5434replicaServiceAccess replica pgbouncer (or postgres)
5436defaultServiceAccess primary postgres
5438offlineServiceAccess offline postgres

Combinations

# Access via cluster domain (this example assumes a cluster VIP; without one, DNS resolves to the primary IP by default)
postgres://test@pg-test:5432/test # DNS -> L2 VIP -> primary direct connection
postgres://test@pg-test:6432/test # DNS -> L2 VIP -> primary connection pool -> primary
postgres://test@pg-test:5433/test # DNS -> L2 VIP -> HAProxy -> primary connection pool -> primary
postgres://test@pg-test:5434/test # DNS -> L2 VIP -> HAProxy -> replica connection pool -> replica
postgres://dbuser_dba@pg-test:5436/test # DNS -> L2 VIP -> HAProxy -> primary direct connection (for admin)
postgres://dbuser_stats@pg-test:5438/test # DNS -> L2 VIP -> HAProxy -> offline direct connection (for ETL/personal queries)

# Access via cluster VIP directly
postgres://[email protected]:5432/test # L2 VIP -> primary direct access
postgres://[email protected]:6432/test # L2 VIP -> primary connection pool -> primary
postgres://[email protected]:5433/test # L2 VIP -> HAProxy -> primary connection pool -> primary
postgres://[email protected]:5434/test # L2 VIP -> HAProxy -> replica connection pool -> replica
postgres://[email protected]:5436/test # L2 VIP -> HAProxy -> primary direct connection (for admin)
postgres://[email protected]:5438/test # L2 VIP -> HAProxy -> offline direct connection (for ETL/personal queries)

# Directly specify any cluster instance name
postgres://test@pg-test-1:5432/test # DNS -> database instance direct connection (singleton access)
postgres://test@pg-test-1:6432/test # DNS -> connection pool -> database
postgres://test@pg-test-1:5433/test # DNS -> HAProxy -> connection pool -> database read/write
postgres://test@pg-test-1:5434/test # DNS -> HAProxy -> connection pool -> database read-only
postgres://dbuser_dba@pg-test-1:5436/test # DNS -> HAProxy -> database direct connection
postgres://dbuser_stats@pg-test-1:5438/test # DNS -> HAProxy -> database offline read/write

# Directly specify any cluster instance IP access
postgres://[email protected]:5432/test # Database instance direct connection (directly specify instance, no automatic traffic distribution)
postgres://[email protected]:6432/test # Connection pool -> database
postgres://[email protected]:5433/test # HAProxy -> connection pool -> database read/write
postgres://[email protected]:5434/test # HAProxy -> connection pool -> database read-only
postgres://[email protected]:5436/test # HAProxy -> database direct connection
postgres://[email protected]:5438/test # HAProxy -> database offline read-write

# Smart client: read/write separation via URL
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

3.5 - Point-in-Time Recovery — A Time Machine for PostgreSQL

High availability handles machine failure; point-in-time recovery handles incorrect data. Pigsty uses pgBackRest to provide PITR out of the box, allowing a cluster to return to any recoverable point covered by its backup and WAL history.

If data, a table, or even a database is deleted accidentally, Point-in-Time Recovery (PITR) can return the cluster to an earlier state.

This capability, once treated as specialist DBA work, is enabled by Pigsty’s standard PostgreSQL configuration.


Replication Is Not Backup

High availability can fail over to another instance when hardware fails. It has a natural blind spot, however: replication is not backup.

Streaming replication faithfully sends every primary change to every replica within milliseconds, including a DELETE without a WHERE clause or a DROP TABLE issued against the wrong database. Failover handles a broken machine; when the data itself is wrong, every replica can contain the same error.

Database disasters therefore fall into two broad classes. Redundancy handles physical service failure through multiple copies and automatic failover. Logical errors require history: a base backup plus continuous WAL archives from which PostgreSQL can reconstruct a state before the mistake.

ThreatHigh AvailabilityDelayed ClusterPITR
Hardware or instance failure✔ Automatic failover✔, with a longer RTO
Accidental DML, table drop, or database drop✘ The error is replicated✔ Within the delay✔ At any recoverable point
Defective software corrupts data over time✘ The error is replicated✔ Within the delay✔ Try different recovery targets
Entire cluster or site is lost✔ Only if the repository survives that failure domain

These mechanisms complement one another: HA restores service quickly, a delayed cluster provides a short undo window, and PITR is the final historical recovery path.


How the Time Machine Works

A database can be viewed as a state machine. A base backup is a complete physical snapshot at one point, while WAL (Write-Ahead Log) records every subsequent state change. With a snapshot and an unbroken WAL history starting from it, PostgreSQL can replay the database to any target covered by that history. The backup determines how far back recovery can start; the latest archived WAL determines how close to the present it can reach.

Base backup + WAL archive = point-in-time recovery

Pigsty orchestrates both inputs. Cluster initialization attempts an initial full backup by default, and the primary continuously sends completed WAL segments to the selected repository. See How PITR Works for the complete model of backups, archives, targets, and timelines.


Available Out of the Box

PITR is enabled in Pigsty’s standard PostgreSQL configuration. Each cluster is prepared with a backup repository, WAL archiving, and recovery tooling powered by pgBackRest. The policy remains declarative and can be customized with a few parameters:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pgbackrest_method: minio       # Silo / S3-compatible storage; local is the default
    pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]  # daily full backup at 01:00

The default local method stores backups under /pg/backup and retains two full backups. With one successful full backup per day, the resulting window is roughly 24–48 hours. Selecting the remote minio preset places the repository in Silo or compatible S3 storage, enables AES-256-CBC repository encryption, and uses time-based retention. With a 14-day retention setting and weekly full backups, the steady-state recovery window is roughly 14–21 days. Treat both ranges as policy estimates: actual coverage starts at the oldest usable backup and ends at the latest WAL that reached the repository.

Recovery is declarative too: specify a target, then let the playbook stop the cluster, restore files, replay WAL, and rebuild HA. An operator must still verify the recovered business state.

./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": { "time": "2026-07-11 10:00:00+08", "action": "promote" }}'

This follows Pigsty’s declarative configuration model: backup policy is part of the cluster definition, and a recovery target is another declared parameter.


Benefits and Costs

PITR materially improves data integrity and availability:

  • RPO (maximum data loss) is usually reduced to minutes, bounded by WAL that had not reached a surviving repository.
  • RTO (time to restore service) becomes tens of minutes to hours rather than permanent loss, depending on backup size, WAL replay distance, and disk or network throughput.
Standalone strategyEventRTORPO
No backupHost and local data are lostPermanent lossAll data
Base backups onlyHost and local data are lostBackup size and bandwidth, often hoursChanges since the latest backup
Base backups + WAL archivesHost and local data are lostBackup size, replay distance, and bandwidthWAL not yet present in the surviving repository

The costs fall mainly into three areas:

  • Confidentiality: backups are another copy of business data and need encryption and access control. Pigsty’s remote preset enables repository encryption, but its default password must be changed.
  • Resources: backups consume storage and archiving consumes bandwidth. Compression, bundling, and block incremental backup reduce this cost but do not eliminate capacity planning.
  • Operations: backup status must be monitored and recovery must be rehearsed. A green backup job alone is not proof that the data can be restored within the required RTO.

PITR by itself does not replace HA. A production design normally combines HA for physical failures with PITR for logical errors and site-level recovery.


Next Steps

  • How PITR Works: snapshots, WAL history, recovery windows, targets, and timelines
  • PITR Architecture: pgBackRest, repository selection, archive flow, scheduling, and failover behavior
  • PITR Tradeoffs: failure domains, capacity, retention, and backup frequency
  • Declarative Recovery: the pg_pitr parameter, pgsql-pitr.yml, and pig pitr
  • PITR Scenarios: accidental deletion, bad releases, investigation, and site loss

For the operational runbooks, see PGSQL Backup and Recovery.

3.5.1 - How PITR Works

Snapshots, WAL history, recovery windows, recovery targets, and timelines: the five concepts needed to reason accurately about PostgreSQL PITR.

If a database is a state machine, WAL (Write-Ahead Log) is its ordered change history. PostgreSQL records each modification in WAL before applying it to data files. Save a physical snapshot at one point, preserve all later WAL, and PostgreSQL can replay that history to a selected consistent state.

PITR is therefore the combination of three simple elements: a snapshot (base backup), history (WAL archive), and a target (where replay should stop).


Snapshot: Base Backup

A base backup is a physical snapshot of the whole PostgreSQL cluster and supplies a starting point for recovery. Pigsty uses pgBackRest to create and manage three backup types:

TypeContentsRecovery characteristics
FullAll database-cluster filesSelf-contained, shortest chain, largest backup
DifferentialChanges since the latest full backupRestore uses the full plus the differential
IncrementalChanges since the latest backup of any typeSmallest backup, restore depends on its complete chain

The wrapper pg-backup [full|diff|incr] triggers a backup. With no argument it requests incr; pgBackRest creates a full backup instead when no valid full exists. pg_crontab declares recurring jobs and installs them in the postgres user’s crontab.

Backup frequency affects recovery time: the newer the usable backup, the less WAL must be replayed to reach a given target. See PITR Tradeoffs.


WAL History

A snapshot reaches only its own state. WAL archiving preserves every later change needed to advance beyond it. Pigsty’s standard Patroni templates enable archiving and ask PostgreSQL to hand each completed WAL segment to pgBackRest:

archive_mode: 'on'
archive_command: 'pgbackrest --stanza=pg-meta archive-push %p'
archive_timeout: 300

Two implementation details matter:

  • archive_timeout: 300: on a low-write cluster, PostgreSQL can force a segment switch after five minutes so a partially filled segment does not wait indefinitely. This normally keeps the right edge of the recovery window within minutes when WAL is being generated; it is not a promise that every commit is already remote.
  • Asynchronous archive: pgBackRest uses /pg/spool with archive-async=y to batch transfers. Pigsty sets archive-push-queue-max=4GiB; if repository failure lets the queue cross that bound, pgBackRest can drop the queued WAL to protect local disk. That creates an archive gap, so a new full backup is required to establish a fresh recoverable chain.

Expiration is automatic. When old backups expire under the repository policy, pgBackRest also expires archived WAL that no remaining backup needs, unless archive retention is overridden explicitly.


Recovery Window

The backup and its continuous WAL history form a recovery window:

  • Left boundary: the start of the oldest usable remaining backup chain. In practical time-based descriptions, this is usually summarized by the oldest retained full backup’s time.
  • Right boundary: the latest WAL successfully archived to a repository that survives the incident.

The window moves forward as new backups arrive and old chains expire. Pigsty’s local preset keeps two full backups; with one successful full per day, coverage is roughly one to two days. The minio preset uses retention_full_type: time with retention_full: 14; with weekly full backups, the oldest retained chain normally yields roughly 14–21 days of steady-state coverage. These are estimates, not SLAs: missed backups, archive gaps, explicit archive-retention overrides, or repository loss change the actual window. Verify it with pig pb info and restore drills.

See PITR Tradeoffs and Backup Policy.


Targets: Where Replay Stops

PostgreSQL supports several ways to locate a state inside the recovery window. Pigsty exposes six target types through pg_pitr:

pg_pitr typeMeaningTypical use
defaultReplay through all WAL available from the repositoryRestore the newest archived state after total loss
timeStop at a timestampRecover from accidental DML or DDL
xidStop at a transaction IDExclude a precisely identified bad transaction
lsnStop at a WAL locationLow-level exact targeting
nameStop at a restore point created with pg_create_restore_point()Planned change checkpoint
immediateStop as soon as the selected backup becomes consistentValidate or expose the selected backup state quickly

The set field is different: it chooses which backup set pgBackRest restores as the starting snapshot; it is not itself a replay stop target.

Boundary Semantics

Targets are inclusive by default: the transaction at the target is retained. To stop immediately before a known bad target, set exclusive: true, which maps to recovery_target_inclusive = false.

Transactions remain atomic. Committed transactions before the effective target survive; transactions not committed at that point are rolled back. Recovery produces a consistent database state rather than half of a transaction.


Timelines

Restoring to the past and accepting new writes creates a fork in history. PostgreSQL uses a timeline to distinguish each branch. PITR promotion, replica promotion, and failover can all create a new timeline; new WAL does not overwrite the old timeline’s files.

gitGraph
    commit id: "Full backup"
    commit id: "Normal writes"
    commit id: "Bad change"
    commit id: "More writes"
    branch Timeline-2
    checkout Timeline-2
    commit id: "PITR before bad change"
    commit id: "New writes"

Keeping the old history allows another attempt if the first target was wrong. The timeline field can select a timeline; Pigsty’s recovery declaration defaults to latest.

Continue with PITR Architecture to see how these concepts map to Pigsty components and configuration.

3.5.2 - PITR Architecture

Pigsty implements PITR with pgBackRest: repository selection, archive flow, scheduling, primary-aware backup execution, performance defaults, and observability.

The PITR principle is compact; the engineering is not. WAL archiving must not stall production writes, object-storage backups need encryption, backup jobs must follow the primary after failover, shared repositories must isolate clusters, and large numbers of small objects can limit throughput.

Pigsty uses pgBackRest as its backup engine and ships production-oriented defaults for those concerns. This page describes the engine, repository abstraction, archive path, scheduler, and primary-aware execution model.


Backup Engine: pgBackRest

Pigsty uses pgBackRest for three responsibilities: create base backups with backup, receive WAL with archive-push, and restore data with restore plus archive-get.

Relevant capabilities include:

  • Parallelism: backup, archive, and restore operations can use multiple processes.
  • Backup chains: full, differential, incremental, and block incremental backups reduce repeated transfer and storage.
  • Compression and encryption: zstd compression and AES-256-CBC repository encryption are built in.
  • Repository backends: POSIX filesystems, S3-compatible services such as Silo and MinIO, Azure, GCS, and SFTP are supported by pgBackRest.
  • Bundling: small files can be packed into larger repository objects, reducing object-storage overhead.

pgBackRest separates cluster histories using a stanza. Pigsty maps the stanza name directly to pg_cluster, allowing multiple clusters to share one storage service without sharing a backup identity:

repository
├── backup/
│   ├── pg-meta/          # base backups for pg-meta
│   └── pg-test/          # base backups for pg-test
└── archive/
    ├── pg-meta/          # archived WAL for pg-meta
    └── pg-test/          # archived WAL for pg-test

Repository Abstraction

Two parameters define repository selection. pgbackrest_method chooses one repository name, and pgbackrest_repo is a dictionary of candidate definitions. Pigsty v4.5.0 renders only the selected pgbackrest_repo[pgbackrest_method] entry as pgBackRest repo1; listing both local and minio does not enable two active repositories.

pgbackrest_method: local          # local, minio, or a custom key below
pgbackrest_repo:
  local:
    path: /pg/backup
    retention_full_type: count
    retention_full: 2             # retain two full backups; a third may exist before expiration
  minio:
    type: s3
    s3_endpoint: sss.pigsty
    s3_region: us-east-1
    s3_bucket: pgsql
    s3_key: pgbackrest
    s3_key_secret: S3User.Backup
    s3_uri_style: path
    path: /pgbackrest
    storage_port: 9000
    storage_ca_file: /etc/pki/ca.crt
    block: y
    bundle: y
    bundle_limit: 20MiB
    bundle_size: 128MiB
    cipher_type: aes-256-cbc
    cipher_pass: pgBackRest       # replace this default secret in production
    retention_full_type: time
    retention_full: 14

The presets intentionally differ. local favors simplicity and fast local restore; it is unencrypted, unbundled, and retained by full-backup count. minio targets a remote Silo or compatible S3 repository, enabling encryption, bundles, block incremental backup, and time-based retention.

Rendering is mechanical: underscores in the chosen repository’s keys become hyphens and each key gets a repo1- prefix in /etc/pgbackrest/pgbackrest.conf. A custom cloud repository can therefore use pgBackRest options directly:

pgbackrest_method: s3
pgbackrest_repo:
  s3:
    type: s3                         # repo1-type=s3
    s3_endpoint: s3.us-west-1.amazonaws.com
    s3_region: us-west-1
    s3_bucket: <your_bucket>
    s3_key: <your_access_key>
    s3_key_secret: <your_secret>
    s3_uri_style: host
    path: /pgbackrest
    cipher_type: aes-256-cbc
    cipher_pass: <your_password>
    retention_full_type: time
    retention_full: 90

See Backup Repository for Silo, external S3-compatible storage, versioning, object locking, TLS, and credential details.


Archiving and Scheduling

When pgbackrest_enabled is true, as it is by default, the Patroni templates configure:

archive_mode: 'on'
archive_timeout: 300
archive_command: 'pgbackrest --stanza=<cluster> archive-push %p'

Base backups enter the system in two ways:

  • Initial backup: after bootstrapping a top-level primary, Pigsty attempts a backup when pgbackrest_init_backup is true. The task ignores backup failure and writes /etc/pgbackrest/initial.done only after success, so the marker means “completed,” not merely “attempted.”
  • Scheduled backup: pg_crontab installs jobs in the database superuser’s crontab. Its role default is an empty list; standard example configurations usually add a daily 01:00 full backup.
pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]

pg-backup [full|diff|incr] is a small wrapper around pgbackrest backup. With no argument it requests an incremental backup, which pgBackRest promotes to a full backup if no usable full exists.


Backups Follow the Primary

pgBackRest and the same scheduled job are installed on every PostgreSQL node, but pg-backup checks /pg/bin/pg-role and only proceeds on the current primary. Replicas fail fast rather than writing a competing backup.

That design decouples the backup schedule from the HA topology:

  • all members receive the same repository configuration and crontab;
  • after failover, the new primary becomes eligible for subsequent backups and WAL archiving without rewriting the schedule;
  • one current primary owns the authoritative write flow to a stanza.

With a non-local repository, Pigsty also adds pgBackRest after basebackup in Patroni’s create_replica_methods. Patroni tries basebackup first; if that method fails, it can restore a replica from the repository with pgbackrest --delta restore, shifting the copy load away from the primary.


Performance Defaults

The shipped pgBackRest template favors light production overhead and aggressive restore throughput:

Settingv4.5.0 behaviorRationale
Compressioncompress-type=zstBalance compression ratio and throughput
Backup/archive workersOne quarter of CPU, clamped to 2–4Limit competition with the database
Restore workersAll detected CPU, capped at 8Minimize restore time
Asynchronous archivearchive-async=y, spool under /pg/spoolBatch transfer without synchronous object-store latency
Archive queue limitarchive-push-queue-max=4GiBBound local spool growth
Fast backup startstart-fast=yRequest an immediate checkpoint
Incremental restoredelta=yReuse destination files that already match

The 4 GiB queue is a safety tradeoff: if the repository remains unavailable and the queue exceeds the limit, pgBackRest can discard queued archive files. PostgreSQL continues running, but the WAL archive becomes incomplete and a new full backup is needed to establish a new recovery chain. See How PITR Works.


Observability

When both backup and exporter settings are enabled, pgbackrest_exporter runs on each PostgreSQL node and exposes metrics on port 9854. The monitoring stack uses those metrics for backup age, type, size, duration, and error visibility.

Useful diagnostic entry points include:

EntryPurpose
pb infoShell helper for pgbackrest info using the configured stanza
/pg/log/pgbackrest/pgBackRest backup, archive, and restore logs
pg-backupManually request a backup on the primary: full / diff / incr

See Backup Administration for operational checks, then PITR Tradeoffs for policy design.

3.5.3 - PITR Tradeoffs

Repository location determines the failure domain, retention determines the recovery window, and backup frequency shapes restore time. Together they define a backup policy.

A backup is an insurance policy. Its premium is storage, network traffic, and operational work; its benefit is how much data can be recovered and how quickly service can return. There is no universal free policy: more history normally needs more capacity, while a shorter RTO normally needs newer backups and tested procedures.

Designing a policy means answering three questions: where is the repository, how long is history retained, and how often are backups taken?


Where: Choose the Failure Domain

Repository location is the most important decision because it defines which disasters the backup survives.

A local repository (pgbackrest_method: local) stores backups on the primary’s local filesystem. It is simple, fast, and has no remote service dependency. But data and backup normally share one host failure domain: loss of the machine, disk, or filesystem can destroy both. Local backup protects well against logical errors, but not total host loss unless /pg/backup is deliberately placed on independent storage.

An object-storage repository (pgbackrest_method: minio or a custom S3 definition) sends backups to Silo or S3. It becomes an independent disaster-recovery copy only when deployed outside the database host or site failure domain. Pigsty’s minio preset also enables AES-256-CBC repository encryption, bundling, and block incremental backup. Recovery throughput then depends on the network and storage service, and that service adds operational responsibility.

ScenarioRecommended repositoryReason
Development, test, demolocalMinimal dependencies; rebuild is acceptable
ProductionDedicated Silo or compatible S3 storageIndependent failure domain and encrypted repository
Cloud deploymentManaged S3-compatible or cloud object storage supported by pgBackRestIndependent storage and lower operational burden
Ransomware/complianceVersioned storage plus correctly configured object lock/retentionPrevent privileged database-host access from deleting protected versions

The backup repository is itself sensitive business data. Change the default access keys and cipher_pass, restrict access, protect credentials separately from the database hosts, and verify any object-lock policy. See Backup Repository.


How Long: Capacity and Recovery Window

Longer retained history generally consumes more storage, but compression, deduplication, block incremental backup, database change rate, and the mix of full/differential/incremental backups determine the actual amount. Measure real backup and WAL growth instead of relying on a fixed multiplier.

For an illustrative 100 GB database changing by 10 GB per day, before compression:

  • Daily full, retain two (local preset policy): about 200 GB of full backups plus WAL, commonly giving roughly a one-to-two-day window when every job succeeds.
  • Weekly full, daily incremental, retain full history by 14 days (minio preset policy): the oldest surviving weekly chain commonly produces roughly 14–21 days of coverage. Capacity must include multiple full backups, their incrementals, archived WAL, and transient retention-plus-one behavior during expiration.

The precise window is not the configuration number alone. It runs from the oldest usable backup chain to the newest WAL present in the surviving repository. pgBackRest’s time retention removes an old full only when another qualifying full can satisfy the period, and related incrementals and WAL follow the retained full chains. Check pig pb info, monitor archive health, and prove coverage with a restore.

Choose a window long enough to cover the delay between an error occurring and being detected. A dropped table may be noticed in minutes; slow corruption or a month-end reconciliation failure can take weeks to surface.


How Often: Backup Frequency and RTO

Restore time has two main components: restore a backup chain, then replay WAL to the target. Backup size and storage throughput shape the first; the distance between the chosen backup and target shapes the second.

WAL replay is largely serial. On a write-heavy database, restoring from a weekly full immediately before the next full can require nearly a week of replay. Daily incremental backups reduce that replay distance while transferring only changes since the previous backup. They still depend on a valid chain, so monitor and test the entire chain rather than only the newest file.

A useful rule is: within the available backup window and production load budget, take backups often enough that measured restore time meets the RTO.


Pigsty Presets

Pigsty provides two candidate repository definitions, but pgbackrest_method selects one for the generated repo1 configuration.

Standard policy: local repository and daily full backup. It is simple and restores through local I/O, making it suitable for development or environments where host-level disaster recovery is provided separately:

pgbackrest_method: local
pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]
# Local preset retains two full backups; actual coverage depends on successful jobs and WAL continuity.

Production policy: remote Silo/S3 repository, weekly full, daily incremental. It separates the repository failure domain and uses the encrypted minio preset:

pgbackrest_method: minio
pg_crontab:
  - '00 01 * * 1 /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'
# The preset retains full history by 14 days; weekly fulls commonly yield about 14–21 days.

Keeping both local and minio in pgbackrest_repo is not a dual-repository setup. They are alternative definitions, and the template renders only pgbackrest_repo[pgbackrest_method] as repo1. A genuine multi-repository pgBackRest design requires explicit advanced configuration plus an independently tested backup, expiration, and restore workflow; the two presets alone do not provide it.

Use Backup Policy for capacity modelling and schedule details.


A Backup Is Proven by Restore

Monitoring a successful backup job is necessary but insufficient. Add clone restore drills to routine operations so you can answer:

  1. Is the chain usable? Restore it end to end and validate data.
  2. What is the measured RTO? Database size and WAL volume change over time.
  3. Can the on-call operator execute the runbook? The first full exercise should not happen during an incident.

A clone recovery leaves the source cluster online but overwrites the designated destination cluster, so verify the exact target and use disposable infrastructure. See Declarative Recovery for the recovery interface.

3.5.4 - Declarative Recovery

Declare the desired pg_pitr recovery target and let pgsql-pitr.yml or pig orchestrate the recovery workflow.

The value of a backup system is realized at restore time, often during an incident when every minute matters. A traditional PITR procedure requires a long sequence of coupled manual steps: pause HA, stop PostgreSQL, prepare recovery settings, restore the backup, replay WAL, validate the target, rebuild metadata, and start the cluster again.

Pigsty applies the same approach used by declarative configuration to recovery: declare the recovery target, then let the orchestration tools stop the cluster, restore the data, replay WAL, and return control to the operator.


Declare a Recovery Target

Describe the target with the pg_pitr parameter and execute it with pgsql-pitr.yml. The most common form restores a cluster to a specific time:

./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": { "time": "2026-07-11 10:00:00+08", "action": "promote" }}'

The six recovery target types and the rest of the recovery behavior are expressed through fields in this parameter:

pg_pitr:                           # Recovery declaration; every field is optional
  cluster: pg-meta                 # Source backup stanza; defaults to this cluster
  type: time                       # default | time | xid | lsn | name | immediate
  time: '2026-07-11 10:00:00+08'   # Mutually exclusive with xid, lsn, and name
  exclusive: false                 # Stop before the target; inclusive by default
  action: promote                  # Explicit promotion; a targeted restore defaults to pause
  timeline: latest                 # Target timeline; latest by default
  set: latest                      # Starting backup set; selected automatically by default
  repo: { ... }                    # Temporary repository definition when not using local config
  backup: false                    # Move the old data directory to /pg/data-backup first
  archive: true                    # Preserve archiving; exploratory recovery can set false
  db_include: [ ... ]              # Restore only selected databases
  data: /pg/data                   # Destination data directory

See Restore Operations for the complete field reference and examples.


What the Playbook Does

pgsql-pitr.yml turns the manual recovery workflow into six stages and supports Ansible tags for staged execution:

StageAction
printPrint the source cluster, target, and restore command; this stage reports the plan and does not prompt for confirmation
pauseRun patronictl pause so Patroni does not intervene during maintenance
stopStop Patroni and PostgreSQL on replicas, then on the primary
pitrRender recovery settings, run an incremental pgBackRest restore, start PostgreSQL to replay WAL, wait for consistency, and print control data
etcdRemove stale cluster metadata from etcd so old and new timelines are not mixed
startStart Patroni again, resume HA management, and rebuild replicas

Several details are important:

  • Incremental restore: pgBackRest uses delta, so it rewrites only files that differ from the backup. For large databases, this can reduce RTO substantially.
  • Verification, not assumption: the playbook prints checkpoint LSN, timeline, and NextXID data from pg_controldata; an operator must still verify that the recovered business state is correct.
  • Rollback copy: with backup: true, the original data directory is moved to /pg/data-backup before recovery. A later run with backup: true removes an existing /pg/data-backup, so this is not a versioned snapshot store.
  • Staged execution: run -t down, -t pitr, and -t up separately when you want an operator checkpoint between phases. Completion of the pitr phase means PostgreSQL reached a consistent recovery state; for a time, XID, LSN, or named target, also confirm WAL replay reached that target.

The action field controls what happens at the target: promote opens a new timeline, pause waits at the target for inspection, and shutdown stops PostgreSQL there. A targeted recovery defaults to pause when action is omitted. To preserve a manual gate for pause or shutdown, run the stages separately; a one-shot recovery should choose promote explicitly. The playbook performs the mechanical workflow, but it cannot decide whether the recovered data is correct.


Command-Line Recovery with pig

The pig CLI provides single-instance PITR orchestration directly on a database node, without requiring the management node or an Ansible environment:

pig pitr -t "2026-07-11 10:00:00+08"    # Recover to a point in time
pig pitr --xid 250000 -X                # Stop before transaction 250000
pig pitr -d                             # Replay through the WAL archive
pig pitr -I --no-restart                # Prepare immediate recovery and leave PostgreSQL stopped

pig pitr validates the target, stanza, and available backups; stops Patroni and PostgreSQL; performs the restore; optionally starts PostgreSQL; and prints post-recovery instructions. For a Patroni-managed data directory, Patroni remains stopped afterward. Validate the data, then use pig pt start to return the instance to HA management. This single-node workflow does not clear etcd, rebuild replicas, or automatically rejoin the cluster, and it refuses destructive forced shutdown unless --force-stop is supplied explicitly.

The lower-level pig pb commands wrap pgBackRest: pb info lists backups, pb backup creates a backup, and pb restore performs a raw restore. There is a deliberate safety boundary: pig pb restore refuses to run while Patroni still manages the instance, because Patroni could restart PostgreSQL during the restore. Use pig pitr or pgsql-pitr.yml for Patroni-managed instances.


In-Place and Clone Recovery

The same mechanism supports two different workflows:

DimensionIn-place recoveryClone recovery
MethodRoll the production cluster backRestore a source backup into a different cluster
DowntimeRequired during recoveryThe source production cluster remains online
EffectDiscards all writes after the targetDoes not affect the source; the destination is overwritten and can be retried
Best forWhole-cluster corruption or disaster recoveryRecovering deleted objects, audit work, and recovery drills

For a clone recovery, the cluster field names the source backup stanza. This example restores the historical state of pg-meta into pg-test without stopping the source cluster:

./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2026-07-11 10:00:00+08", "archive": false, "action": "promote" }}'

Exporting an accidentally deleted table from the clone and importing it into production is generally safer than rolling the entire production cluster back. See Clone a Database Cluster for the complete workflow and cleanup steps.


After Recovery

Recovery completion is not the end of the incident. Include these steps in the closeout checklist:

  1. New timeline, new backup: after promotion, create a full backup with pg-backup full so a recoverable window exists on the new timeline.
  2. Archiving state: if an exploratory restore used archive: false, restore normal archiving as described in Post-Recovery.
  3. Clone cleanup: a clone’s cluster identity and source backup stanza do not match. Recreate the destination stanza before enabling its own backups; see Clone a Database Cluster.

The tools execute the procedure; operators still decide the target, whether to restore in place or into a clone, and whether the recovered data is correct. Continue with PITR Scenarios for that decision framework.

3.5.5 - PITR Scenarios

How to choose a recovery target and workflow for accidental DML, dropped objects, defective releases, investigations, and site loss — and why recovery drills must be routine.

During an incident, the most expensive resource is often decision time. Pigsty can orchestrate the mechanical recovery steps, but an operator must still answer three questions: what is the target, should recovery be in place or into a clone, and how will the result be validated?

Read and rehearse this framework before an incident.


Decision Framework

ScenarioTypical problemRecommended workflowTarget
Accidental DMLDELETE or UPDATE affects the wrong rowsClone, validate, then copy back datatime / xid
Dropped table, schema, or databaseDROP or an incorrect migrationClone, validate, then copy back objectstime / name
Defective release or batch corruptionSoftware writes incorrect data for a periodClone and compare before choosing repair or cutovertime / xid
Audit, investigation, or forensicsInspect historical stateClone and hold at the target for inspectiontime / lsn
Whole-cluster or site lossHosts or storage are gone or encryptedRecover in place on replacement infrastructuredefault / time

Two principles apply throughout:

  • Stop the damage first. Pause the defective application or remove its write access before choosing a target. The window is moving, but a rushed restore to the wrong cluster can cause a second incident.
  • Prefer a clone while production is usable. It leaves the source untouched, supports repeated target selection, and allows validation before export or cutover. It does overwrite the designated destination cluster. In-place recovery is appropriate when the whole cluster is unusable or the business has explicitly accepted rolling every database back.
flowchart TD
    A["Data error detected"] --> B["Contain the source of bad writes"]
    B --> C{"Can production still serve?"}
    C -->|Yes| D["Clone recovery<br/>validate and copy back or cut over"]
    C -->|No| E["In-place recovery<br/>or rebuild on new infrastructure"]
    D --> F["Validate, take a new backup, review the incident"]
    E --> F

Accidental DML

A DELETE without WHERE, an incorrect UPDATE, or a defective batch job is the most common PITR use case.

First locate the error using application logs, PostgreSQL logs, metrics, or audit records. A timestamp is usually sufficient. If the exact transaction ID is known, xid plus exclusive: true can stop immediately before that transaction.

# If the deletion occurred around 10:15, clone the state from 10:14
./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2026-07-11 10:14:00+08", "archive": false, "action": "promote" }}'

# If the deleting transaction was 250000, stop immediately before it
./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "xid": "250000", "exclusive": true, "archive": false, "action": "promote" }}'

Validate the recovered rows, then copy only the required data back with pg_dump, COPY, or an application-specific reconciliation procedure. If a configured delayed cluster is still inside its delay window, reading from it may be faster than PITR.


Dropped Objects

The same approach applies to DROP TABLE, DROP DATABASE, or a migration executed in the wrong environment, with an even stronger preference for a clone. Rolling the entire production cluster back to recover one object also discards every legitimate write after the target.

Restore a separate destination to before the DDL, validate the object, export it with pg_dump, and import it into production. For planned high-risk changes, create a named restore point with pg_create_restore_point() beforehand; a name target then removes timestamp ambiguity.


Defective Release or Batch Corruption

When a faulty release corrupts data for hours, the challenge is usually identifying the last clean state and the full impact. A clone provides a clean comparison set. Restore repeatedly to candidate times, compare it with production, and decide whether to copy back corrected rows or cut over to a recovered cluster.

This decision needs application-owner validation: a successful PostgreSQL restore proves consistency at a target, not that the target represents correct business state.


Audit and Investigation

Questions such as “what was this balance at month end?” require historical state. Restore into a separate destination, stop at a time, LSN, XID, or named restore point, and inspect without altering the source.

action: pause is the targeted-restore default and holds recovery at the target for inspection; it does not itself configure read-only access or create a separate cluster. The inventory limit and cluster source field determine the destination workflow. Run -t down, -t pitr, and -t up separately when you need an operator gate before promotion, and enforce read-only access explicitly if the investigation requires it. immediate means “stop at the first consistent point,” not “choose a historical timestamp.”


Site Loss

If every database host is destroyed or encrypted, HA cannot help. Recovery requires a repository and the other control-plane assets to have survived outside that failure domain. That survivor can be Silo/S3, another protected host or filesystem, or another tested pgBackRest backend; a remote object store is recommended but the essential property is independent failure-domain survival.

Rebuild hosts, restore the declarative inventory, credentials, and PKI, point the cluster at the surviving repository, then restore through the end of archived WAL:

./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {"action": "promote"}}'

Inventory and backup data are necessary but not sufficient. Preserve installation media or package repositories, repository credentials and encryption passwords, CA material, custom files, DNS dependencies, and an independently accessible runbook. Keep secrets encrypted and separate from both the database hosts and ordinary source control.


Make Recovery a Routine Drill

The first end-to-end execution of any of these workflows should not occur during a production incident. Use a disposable destination to rehearse clone recovery regularly and after material architecture changes. Measure three outcomes:

  1. Usability: can the backup and complete WAL chain be restored and validated?
  2. RTO: how long does the actual restore and replay take now?
  3. Operator readiness: can the on-call engineer identify source and destination, select a target, and follow the safety gates?

See Restore Operations and Clone a Database Cluster for the task-level runbooks.

3.6 - Monitoring System

How Pigsty’s monitoring system is architected and how monitored targets are automatically managed.

Pigsty’s monitoring system has three pillars—metrics, logs, and alerting—and is available out of the box. Logs and alerts are also important inputs for audit and traceability. It can monitor clusters managed by Pigsty, existing PostgreSQL clusters, and external RDS services.


Monitoring Targets

Pigsty monitoring covers these core targets:

  • PostgreSQL clusters and instances (SQL performance, connections, replication, transactions, checkpoints, WAL)
  • Infrastructure components (Grafana, VictoriaMetrics, Alertmanager, Nginx, etc.)
  • Host nodes (CPU, memory, disk, network, kernel)
  • Key middleware (ETCD, MINIO, REDIS, JUICE, VIBE, etc.)

Technology Stack

ComponentPurpose
GrafanaVisualization dashboards, unified entry point, alert views
VictoriaMetricsTime-series metric ingestion, storage, and query
VictoriaLogsStructured log ingestion, indexing, and search
VMAlert + AlertmanagerAlert rule evaluation and notification delivery
Exporter / AgentDatabase/system metric exposure and log forwarding

Onboarding Modes

Pigsty supports three monitoring onboarding modes:

ModeUse CaseEntry
FULLDatabase is deployed and managed directly by PigstyPGSQL Monitoring System
MANAGEDExisting PostgreSQL cluster with SSH-manageable nodesMonitor Existing Cluster
RDSCloud database accessible only by connection stringMonitor RDS

Continue Reading

3.7 - Security and Compliance

Pigsty manages authentication, authorization, encryption, audit, backup, and recovery as code, with a clear path from the default baseline to production hardening.

The database is usually the most sensitive component in an information system: it stores the most valuable data, so attacks and failures can have the most serious consequences. Database security is not a feature that can be enabled with one switch. It is the combined answer to a series of questions: Who can connect? What can they do after connecting? Can traffic be intercepted? Are operations recorded? Can damaged, lost, or deleted data be recovered?

Pigsty turns these answers into an out-of-the-box security baseline and manages it through declarative configuration: HBA rules, roles and privileges, certificates, encryption, backups, and audit policies are declared as parameters in the inventory, then rendered and applied by idempotent playbooks.

This Security as Code approach is itself an important security practice. Policies can be versioned, reviewed, and traced, while one inventory provides a consistent baseline across many instances. When an auditor asks who can access a database, you can start from a readable YAML declaration, then verify the generated HBA rules and database grants against the running system.


Security as Code

In traditional operations, security settings are often scattered across the environment: pg_hba.conf on one server, a GRANT statement executed manually by a DBA, or a firewall rule opened temporarily during an incident. Over time, documentation and actual state can drift, making it difficult to determine which rule set each instance is using.

Pigsty takes a different approach: security policy is part of the cluster definition and lives alongside other cluster properties.

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_users:                     # Who may log in: account, role, and expiration
      - { name: dbuser_app ,password: '<unique-random-password>' ,roles: [dbrole_readwrite] ,expire_in: 365 }
    pg_databases:                 # Databases and their isolation policy
      - { name: app ,owner: dbuser_app ,revokeconn: true }
    pg_hba_rules:                 # Who may connect, from where, and how
      - { user: dbuser_app ,db: app ,addr: 10.1.0.0/16 ,auth: ssl ,order: 50 ,title: 'app access via ssl' }

Users, privileges, and HBA rules are described declaratively, and playbooks apply them idempotently to every cluster instance. New instances inherit the same policy, and Git history records security configuration changes. Manual GRANT statements, runtime parameter changes, and edits to node files can still cause drift, so production environments should compare declared and actual state regularly.


Default Security Baseline

Reasonable defaults reduce omissions. The following capabilities are enabled in the default Pigsty configuration:

CapabilityDefault BehaviorRelated Parameter
Password hashingNew or updated PostgreSQL passwords use SCRAM-SHA-256pg_pwd_enc
Data checksumsPage checksums are enabled during cluster initialization to detect silent corruptionpg_checksum
Server-side TLSPostgreSQL server certificates are installed and ssl is enabled, so TLS connections are accepted
Local CAA self-signed CA is created automatically for managed component certificatesca_create
etcd encryption and authenticationTLS for client and peer traffic, plus RBAC password authenticationetcd_root_password
MINIO object storage HTTPSSilo backup traffic uses HTTPS by defaultminio_https
Nginx HTTPSWeb ingress listens on both ports 80 and 443 by defaultnginx_sslmode
HBA rulesLayered access: local ident, intranet password authentication, and SSL required for public administrator accesspg_default_hba_rules
Roles and privilegesA four-tier role model and default privilege templates provide a least-privilege baselinepg_default_roles
Backup and recoverypgBackRest is enabled by default, with two full backups retained in the local repositorypgbackrest_enabled
FirewallZone mode trusts intranet CIDRs and exposes only required ports to public networksnode_firewall_mode
Restricted sudoSudo access for the database OS user is limited to the required command setpg_dbsu_sudo

Hardening with Trade-offs

The default configuration targets deployments on a trusted intranet. Some controls require explicit enablement because they impose performance or compatibility costs, or require decisions from the operator:

  • Default configurations and examples contain publicly documented default passwords for quick starts and local testing. Before production deployment, use ./configure -g to randomize the credentials it recognizes, then check the pgBackRest encryption passphrase, Silo users in ha/safe, and all custom values.
  • TLS is disabled by default for the Patroni REST API and PgBouncer (patroni_ssl_enabled, pgbouncer_sslmode); enable it explicitly with the certificates already issued.
  • Password strength checks (passwordcheck) and the audit extension (pgaudit) are disabled by default. Confirm package availability, then configure preloading and policy before use.
  • SELinux defaults to permissive. Demo configurations also expose port 5432 through the firewall; remove that exception in production.
  • The local backup repository is not encrypted by default. The remote minio repository preset uses AES-256 encryption by default, but its default encryption passphrase must be changed.

The ha/safe hardening template combines TLS, certificate authentication, password checks, and backup encryption. Together with the consistency-first CRIT parameter template, it provides a practical starting point. Public credentials, audit extensions, and the failure model still require explicit review. See the Security Model for the complete upgrade path.


This Chapter

SectionQuestion Answered
Security ModelWhere is the root of trust? How many defensive layers exist? How should the baseline be hardened?
AuthenticationWho can connect? How is identity proven? How are HBA rules declared and applied?
Access ControlWhat can a connected user do? How does least privilege become the default?
Encrypted CommunicationHow is traffic encrypted? Who issues, distributes, and rotates certificates?
Data SecurityHow is data kept intact, recoverable, confidential, and traceable?
ComplianceHow do security capabilities map to MLPS and SOC 2 controls?

Beyond the conceptual model, these pages provide operational security guidance:

3.7.1 - Security Model

Pigsty trust boundaries and defense in depth, with the admin node as a high-trust control plane and a path from the default baseline to production hardening.

Before examining individual security features, answer two more fundamental questions: Where is the root of trust? and How many defensive layers exist? The first determines what deserves the strongest protection. The second determines what remains when one layer fails.


Trust Boundaries

Pigsty is an Ansible-based declarative deployment system. Like other control-plane systems, its admin node is the control plane and the node that requires the strongest protection.

RoleAssets and Privileges
Admin nodeThe pigsty.yml inventory, which normally contains system and application credentials; the CA private key; SSH administration access to every node
INFRA nodesMonitoring and alerts, DNS, Nginx ingress, and software repositories
Database nodesDatabase instances, local dbsu, and restricted sudo
ClientsDatabase credentials or client certificates; access through service ports, HBA, and authentication

These roles hold different capabilities; they do not form a simple linear hierarchy. Three assets are especially important:

  1. The pigsty.yml inventory contains component passwords and credentials. Strictly control access to the admin node and to the configuration repository when Git is used.
  2. The CA private key, files/pki/ca/ca.key, is the trust anchor for the deployment. Anyone holding it can issue an arbitrary trusted certificate. The file uses mode 0600 inside a 0700 directory; keep an offline backup.
  3. The administration user’s SSH private key lets the admin node manage every enrolled node with passwordless sudo. It is effectively root access to the managed fleet.

Pigsty’s security policy states this boundary explicitly: an attack that requires admin-node access, or possession of both pigsty.yml and the CA private key, is not treated as a product vulnerability. These are high-trust control-plane assets by design and must be protected accordingly.


Seven Defensive Layers

Defense in depth does not ask one mechanism to solve every problem. It combines controls so that one failure does not remove all protection. Pigsty’s security capabilities can be summarized as seven layers:

#LayerMechanismsDetails
1Network boundaryFirewall zones, constrained listen addresses, centralized ingressThis page
2Transport encryptionLocal CA and TLS between componentsEncrypted Communication
3AuthenticationHBA rules, SCRAM passwords, client certificatesAuthentication
4Access controlRole model, default privileges, database isolationAccess Control
5Host securitySELinux, restricted sudo, dedicated OS usersThis page
6Data securityChecksums, backup and encryption, PITR, deletion safeguardsData Security
7Audit trailDDL and connection logs, audit extensions, centralized logsData Security

Layers 2, 3, 4, 6, and 7 have dedicated chapters. The following sections cover the network and host layers.

Network Boundaries

Pigsty enables a firewall during node provisioning (node_firewall_mode defaults to zone), using firewalld or ufw according to the operating system. Intranet CIDRs (10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16, defined by node_firewall_intranet) enter the trusted zone. Public networks can reach only ports declared in node_firewall_public_port, which defaults to 22 for SSH and 80/443 for web traffic.

The default demo inventory, pigsty.yml, also exposes port 5432 for local evaluation. Remove it in production. If direct database access is required, restrict sources to explicit CIDRs with security groups, host firewalls, and HBA.

PostgreSQL listens on all addresses by default (pg_listen: 0.0.0.0). The effective access boundary is the combination of listen addresses, firewall rules, and HBA. Stricter environments can constrain the listener:

pg_listen: '${ip},${vip},${lo}'   # Host IP, cluster VIP, and loopback only

The default firewall does not expose Grafana, VictoriaMetrics, or other web infrastructure directly to public networks. External web access normally enters through the Nginx portal. Database traffic enters through HAProxy service ports. Fewer entry points are easier to harden and audit.

Host Security

The central host-level rule is: each OS user receives only the privileges required for its job.

  • The database superuser postgres (pg_dbsu) has no password by default and can enter the database only through local ident authentication. pg_dbsu_sudo defaults to limit, allowing passwordless systemctl operations for database services and log viewing rather than unrestricted root access.
  • The administration user (node_admin_username, default dba) is used by operators and playbooks and receives passwordless sudo (nopass) by default. Security-sensitive environments can set node_admin_sudo to all, which requires a sudo password, or limit, which restricts the command set.
  • node_selinux_mode defaults SELinux to permissive: violations are logged but not blocked, providing a baseline before moving to enforcing.

Pigsty does not manage the SSH server configuration. Disabling password login, restricting remote root login, and similar operating-system hardening belong in your host security baseline.


Hardening Levels

Security does not have to jump to its final state in one step. Pigsty provides an upgrade path in which each level builds on the previous one:

Level 1: default baseline. Out-of-the-box controls include SCRAM passwords, data checksums, a local CA and component certificates, layered HBA, a four-tier role model, default backups, and firewall zones. This level suits development, testing, and evaluation on a trusted intranet. Production still requires credential review, network-boundary review, and client verification.

Level 2: randomized credentials. Default passwords are documented publicly and must be changed in every network-exposed deployment. Add -g when generating configuration to randomize built-in parameters and example credentials recognized by the configuration wizard:

./configure -g    # --generate: randomize recognized default credentials

This option does not replace the pgBackRest cipher_pass, every Silo example credential in ha/safe, or user-defined values. See the Default Credentials Checklist for the complete scope.

Level 3: policy hardening with the ha/safe template. conf/ha/safe.yml combines several controls into a starting point for further customization:

  • TLS and certificate authentication: the main TCP HBA rules use ssl, public administrator access uses a client certificate, PgBouncer uses require, and the Patroni API uses HTTPS. Local ident and selected localhost password rules remain.
  • Password policy: passwordcheck is preloaded explicitly, and built-in users declare expire_in. Example passwords in the template still require review and replacement.
  • Reduced attack surface: listen addresses are limited to ${ip},${vip},${lo}, and public connection-pool access by monitoring and administration accounts is denied explicitly.
  • Backup encryption: pgBackRest uses the remote minio repository preset with AES-256-CBC. pgBR.${pg_cluster} is a predictable example value and must be replaced.
  • Security extensions: passwordcheck, credcheck, pgaudit, pgsodium, anonymizer, and related extensions are installed. Installation does not preload, create, or configure an extension.

Level 4: database hardening with the crit.yml parameter template. The safe template selects the CRIT parameter template for consistency-first workloads. Compared with the general oltp template, it:

  • forces data checksums regardless of pg_checksum;
  • enables strict synchronous replication (synchronous_mode_strict), blocking writes that require synchronous acknowledgment when no synchronous replica is available;
  • logs connection and disconnection events; PostgreSQL 18 also separates connection receipt, authentication, and authorization stages;
  • configures watchdog as automatic, which activates only when a usable device exists.

Strict synchronous mode targets preservation of acknowledged transactions, but still depends on synchronous_commit, synchronous replica state, and failover eligibility. Validate RPO with failure exercises on the target topology.

You can also select individual controls instead of adopting the complete template:

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1 , pg_role: primary }
    10.10.10.11: { pg_seq: 2 , pg_role: replica }
    10.10.10.12: { pg_seq: 3 , pg_role: replica }
  vars:
    pg_cluster: pg-meta
    pg_conf: crit.yml                    # Use the CRIT database parameter template
    patroni_ssl_enabled: true            # Enable HTTPS for the Patroni API
    pgbouncer_sslmode: require           # Require TLS for PgBouncer
    pg_listen: '${ip},${vip},${lo}'      # Constrain listen addresses
    pg_libs: '$libdir/passwordcheck, pg_stat_statements, auto_explain'  # Password strength checks

Next

3.7.2 - Authentication

Pigsty manages PostgreSQL and PgBouncer HBA rules declaratively, combining SCRAM passwords and client certificates to define who may connect and how identity is proven.

PostgreSQL uses pg_hba.conf for Host-Based Authentication: who may connect, from where, to which database, and how they must prove their identity.

The mechanism is powerful, but expensive to maintain manually across a cluster. Primary and replica instances may require different rules, and every instance stores its own configuration in the data directory. Without a common declaration and refresh process, rules can drift between instances.

Pigsty applies the same declarative configuration model here: HBA rules are part of the inventory and are rendered and distributed consistently by playbooks.


HBA as Code

Cluster HBA policy combines two parameter groups: the global defaults in pg_default_hba_rules and cluster-specific additions in pg_hba_rules. The PgBouncer connection pool has two independent counterparts: pgb_default_hba_rules and pgb_hba_rules.

A rule can use either of two forms. The recommended alias form keeps one semantic rule on one line:

pg_hba_rules:
  - { user: dbuser_app ,db: app ,addr: 10.1.0.0/16 ,auth: ssl ,order: 50 ,title: 'app user access via ssl' }

The raw form supplies a literal pg_hba.conf line for cases the aliases cannot express.

In addition to user, address, database, and authentication method, each rule has two control fields:

  • order: render order. HBA uses first-match semantics, so order is priority. By convention, 0-99 is reserved for high-priority user rules, 100-999 for defaults, and rules without order come last.
  • role: instance-role filter. common and default apply to every instance; primary, replica, offline, standby, and delayed apply only to matching instances. A role: offline rule is also rendered on instances marked with pg_offline_query. The same declaration therefore produces the appropriate rules for each instance role without maintaining primary and replica files manually.

After editing the declaration, apply it with the wrapper script. The rules are rendered again and reloaded:

bin/pgsql-hba pg-meta          # Render and apply HBA rules for pg-meta

pg_hba_rules appends rules; it does not automatically narrow broader defaults. To establish a stricter boundary, review pg_default_hba_rules as well, then inspect the generated pg_hba.conf on every instance.


Address and Authentication Aliases

The alias form gives common cases semantic names. Values in addr expand into concrete address blocks:

AliasExpands ToMeaning
localUnix socketLocal socket only
localhostUnix socket, 127.0.0.1/32, and ::1/128Local host
admin<admin_ip>/32Admin node
infra/32 address of each INFRA nodeInfrastructure nodes
cluster/32 address of every cluster memberCluster-internal traffic
intra10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16Intranet CIDRs, customizable with node_firewall_intranet
world0.0.0.0/0 and ::/0Any address
CIDRUnchangedCustom network

Values in auth select the authentication method and whether TLS is mandatory:

AliasAuthentication MethodNotes
denyrejectExplicit rejection
trusttrustUnconditional access; use with care
pwdscram-sha-256 or md5Follows pg_pwd_enc; SCRAM by default
shascram-sha-256Force SCRAM
md5md5Compatibility for legacy clients
sslhostssl with password authenticationPassword authentication over mandatory TLS
ssl-shahostssl with scram-sha-256Mandatory TLS and SCRAM
certhostssl with certClient certificate authentication
ident, osident (peer in PgBouncer)OS user mapping
peerpeerLocal OS user

The user field supports four placeholders, replaced with actual user names during rendering: ${dbsu} (superuser), ${repl} (replication user), ${monitor} (monitoring user), and ${admin} (administration user). A +role prefix matches all members of that role.

Do not confuse transport enforcement with server verification: auth: ssl requires TLS but does not require the client to verify the server identity. Security-sensitive clients should also use sslmode=verify-full with a trusted CA; see Encrypted Communication.


Default Rules Explained

Pigsty’s default HBA policy follows a simple rule: the farther the source, the stronger the requirement. These are the PostgreSQL defaults from the source configuration:

pg_default_hba_rules:             # postgres default host-based authentication rules, order by `order`
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}

Layer by layer:

  • Local access is most trusted: postgres can enter only through a local Unix socket with ident. No password is required, but remote login is impossible. This is why dbsu has no password by default.
  • The intranet comes next: replication and application accounts use SCRAM password authentication on the intranet. Remote monitoring and administration access primarily originates from INFRA nodes.
  • Public sources are strictest: only the administrator may connect from any address by default, and the connection requires both a password and TLS.

PgBouncer defaults are more restrictive: public access for monitoring and administration accounts is explicitly denied, while application users are limited to localhost and intranet sources.

The default +dbrole_offline rule does not set role and therefore applies to every instance. To restrict offline users to pg_role: offline or instances with pg_offline_query: true, add role: offline explicitly to the corresponding HBA rule.

This default policy favors usability: application accounts can connect from the intranet with password authentication. The ha/safe template changes the main TCP rules to ssl and requires administrators outside the intranet to present a client certificate (cert); local ident and selected localhost password rules remain.


Password Policy

Pigsty uses PostgreSQL’s recommended scram-sha-256 password storage by default (pg_pwd_enc). Downgrade to md5 only for legacy client compatibility.

Before executing ALTER USER ... PASSWORD, the password workflow temporarily disables statement logging (SET log_statement TO 'none') to keep passwords out of PostgreSQL logs. Plaintext passwords still appear in the inventory, and rendered user SQL is written to /pg/tmp/pg-user-<name>.sql with mode 0640. The related Ansible tasks do not use no_log consistently. Restrict access to the admin node, configuration repository, and automation output, and avoid --diff on tasks containing credentials.

Password strength is not enforced by default. If required, preload passwordcheck or the more configurable credcheck:

pg_libs: '$libdir/passwordcheck, pg_stat_statements, auto_explain'   # Reject weak passwords

The ha/safe template sets this pg_libs value explicitly. Selecting the CRIT parameter template alone does not load passwordcheck.

Declare account lifetime with expire_in (days after creation) or expire_at (absolute date), then combine it with the organization’s rotation process:

pg_users:
  - { name: dbuser_app ,password: '<unique-random-password>' ,roles: [dbrole_readwrite] ,expire_in: 365 }

Certificate Authentication

Passwords can be phished, reused, or guessed. For privileged accounts such as administrators, use auth: cert in HBA to require client certificate authentication. The client must present a certificate signed by the local CA whose CN matches the database user name. When the HBA rule accepts only cert, a leaked password alone cannot authenticate.

Issue client certificates with the built-in cert.yml playbook:

./cert.yml -e cn=dbuser_dba                  # Issue a 20-year client certificate by default
./cert.yml -e cn=dbuser_dba -e expire=365d  # Or specify a shorter lifetime

The certificate and key are stored in files/pki/misc/<cn>.crt and files/pki/misc/<cn>.key. Deliver the private key through a controlled channel. The client should still use verify-full to authenticate the database server; see Encrypted Communication.


Connection Pool and Component APIs

The database is not the only authenticated entry point.

The PgBouncer connection pool uses an independent HBA policy and user list. pgbouncer_auth_query is disabled by default, so only users declared with pgbouncer: true are written to userlist.txt and can authenticate through the pool. Re-evaluate the login scope before enabling dynamic authentication queries.

The Patroni REST API carries high-availability control operations such as restart, switchover, and configuration reload. Write operations require HTTP Basic authentication (patroni_username and patroni_password) and are restricted by source-address allowlists. When patroni_ssl_enabled is enabled, the API uses HTTPS throughout.

Credentials for Grafana, the HAProxy administration interface, the object-storage backend selected by the MINIO module, etcd, and other components are also declared in the inventory. See the Default Credentials Checklist for the full list and update guidance.


Next

3.7.3 - Access Control

Pigsty turns least privilege into reusable declarative cluster configuration through a built-in four-tier role model and default privilege templates.

Authentication answers “Who are you?” Authorization answers “What may you do?”

Privilege failures rarely result from a lack of mechanisms—PostgreSQL GRANT and REVOKE are sufficiently precise. The usual problem is the absence of conventions that are applied by default: an application account is made the owner at launch, temporary superuser access is not revoked after troubleshooting, or grants are missed when new tables are created and cause failures in production.

Pigsty provides an out-of-the-box access control model as a starting point: four role tiers, default privileges, and database isolation. It reduces per-database manual grants, but operators must still assign roles according to business boundaries and review effective privileges regularly.

pigsty-acl.jpg


Role System

Pigsty creates four business roles by default. They cannot log in and are used as privilege groups:

RoleAttributeInheritsPurpose
dbrole_readonlyNOLOGINGlobal read-only access
dbrole_readwriteNOLOGINdbrole_readonlyGlobal DML access; the default choice for application accounts
dbrole_adminNOLOGINdbrole_readwrite, pg_monitorObject creation and DDL for administration and release workflows
dbrole_offlineNOLOGINIndependent read-only role that can be restricted to offline instances through HBA

Pigsty also creates four system users, each with a specific responsibility:

UserAttributePurpose
postgresSUPERUSERDatabase superuser; no password and local ident login only
replicatorREPLICATIONStreaming replication and backup, with pg_monitor and read-only privileges
dbuser_dbaSUPERUSERRoutine administration user that inherits dbrole_admin
dbuser_monitorMonitoring user with only pg_monitor and read-only privileges

Application accounts join role groups through the roles field and inherit their privileges:

pg_users:
  - { name: dbuser_app    ,password: '...' ,roles: [dbrole_readwrite] }  # Regular application account
  - { name: dbuser_report ,password: '...' ,roles: [dbrole_readonly]  }  # Read-only reporting account
  - { name: dbuser_etl    ,password: '...' ,roles: [dbrole_offline]   }  # Offline ETL account

The role system is itself declarative (pg_default_roles) and can be customized. This parameter is a complete list. Preserve all required system users and default roles when changing it, and check references from HBA rules, default privileges, and scripts at the same time.


Default Privileges

Roles answer “Who receives a privilege?” The other half of the problem is: How do newly created objects receive the correct privileges automatically?

PostgreSQL provides ALTER DEFAULT PRIVILEGES. Pigsty declares these rules through pg_default_privileges:

pg_default_privileges:            # Apply these privileges to new objects created by managed identities
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin

The read-only role receives query and function execution privileges, the read-write role adds DML, and the administrator role adds the supporting privileges required for object management.

Ownership Convention

Default privileges have an often-missed prerequisite: they apply only to objects created by identities for which those defaults were configured. Pigsty configures default privileges for:

  • the database OS user pg_dbsu, which defaults to postgres;
  • the administration user pg_admin_username, which defaults to dbuser_dba;
  • dbrole_admin;
  • each database owner declared in pg_databases.

Application DDL should normally run as the declared database owner. Platform administration and release workflows can use dbuser_dba or first execute SET ROLE dbrole_admin. Objects created directly by other users do not enter this default privilege model unless ALTER DEFAULT PRIVILEGES is also configured for those users.

This is PostgreSQL behavior, not a Pigsty limitation: default privileges follow the object creator; they do not automatically propagate from the database or the session login name.


Database Isolation

PostgreSQL grants CONNECT on databases to PUBLIC by default. If HBA also permits a connection, a login role may enter a database it does not own. This default is particularly important to tighten when several applications share a cluster.

Set revokeconn in a database definition to revoke public connection access:

pg_databases:
  - { name: app_a ,owner: dbuser_a ,revokeconn: true }
  - { name: app_b ,owner: dbuser_b ,revokeconn: true }

When enabled, CONNECT is revoked from PUBLIC and granted explicitly to the replication, monitoring, and administration users and to the database owner. The owner receives GRANT OPTION and can decide who else may connect. Without additional grants or inherited roles, the app_a account cannot connect to app_b.

Cluster initialization also revokes CREATE from PUBLIC on the database and the public schema:

REVOKE CREATE ON DATABASE app FROM PUBLIC;
REVOKE CREATE ON SCHEMA public FROM PUBLIC;

Ordinary users can no longer create objects freely in public databases or schemas, reducing risks from unsafe search_path settings and object shadowing. PostgreSQL 15 tightened the default CREATE privilege on the public schema; Pigsty applies the same boundary consistently across all supported major versions.


Offline Role and Instance Isolation

dbrole_offline provides an independent set of read-only privileges for ETL, reporting, and ad hoc queries. The role controls object privileges only; it does not automatically restrict which instance a user may connect to.

In the current default HBA rules, the intranet rule for +dbrole_offline does not set role and therefore applies to every instance. To restrict it to a dedicated pg_role: offline instance, or to a regular replica marked with pg_offline_query: true, modify that rule in the complete pg_default_hba_rules list:

pg_default_hba_rules:
  # Copy and retain all other default rules; change only the offline-role rule
  - { user: '+dbrole_offline', db: all, addr: intra, auth: pwd, role: offline, order: 650,
      title: 'allow offline users on offline instances' }

Defining pg_default_hba_rules replaces the entire default list; the example rule cannot be used alone. Expensive queries are limited to offline instances only when HBA filters by instance role and the user does not inherit another role allowed by broader rules. Resource isolation should also use a dedicated service endpoint, connection limits, and query resource controls.


Beyond the Database

Least privilege also applies at the host level:

  • The postgres superuser has no password and can log in only through local ident. Its sudo access defaults to a restricted set of database service and log commands (pg_dbsu_sudo: limit).
  • The monitoring user dbuser_monitor holds pg_monitor, the read-only role, and privileges on the dedicated monitor schema; it cannot write business tables by default.
  • The replication user replicator receives only the directory function privileges required for backup and recovery instead of broad superuser access.

Next

3.7.4 - Encrypted Communication

Pigsty provides a self-signed CA that issues certificates and distributes trust for managed components, creating a unified TLS foundation.

TLS can provide three separate protections: transport encryption, server authentication, and client authentication. Each must be configured independently. Enabling server-side TLS does not mean the client verifies the server identity, nor does it mean the server requires a client certificate.

The main operational cost of TLS is not the encryption algorithm but certificate issuance, distribution, trust, and rotation. Without centralized management, internal services often encrypt traffic while skipping certificate verification—or remain on plaintext connections.

Pigsty brings PKI under declarative management. During deployment it creates a local self-signed CA, issues certificates for managed components, and distributes trust so TLS is ready for use after installation.


Local CA

During the first deployment, Pigsty checks for a CA on the admin node and creates one when required:

FileDescriptionPermissions
files/pki/ca/ca.keyCA private key and root of trust for the deployment; protect it carefully0600, with directory mode 0700
files/pki/ca/ca.crtCA root certificate; safe to distribute0644
  • ca_create controls CA behavior. An existing private key and certificate are reused unchanged; if the certificate is missing but the private key exists, that key is used to issue a replacement certificate. ca_create: false only prevents creation of a missing CA private key. Deployment stops if ca.key is absent, preventing an unexpected trust root. Always back up and restore ca.key and ca.crt together.
  • ca_cn sets the CA certificate CN, which defaults to pigsty-ca. The key is RSA 4096.
  • The root CA is valid for 100 years, while component certificates default to 20 years (cert_validity: 7300d). The browser-facing Nginx certificate is an exception and currently defaults to 397 days.

Long default lifetimes reduce the initial maintenance burden for private infrastructure; they do not remove the need for production rotation. Organizations with an established certificate policy should shorten lifetimes and monitor expiration.


Trust Distribution

Issuing a certificate is only half of PKI. Every node must trust it. When a node is managed, Pigsty distributes the CA certificate to /etc/pki/ca.crt and links it into the operating system trust store:

  • EL family (RHEL, Rocky, Alma): link under /etc/pki/ca-trust/source/anchors/ and run update-ca-trust
  • Debian and Ubuntu: link under /usr/local/share/ca-certificates/ and run update-ca-certificates

Clients that use the OS trust store, such as curl, can then verify certificates signed by the Pigsty CA. The CA certificate is also published as ca.crt at the site root of the Nginx portal for browsers and external clients.

PostgreSQL libpq clients require special attention: by default they look for ~/.postgresql/root.crt and use sslmode=prefer, so they do not directly use the operating system trust store to verify the server identity.


Server Identity Verification

Security-sensitive PostgreSQL clients should use sslmode=verify-full and specify the Pigsty CA:

psql "host=pg-meta dbname=postgres user=dbuser_dba sslmode=verify-full sslrootcert=/etc/pki/ca.crt"

verify-full validates both the certificate chain and the connection host name. The DNS name or IP address used by the client must therefore appear in the server certificate SAN. External clients must install ca.crt or specify it with sslrootcert.


Certificate Matrix

The local CA issues certificates for the following components and places them under one trust chain:

ComponentCertificate Identity (CN)Deployment PathEncryption State
PostgreSQL<cluster>-<sequence>/pg/cert/server.{crt,key}Server-side SSL enabled by default; HBA determines whether it is mandatory
PgBouncerReuses the PostgreSQL certificate/pg/cert/TLS disabled by default (pgbouncer_sslmode)
PatroniReuses the PostgreSQL certificate/pg/cert/API HTTPS disabled by default (patroni_ssl_enabled)
etcd<instance-name>/etc/etcd/server.{crt,key}TLS for client and peer traffic
Silo<node-name>~minio/.minio/certs/Silo HTTPS is enabled by default (minio_https)
Kafka<cluster>-<sequence>/etc/kafka/pki/kafka.pemSASL_SSL/SSL with kafka_security: scram; defaults to plaintext
MySQL<instance-name>/etc/mysql/pki/server.{crt,key}Secure transport enforced; clients and group replication verify the certificate chain
Nginxpigsty, with portal domains in SAN/etc/nginx/conf.d/cert/HTTPS enabled by default (nginx_sslmode)
INFRA node<node-name>/etc/pki/infra.{crt,key}Available to infrastructure components

The encryption-state column reflects deliberate defaults:

  • Enabled at deployment: PostgreSQL accepts SSL connections; etcd uses TLS for client and peer traffic.
  • Encrypted by default: Object-storage backup traffic through the MINIO module and Nginx web traffic use HTTPS.
  • Disabled by default, available on demand: TLS for the Patroni REST API and PgBouncer is disabled by default, but certificates are already present. Enable it through the corresponding parameters; both are enabled in the ha/safe template.

Keep three states distinct: server-side SSL support does not force clients to use SSL, and neither state proves that the client verifies the server identity. HBA rules enforce encryption with auth: ssl or cert. Client sslmode and trust settings control server verification. The default rules require TLS only for administrator connections from arbitrary sources. The safe template changes the main TCP rules to ssl or cert while retaining local ident and selected localhost password rules.


Client Certificates

The built-in cert.yml playbook issues client certificates. The certificate CN represents the database user name for HBA cert authentication:

./cert.yml -e cn=dbuser_dba                  # Issue a 20-year client certificate by default
./cert.yml -e cn=dbuser_dba -e expire=365d  # Or specify a shorter lifetime

Results are stored in files/pki/misc/<cn>.key and files/pki/misc/<cn>.crt. Deliver private keys through a controlled channel and make them readable only by the corresponding user. The client certificate lets the server authenticate the client; the client must still use verify-full to authenticate the database server.


Using an Enterprise CA

If the organization already operates a PKI, Pigsty can issue certificates from that CA, or from an intermediate signed by the enterprise root. Place the certificate and private key at the expected paths; playbooks do not regenerate a CA when one already exists:

files/pki/ca/ca.key    # CA or intermediate CA private key
files/pki/ca/ca.crt    # Corresponding CA certificate

Also set ca_create: false. Deployment will then fail explicitly if the private key is missing instead of creating an unexpected trust root. This setting does not stop the role from reissuing the CA certificate when the private key exists but the certificate is missing, so verify and restore both files together.


Key Protection and Rotation

  • The CA private key exists only on the admin node. Together with pigsty.yml, it is one of the highest-trust assets in the deployment; see Trust Boundaries. Keep an offline backup.
  • If the CA private key is compromised, establish a new trust root and reissue every component and client certificate. Plan an overlap period in which both old and new CAs are trusted to avoid interrupting all connections at once.
  • Component certificate sources are stored under files/pki/<component>/ on the admin node; node certificates are deployment copies. Deleting only a node copy restores the same certificate rather than issuing a new one. To rotate, update or remove the corresponding source on the admin node, rerun the relevant playbook, then reload or roll the component as required.

Next

  • 🔑 Authentication: use HBA to decide who must use SSL or client certificates
  • 🔒 Data Security: encryption for stored data and backups
  • Compliance: evidence for certificate management

3.7.5 - Data Security

Protect PostgreSQL data integrity, recoverability, confidentiality, and traceability with checksums, backup and PITR, encryption, and audit logs.

Network boundaries, authentication, and access control reduce the likelihood of an incident. When hardware fails, credentials leak, or an operator makes a mistake, data-layer controls must limit the impact and support recovery.

Data security answers four questions: Is the data intact? Can it be recovered? If copied, does it remain confidential? Can you determine what happened?


Integrity

Bad disk sectors, memory bit flips, and storage firmware defects can cause silent data corruption: the data is damaged without an immediate error. Pigsty enables page checksums by default (pg_checksum: true). The cluster is initialized with data-checksums, so PostgreSQL calculates a checksum when writing a page and verifies it when reading.

Page checksums primarily detect corruption in storage media, the I/O path, or pages after they were written. They do not detect every memory error, logical error, or incorrect application write, and they do not replace backups.

The CRIT parameter template goes further: checksums are mandatory regardless of the parameter, and strict synchronous replication (synchronous_mode_strict) blocks writes that require synchronous acknowledgment when no synchronous replica is available. This mode targets preservation of acknowledged transactions, but it still assumes clients have not reduced synchronous_commit, a synchronous replica participates in the commit, and failover selects only a node containing the required WAL. Validate RPO through failure exercises on the target topology.


Recoverability

Replicas primarily handle node failures; backups handle accidental deletion, logical errors, cluster corruption, and broader disasters. High availability can shorten an interruption after primary failure, but replication also copies an accidental deletion to every replica. Backups are therefore indispensable.

Pigsty enables pgBackRest by default (pgbackrest_enabled). Base backups plus continuous WAL archiving provide Point-in-Time Recovery (PITR), allowing recovery to a target time within the retained backup and WAL window.

Select the backup repository with pgbackrest_method:

RepositoryLocationDefault RetentionEncryption
local (default)Local /pg/backup directoryLatest 2 full backupsNone
minioSilo or external S3-compatible object storage14 daysAES-256-CBC

Two additional controls reduce damage from accidental deletion:

  • Delayed replica: declare a pg_delay: 1h replica for a critical cluster. Before an erroneous operation is replayed, pause replication and extract the required data. A delayed replica eventually catches up and does not replace a backup.
  • Removal safeguards: when pg_safeguard or etcd_safeguard is enabled, the corresponding removal playbook refuses to run, reducing the risk of accidental cluster removal.

Having a backup is not the same as being able to restore. Recovery exercises should be routine; see Backup and Recovery for mechanisms and procedures.


Confidentiality

Protect data at rest at three layers:

Backup encryption. pgbackrest_method: minio denotes an S3-compatible repository. It can be provided by Silo deployed through the MINIO module, or independently managed MinIO, RustFS, and external S3 services. The preset uses AES-256-CBC by default, but the public pgBackRest passphrase must be changed in production. The ha/safe template derives an example passphrase from the cluster name:

pgbackrest_repo:
  minio:
    cipher_type: aes-256-cbc
    cipher_pass: 'pgBR.${pg_cluster}'   # Example only; replace before deployment

pgBR.${pg_cluster} is predictable, and configure -g does not replace it. Use a unique random passphrase in production and store it separately from the backup. Losing the passphrase makes the backup unrecoverable.

The local backup repository is not encrypted by default. Encryption reduces disclosure if backup files or media are copied separately, but offers limited protection when the key and backup remain on the same host.

Transport encryption. Backup uploads to Silo or external S3 services use HTTPS. PostgreSQL client and replication traffic can require SSL through HBA. Clients should also verify the server certificate; see Encrypted Communication.

Encryption at rest. Upstream PostgreSQL currently has no general built-in transparent data encryption (TDE). Pigsty provides two practical options: use the pg_tde extension with Percona Distribution for PostgreSQL for table-level transparent encryption (see the pgtde configuration template); or use security extensions such as pgsodium, pgcrypto, and anonymizer for column-level encryption and masking. The safe template installs this extension category. Full-disk encryption such as LUKS or dm-crypt protects against stolen media at the operating-system layer and complements database-level controls.


Audit and Traceability

After an incident, you must be able to answer who did what and when. Pigsty provides layered logging:

Default baseline: all DDL is logged (log_statement: ddl), and statements taking longer than 100 ms are logged (log_min_duration_statement: 100). PostgreSQL 18 and later also record connection authorization events.

CRIT template: connection and disconnection events are recorded with log_connections and log_disconnections. PostgreSQL 18 can distinguish connection receipt, authentication, and authorization stages.

pgaudit extension: for fine-grained statement auditing such as object reads and writes or role-based audit classes, install pgaudit and add it to pg_libs for preloading. The safe template installs the extension, but loading and audit policy must be declared explicitly.

When INFRA logging is enabled and Vector is configured, PostgreSQL logs are sent to VictoriaLogs for centralized storage. The default retention is 15 days and can be adjusted for compliance. Logs and metrics support search, alerts, and incident reconstruction, but incident classification, response, and evidence preservation still require an operational process.


Next

3.7.6 - Compliance

Compliance combines configuration, process, and evidence. This page covers launch hardening, MLPS and SOC 2 control mappings, supply-chain integrity, and vulnerability response.

Compliance is not a product you can buy. It is a state that must be demonstrated continuously through three elements:

  • Configuration: whether security controls are enabled. Pigsty directly provides this part.
  • Process: access approval, change management, recovery exercises, and related procedures. The organization must establish these.
  • Evidence: records showing that configuration and process remain effective. Pigsty’s inventory, runtime logs, and monitoring system can provide part of this evidence.

This page begins with a pre-launch hardening checklist and then maps Pigsty security capabilities to common compliance frameworks. The mappings support architecture and gap analysis; they are not an MLPS assessment conclusion, a SOC 2 audit opinion, or legal advice.


Default Credentials Checklist

Pigsty default credentials are public in the documentation and source code. They are intended only for demonstrations and local development. Change every applicable default before any production or network-exposed deployment goes live:

ScopeExample Defaultconfigure -g
Grafana administrator and viewerpigsty, DBUser.ViewerYes
HAProxy administration interfacepigstyYes
PostgreSQL administration, monitoring, and replication usersDBUser.DBA, DBUser.Monitor, DBUser.ReplicatorYes
Patroni REST APIPatroni.APIYes
etcd rootEtcd.RootYes
MINIO module object-storage rootS3User.MinIOYes
Object-storage backup and example application usersS3User.Backup, S3User.Meta, S3User.DataYes
Example database usersDBUser.Meta, DBUser.Supa, Vibe.CodingYes
pgBackRest encryption passphrasecipher_pass: pgBackRestNo
Silo users and pgBR.${pg_cluster} in ha/safeTemplate example valuesNo
User-defined credentialsCustom valuesNo

Use -g while generating configuration to randomize built-in parameters and example strings recognized by the configuration wizard:

./configure -g     # Generate the inventory and randomize recognized default credentials

The wizard prints generated passwords to the terminal, so protect terminal history and automation logs as sensitive data. After generation, inspect the configuration and replace pgBackRest cipher_pass, MINIO module example values in ha/safe that were not covered, and all custom credentials.


Launch Hardening Checklist

Before deployment:

After deployment:

  • Confirm that credentials covered by configure -g and uncovered backup, object-storage, and custom credentials have all been changed
  • Review the effective HBA rules in /pg/data/pg_hba.conf against the declaration and intended boundary
  • Query effective users, roles, default privileges, and database CONNECT grants, and compare them with the inventory
  • Run one full backup and a recovery exercise to validate the backup path
  • Confirm log collection, monitoring alerts, and notification channels

Periodically:

  • Audit privileges: compare pg_users declarations with effective grants, and remove expired or departed-user accounts
  • Rotate credentials and certificates
  • Exercise recovery and failover
  • Track security updates for Pigsty and upstream components

Compliance Evidence

Declarative configuration provides a stable starting point for audit evidence. Retain runtime state as well to show that the configuration was applied and remains effective.

EvidenceSource
Security baseline and change historyThe pigsty.yml inventory and Git history
Access-control matrixpg_default_roles, pg_users, and pg_hba_rules declarations
Effective authentication policyRendered pg_hba.conf on each instance, compared with declarations to detect drift
Effective users and privilegesPostgreSQL catalogs, database ACLs, \du+, and \ddp+
Operation and connection logsPostgreSQL DDL, slow-query, and connection logs retained in VictoriaLogs
Backup recordspgBackRest information and monitoring dashboards
Security incidents and alertsMonitoring alert history
Certificate inventoryfiles/pki/ and deployed component certificates

MLPS Level 3 Mapping

The following maps database-related Pigsty capabilities to controls in the “secure computing environment” section of GB/T 22239-2019 Level 3:

ControlPigsty CapabilityAdditional Requirement
Unique identityIndependent accounts and SCRAM-SHA-256 password storageReal-name account management process
Password complexity and rotationpasswordcheck, credcheck, and expire_inEnable extensions and establish a rotation process
Login failure handlingCan be implemented with credcheck and related extensionsEnable and configure as required
Access control and least privilegeFour-tier roles, default privileges, and database isolationPrivilege approval workflow
Security auditDDL, connection, and slow-query logs; pgaudit; centralized retentionCRIT or manual connection logging; required retention period
Communication confidentialityLocal CA and TLS; HBA-enforced ssl or certEnforce TLS, client verify-full, and certificate rotation
Data integrityPage checksums by default and strict synchronous replication with CRITStorage protection, defined failure model, and exercises
Data confidentialityAES-encrypted backup plus TDE and column-encryption optionsEnable as required
Backup and recoverypgBackRest, PITR, and a remote S3-compatible repositoryRecovery exercise process
Residual information protectionMedia destruction and erasure process

MLPS also covers physical security, communication networks, and management systems beyond the scope of a database distribution. Pigsty can support database-related technical controls in a secure computing environment; facilities, network devices, and governance must be addressed in the overall system.


SOC 2 Mapping

Database-related controls in the SOC 2 Trust Services Criteria (TSC) include:

CriterionPigsty CapabilityAdditional Requirement
CC6.1 Logical access securityHBA, RBAC, default privileges, and database isolationPrivilege design, approval, and periodic review
CC6.2 User registration and authorizationDeclarative users, roles, and expirationJoiner, mover, leaver, and identity-verification process
CC6.3 Access changes and revocationpg_users, role changes, REVOKE, and expirationTickets, approval evidence, and timely revocation
CC6.6 External boundary threatsFirewalls, listen addresses, HBA, and restricted management ingressNetwork architecture, boundary devices, and continuous validation
CC6.7 Information transmission and movementTLS, client verification, and backup encryptionPolicies for exports, media, and third-party transfer
CC7.2 System monitoringVictoria observability stack with extensive metrics and alertsAlert-response process
CC7.3 Incident traceabilityCentralized logs and audit extensionsLog-review process
A1.2 Availability and recoveryHigh Availability and PITRExercise records and RTO/RPO objectives

Supply Chain and Vulnerability Response

Compliance reviews increasingly cover the software supply chain. Pigsty provides the following distribution and response controls:

Package integrity: RPM and DEB packages in the Pigsty repositories (repo.pigsty.io and repo.pigsty.cc) are GPG-signed. The public-key fingerprint is 9592 A7BC 7A68 2E73 3337 6E09 E793 5D8D B9BD 8B20 (B9BD8B20) and can be verified before trust is established. Repository definitions written during deployment and the local repository on the INFRA node do not enforce signature verification for every package by default; review package-manager repository trust and signature settings in production.

Vulnerability response: report security issues privately through GitHub private vulnerability reporting or email, as documented in SECURITY.md. The project targets acknowledgment within three business days and an initial assessment within seven days.

Version support: security fixes ship with the latest stable release. Staying current is the standard way to receive them. Users who must remain on a version for longer can obtain extended support through subscription services.


Next

4 - About

Learn about Pigsty itself in every aspect - features, history, license, privacy policy, community, and news.

4.1 - Features

Pigsty’s value propositions and highlight features.

PostgreSQL In Great STYle”: Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours.

—— Battery-included, local-first PostgreSQL distribution, open-source RDS alternative


Value Propositions

Pigsty feature overview

Overview

Pigsty is a better local open-source RDS for PostgreSQL alternative:

  • Battery-Included RDS: From kernel to RDS distribution, providing production-grade PG database services for versions 14-18 on EL/Debian/Ubuntu.
  • Rich Extensions: Providing unparalleled 576 extensions with out-of-the-box distributed, time-series, geospatial, graph, vector, multi-modal database capabilities.
  • Flexible Modular Architecture: Compose Redis, Etcd, and Silo object-storage modules with PostgreSQL modes such as Mongo; monitor existing RDS, hosts, and databases independently.
  • Stunning Observability: Based on modern observability stack Prometheus/Grafana, providing stunning, unparalleled database observability capabilities.
  • Battle-Tested Reliability: Self-healing high-availability architecture: automatic failover on hardware failure, seamless traffic switching. With auto-configured PITR as safety net for accidental data deletion!
  • Easy to Use and Maintain: Declarative API, GitOps ready, foolproof operation, Database/Infra-as-Code and management SOPs encapsulating management complexity!
  • Solid Security Practices: HBA, ACL, TLS, backup, logging, and host-firewall foundations, with explicit default boundaries and production hardening requirements.
  • Broad Application Scenarios: Low-code data application development, or use preset Docker Compose templates to spin up massive software using PostgreSQL with one click!
  • Open-Source Free Software: Own better database services at less than 1/10 the cost of cloud databases! Truly “own” your data and achieve autonomy!

PostgreSQL integrates ecosystem tools and best practices:

  • Out-of-the-box PostgreSQL distribution, deeply integrating 576 packaged extensions for geospatial, time-series, distributed, graph, vector, search, and AI!
  • Runs on bare operating systems without container support, supporting mainstream operating systems: EL 8/9/10, Ubuntu 22.04/24.04/26.04, and Debian 12/13.
  • Based on patroni, haproxy, and etcd, creating a self-healing high-availability architecture: automatic failover on hardware failure, seamless traffic switching.
  • Combines pgBackRest with optional Silo object storage to provide out-of-the-box point-in-time recovery (PITR), protecting against software defects and accidental data deletion.
  • Based on Ansible providing declarative APIs to abstract complexity, greatly simplifying daily operations management in a Database-as-Code manner.
  • Pigsty has broad applications, can be used as complete application runtime, develop demo data/visualization applications, and massive software using PG can be spun up with Docker templates.
  • Provides Vagrant-based local development and testing sandbox environment, and Terraform-based cloud auto-deployment solutions, keeping development, testing, and production environments consistent.
  • Run PostgreSQL in Mongo-compatible mode with DocumentDB and the FerretDB Docker APP

Battery-Included RDS

Get production-grade PostgreSQL database services locally immediately!

PostgreSQL is a near-perfect database kernel, but it needs more tools and systems to become a good enough database service (RDS). Pigsty helps PostgreSQL make this leap. Pigsty solves various challenges you’ll encounter when using PostgreSQL: kernel extension installation, connection pooling, load balancing, service access, high availability / automatic failover, log collection, metrics monitoring, alerting, backup recovery, PITR, access control, parameter tuning, security encryption, certificate issuance, NTP, DNS, parameter tuning, configuration management, CMDB, management playbooks… You no longer need to worry about these details!

Pigsty supports PostgreSQL 14 ~ 18 mainline kernels and other compatible forks, running on EL / Debian / Ubuntu and compatible OS distributions, available on x86_64 and ARM64 chip architectures, without container support required. Besides database kernels and many out-of-the-box extension plugins, Pigsty also provides complete infrastructure and runtime required for database services, as well as local sandbox / production environment / cloud IaaS auto-deployment solutions.

Pigsty can bootstrap an entire environment from bare metal with one click, reaching the last mile of software delivery. Ordinary developers and operations engineers can quickly get started and manage databases part-time, building enterprise-grade RDS services without database experts!

pigsty-arch.jpg


Rich Extensions

Hyper-converged multi-modal, use PostgreSQL for everything, one PG to replace all databases!

PostgreSQL’s soul lies in its rich extension ecosystem, and Pigsty uniquely deeply integrates 576 extensions from the PostgreSQL ecosystem, providing you with an out-of-the-box hyper-converged multi-modal database!

Extensions can create synergistic effects, producing 1+1 far greater than 2 results. You can use PostGIS for geospatial data, TimescaleDB for time-series/event stream data analysis, and Citus to upgrade it in-place to a distributed geospatial-temporal database; You can use PGVector to store and search AI embeddings, ParadeDB for ElasticSearch-level full-text search, and simultaneously use precise SQL, full-text search, and fuzzy vector for hybrid search. You can also achieve dedicated OLAP database/data lakehouse analytical performance through pg_duckdb, pg_mooncake and other analytical extensions.

Using PostgreSQL as a single component to replace MySQL, Kafka, ElasticSearch, MongoDB, and big data analytics stacks has become a best practice — a single database choice can significantly reduce system complexity, greatly improve development efficiency and agility, achieving remarkable software/hardware and development/operations cost reduction and efficiency improvement.

pigsty-ecosystem.jpg


Flexible Modular Architecture

Flexible composition, free extension, multi-database support, monitor existing RDS/hosts/databases

Components in Pigsty are abstracted as independently deployable modules, which can be freely combined to address varying requirements. The INFRA module comes with a complete modern monitoring stack, while the NODE module tunes nodes to desired state and brings them under management. Installing the PGSQL module on multiple nodes automatically forms a high-availability database cluster based on primary-replica replication, while the ETCD module provides consensus and metadata storage for database high availability.

Beyond these four core modules, Pigsty also provides a series of optional feature modules: The MINIO module can deploy Silo to provide local object storage and serve as a centralized database backup repository. The REDIS module can provide auxiliary services for databases in standalone primary-replica, sentinel, or native cluster modes. The DOCKER module can be used to spin up stateless application software.

Additionally, Pigsty provides PG-compatible / derivative kernel support. You can use Babelfish for MS SQL Server compatibility, IvorySQL for Oracle compatibility, OpenHaloDB for MySQL compatibility, and OrioleDB for ultimate OLTP performance.

Furthermore, you can use PostgreSQL Mongo mode for MongoDB compatibility, Supabase for Firebase compatibility, and PolarDB to meet domestic compliance requirements. Message queues are covered by the KAFKA module, which deploys Kafka 4.x dynamic KRaft clusters. More professional/pilot modules will be continuously introduced to Pigsty, such as GPSQL, DUCKDB, TIGERBEETLE, KUBERNETES, CONSUL, GREENPLUM, CLOUDBERRY, MYSQL, …

pigsty-sandbox.jpg


Stunning Observability

Using modern open-source observability stack, providing unparalleled monitoring best practices!

Pigsty provides best practices for monitoring based on the open-source Grafana / Prometheus modern observability stack: Grafana for visualization, VictoriaMetrics for metrics collection, VictoriaLogs for log collection and querying, Alertmanager for alert notifications. Blackbox Exporter for checking service availability. The entire system is also designed for one-click deployment as the out-of-the-box INFRA module.

Pigsty automatically monitors every managed component: host nodes, HAProxy load balancers, PostgreSQL databases, PgBouncer connection pools, Etcd metadata stores, Redis-compatible caches, Silo object storage, and the monitoring infrastructure itself. Grafana dashboards and preset alert rules provide immediate operational visibility. The same stack can also monitor applications, existing database instances, and cloud RDS services.

Whether for failure analysis or slow query optimization, capacity assessment or resource planning, Pigsty provides comprehensive data support, truly achieving data-driven operations. In Pigsty, over three thousand types of monitoring metrics are used to describe all aspects of the entire system, and are further processed, aggregated, analyzed, refined, and presented in intuitive visualization modes. From global overview dashboards to CRUD details of individual objects (tables, indexes, functions) in a database instance, everything is visible at a glance. You can drill down, roll up, or jump horizontally freely, browsing current system status and historical trends, and predicting future evolution.

pigsty-dashboard.jpg

Additionally, Pigsty’s monitoring system module can be used independently — to monitor existing host nodes and database instances, or cloud RDS services. With just one connection string and one command, you can get the ultimate PostgreSQL observability experience.

Visit the Screenshot Gallery and Online Demo for more details.


Battle-Tested Reliability

Out-of-the-box high availability and point-in-time recovery capabilities ensure your database is rock-solid!

For table/database drops caused by software defects or human error, Pigsty provides out-of-the-box PITR point-in-time recovery capability, enabled by default without additional configuration. As long as storage space allows, base backups and WAL archiving based on pgBackRest let you quickly return to any point within the recovery window. You can use local directories/disks, Silo deployed by the MINIO module, or external S3-compatible object-storage services to retain longer recovery windows, according to your budget.

Pigsty provides a high-availability self-healing architecture based on Patroni, etcd, and HAProxy. When the node, network, quorum, and synchronous-replica assumptions hold, it can fail over the primary automatically. Actual RTO and RPO depend on replication mode, failure type, timeout settings, and client reconnection behavior.

Pigsty includes built-in HAProxy load balancers for automatic traffic switching, providing DNS/VIP/LVS and other access methods for clients. Failover and active switchover are almost imperceptible to the business side except for brief interruptions, and applications don’t need to modify connection strings or restart. The minimal maintenance window requirements bring great flexibility and convenience: you can perform rolling maintenance and upgrades on the entire cluster without application coordination. The feature that hardware failures can wait until the next day to handle lets developers, operations, and DBAs sleep well. Many large organizations and core institutions have been using Pigsty in production for extended periods. The largest deployment has 25K CPU cores and 200+ PostgreSQL ultra-large instances; in this deployment case, dozens of hardware failures and various incidents occurred over six to seven years, DBAs changed several times, but still maintained availability higher than 99.999%.

pigsty-ha.png


Easy to Use and Maintain

Infra as Code, Database as Code, declarative APIs encapsulate database management complexity.

Pigsty provides services through declarative interfaces, elevating system controllability to a new level: users tell Pigsty “what kind of database cluster I want” through configuration inventories, without worrying about how to do it. In effect, this is similar to CRDs and Operators in K8S, but Pigsty can be used for databases and infrastructure on any node: whether containers, virtual machines, or physical machines.

Whether creating/destroying clusters, adding/removing replicas, or creating new databases/users/services/extensions/whitelist rules, you only need to modify the configuration inventory and run the idempotent playbooks provided by Pigsty, and Pigsty adjusts the system to your desired state. Users don’t need to worry about configuration details — Pigsty automatically tunes based on machine hardware configuration. You only need to care about basics like cluster name, how many instances on which machines, what configuration template to use: transaction/analytics/critical/tiny — developers can also self-serve. But if you’re willing to dive into the rabbit hole, Pigsty also provides rich and fine-grained control parameters to meet the demanding customization needs of the most meticulous DBAs.

Beyond that, Pigsty’s own installation and deployment is also one-click foolproof, with all dependencies pre-packaged, requiring no internet access during installation. The machine resources needed for installation can also be automatically obtained through Vagrant or Terraform templates, allowing you to spin up a complete Pigsty deployment from scratch on a local laptop or cloud VM in about ten minutes. The local sandbox environment can run on a 1-core 2GB micro VM, providing the same functional simulation as production environments, usable for development, testing, demos, and learning.

pigsty-iac.jpg


Solid Security Practices

Pigsty provides the security foundations required for database deployment: layered HBA, built-in roles and default privileges, SCRAM-SHA-256, page checksums, a local CA, component certificates, backup, PITR, centralized logs, and firewall configuration.

The defaults target development, testing, and demonstrations on a trusted intranet. Production deployments must replace public credentials, review network boundaries, enforce TLS where required, configure server-certificate verification, and establish backup recovery, privilege review, and incident-response processes.

Security and Compliance documents each mechanism’s default state and boundary. Security Considerations provides production hardening guidance, and Compliance maps relevant controls to MLPS and SOC 2. Whether a deployment meets a specific requirement depends on scope, organizational process, continuous evidence, and the auditor’s conclusion.

pigsty-acl.jpg


Broad Application Scenarios

Use preset Docker templates to spin up massive software using PostgreSQL with one click!

In various data-intensive applications, the database is often the trickiest part. For example, the core difference between GitLab Enterprise and Community Edition is the underlying PostgreSQL database monitoring and high availability. If you already have a good enough local PG RDS, you can refuse to pay for software’s homemade database components.

Pigsty provides the Docker module and many out-of-the-box Compose templates. You can use Pigsty-managed high-availability PostgreSQL (as well as Redis and Silo) as backend storage, spinning up these software in stateless mode with one click: GitLab, Gitea, Wiki.js, NocoDB, Odoo, Jira, Confluence, Harbor, Mastodon, Discourse, KeyCloak, Mattermost, etc. If your application needs a reliable PostgreSQL database, Pigsty is perhaps the simplest way to get one.

Pigsty also provides application development toolsets closely related to PostgreSQL: PGAdmin4, PGWeb, ByteBase, PostgREST, Kong, as well as EdgeDB, FerretDB, Supabase — these “upper-layer databases” using PostgreSQL as storage. More wonderfully, you can build interactive data applications quickly in a low-code manner based on the Grafana and Postgres built into Pigsty, and even use Pigsty’s built-in ECharts panels to create more expressive interactive visualization works.

Pigsty provides a powerful runtime for your AI applications. Your agents can leverage PostgreSQL and the powerful capabilities of the observability world in this environment to quickly build data-driven intelligent agents.

pigsty-app.jpg


Open-Source Free Software

Pigsty is free software open-sourced under Apache-2.0, watered by the passion of PostgreSQL-loving community members

Pigsty is completely open-source and free software, allowing you to run enterprise-grade PostgreSQL database services at nearly pure hardware cost without database experts. For comparison, database vendors’ “enterprise database services” and public cloud vendors’ RDS charge premiums several to over ten times the underlying hardware resources as “service fees.”

Many users choose the cloud precisely because they can’t handle databases themselves; many users use RDS because there’s no other choice. We will break cloud vendors’ monopoly, providing users with a cloud-neutral, better open-source RDS alternative: Pigsty follows PostgreSQL upstream closely, with no vendor lock-in, no annoying “licensing fees,” no node count limits, and no data collection. All your core assets — data — can be “autonomously controlled,” in your own hands.

Pigsty itself aims to replace tedious manual database operations with database autopilot software, but even the best software can’t solve all problems. There will always be some rare, low-frequency edge cases requiring expert intervention. This is why we also provide professional subscription services to provide safety nets for enterprise users who need them. Subscription consulting fees of tens of thousands are less than one-thirtieth of a top DBA’s annual salary, completely eliminating your concerns and putting costs where they really matter. For community users, we also contribute with love, providing free support and daily Q&A.

pigsty-price.jpg

tooltip: { trigger: axis, formatter: $fn:ttfmt }
legend: { top: 4, itemGap: 16, data: [Oracle, Open-Source PG, Cloud RDS, Pigsty over IaaS, Pigsty over IDC ] }
grid: { left: 96, right: 36, bottom: 70, top: 50 }
xAxis:
  type: category
  name: CPU Cores
  nameLocation: middle
  nameGap: 36
  boundaryGap: false
  data: [2, 4, 8, 12, 16, 24, 32, 52, 64, 104, 128, 196, 256, 384, 512]
yAxis:
  type: log
  logBase: 10
  min: 10
  name: Monthly Cost (CNY)
  axisLabel: { formatter: $fn:yfmt }
  splitLine: { show: true, lineStyle: { type: dashed, opacity: 0.5 } }
series:
  - { name: Oracle, type: line, symbolSize: 7, lineStyle: { width: 3 }, itemStyle: { color: "#d62728" }, data: [45000, 65000, 105000, 145000, 185000, 265000, 345000, 545000, 665000, 1065000, 1305000, 1985000, 2585000, 3865000, 5145000] }
  - { name: Cloud RDS, type: line, symbolSize: 6, lineStyle: { width: 2 }, itemStyle: { color: "#ff7f0e" }, data: [800, 1600, 3200, 4800, 6400, 9600, 12800, 20800, 25600, 41600, 51200, 78400, 102400, 153600, 204800] }
  - { name: Pigsty over IaaS, type: line, symbolSize: 6, lineStyle: { width: 2 }, itemStyle: { color: "#2ca02c" }, data: [360, 720, 1440, 2160, 2880, 4320, 5760, 9360, 11520, 18720, 23040, 35280, 46080, 69120, 92160] }
  - { name: Pigsty over IDC, type: line, symbolSize: 6, lineStyle: { width: 2 }, itemStyle: { color: "#9467bd" }, data: [38, 76, 152, 228, 304, 456, 608, 988, 1216, 1976, 2432, 3724, 4864, 7296, 9728] }

4.2 - History

The origin and motivation of the Pigsty project, its development history, and future goals and vision.

Historical Origins

The Pigsty project began in 2018-2019, originating from Tantan. Tantan is an internet dating app — China’s Tinder, now acquired by Momo. Tantan was a Nordic-style startup with a Swedish engineering founding team.

Tantan had excellent technical taste, using PostgreSQL and Go as its core technology stack. The entire Tantan system architecture was modeled after Instagram, designed entirely around the PostgreSQL database. Up to several million daily active users, millions of TPS, and hundreds of TB of data, the data component used only PostgreSQL. Almost all business logic was implemented using PG stored procedures — even including 100ms recommendation algorithms! It was arguably the most complex PostgreSQL-at-scale use case in China at the time.

This atypical development model of deeply using PostgreSQL features placed extremely high demands on the capabilities of engineers and DBAs. And Pigsty is the open-source project we forged in this real-world large-scale, high-standard database cluster scenario — embodying our experience and best practices as top PostgreSQL experts.


Development Process

In the beginning, Pigsty did not have the vision, goals, and scope it has today. It started as a PostgreSQL monitoring system for our own use. We surveyed all available solutions — open-source, commercial, cloud-based, datadog, pgwatch, etc. — and none could meet our observability needs. So I decided to build one myself based on Grafana and Prometheus. This became Pigsty’s predecessor and prototype. Pigsty as a monitoring system was quite impressive, helping us solve countless management problems.

Subsequently, developers wanted such a monitoring system on their local development machines, so we used Ansible to write provisioning playbooks, transforming this system from a one-time construction task into reusable, replicable software. New versions allowed users to use Vagrant and Terraform, using Infrastructure as Code to quickly spin up local DevBox development machines or production environment servers, automatically completing PostgreSQL and monitoring system deployment.

Next, we redesigned the production environment PostgreSQL architecture, introducing Patroni and pgBackRest to solve database high availability and point-in-time recovery issues. We developed a zero-downtime migration solution based on logical replication, rolling upgrading two hundred production database clusters to the latest major version through blue-green deployment. And we incorporated these capabilities into Pigsty.

Pigsty is software we built for ourselves. The biggest benefit of “eating our own dog food” is that we are both developers and users — as client users, we know exactly what we need, do not cut corners, and never worry about automating ourselves out of jobs.

We solved problem after problem, depositing the solutions into Pigsty. Pigsty’s positioning also gradually evolved from a monitoring system into an out-of-the-box PostgreSQL database distribution. We then decided to open-source Pigsty and began a series of technical sharing and publicity, and external users from various industries began using Pigsty and providing feedback.


Full-Time Entrepreneurship

In 2022, the Pigsty project received seed funding from Miracle Plus, initiated by Dr. Qi Lu, allowing me to work on this full-time.

As an open-source project, Pigsty has developed quite well. In these years of full-time work, Pigsty’s GitHub stars grew from a few hundred to 5,213 as of 2026-07-11; it made the HN front page, and growth began snowballing. In November 2025, Pigsty won the Magneto Award at the PostgreSQL Ecosystem Conference. In 2026, Pigsty’s subproject PGEXT.CLOUD was selected for a PGCon.Dev 2026 talk. Pigsty became the first Chinese open-source project to appear on the stage of this core PostgreSQL ecosystem conference.

Previously, Pigsty could only run on CentOS 7, but now it covers all mainstream Linux distributions (EL, Debian, Ubuntu) across 16 operating system platforms. Supported PG major versions cover 14-18, and we maintain and integrate 576 extension plugins in the PG ecosystem. Among these, I personally maintain over half (360+) of the extension plugins, providing out-of-the-box RPM/DEB packages. Including Pigsty itself, “based on open source, giving back to open source,” this is our way of contributing to the PG ecosystem.

Pigsty’s positioning has also continuously evolved from a PostgreSQL database distribution to an open-source cloud database. It truly benchmarks against cloud vendors’ entire cloud database brands.


Rebel Against Public Clouds

Public cloud vendors like AWS, Azure, GCP, and Aliyun have provided many conveniences for startups, but they are closed-source and force users to rent infrastructure at exorbitant fees.

We believe that excellent database services, like excellent database kernels, should be accessible to every user, rather than requiring expensive rental from cyber lords.

Cloud computing’s agility and elasticity value proposition is strong, but it should be free, open-source, inclusive, and local-first — We believe the cloud computing universe needs a solution representing open-source values that returns infrastructure control to users without sacrificing the benefits of the cloud.

Therefore, we are also leading a movement and battle to exit the cloud, as rebels against public clouds, to reshape the industry’s values.


Our Vision

I hope that in the future world, everyone will have the de facto right to freely use excellent services, rather than being confined to a few cyber lord public cloud giants’ territories as cyber tenants or even cyber serfs.

This is exactly what Pigsty aims to do — a better, free and open-source RDS alternative. Allowing users to spin up database services better than cloud RDS anywhere (including cloud servers) with one click.

Pigsty is a complete complement to PostgreSQL, and a spicy mockery of cloud databases. It literally means “pigsty,” but it’s also an acronym for Postgres In Great STYle, meaning “PostgreSQL in its full glory.”

Pigsty itself is completely open-source and free software, so you can build a PostgreSQL service that scores 90 without database experts. We sustain operations by providing premium consulting services to take you from 90 to 100, with warranty, Q&A, and a safety net.

A well-built system may run for years without needing a “safety net,” but database problems, once they occur, are never small. Often, expert experience can turn decay into magic, and we provide such premium consulting — we believe this is a more just, reasonable, and sustainable model.


About the Team

I am Feng Ruohang, the author of Pigsty. Almost all of Pigsty’s code is developed by me alone.

Individual heroism still exists in the software field. Only unique individuals can create unique works — I hope Pigsty becomes such a work.

If you’re interested in me, here’s my personal homepage: https://vonng.com/

Modb Interview with Feng Ruohang” (Chinese)

Post-90s, Quit to Start Business, Says Will Crush Cloud Databases” (Chinese)




4.3 - News & Events

News and events related to Pigsty and PostgreSQL, including latest announcements!

Recent News


Conferences & Talks

DateTypeEventTopic
2025-11-29Award&TalkThe 8th Conf of PG Ecosystem (Hangzhou)PostgreSQL Magneto Award, A World-Grade Postgres Meta Distribution
2025-05-16LightningPGConf.Dev 2025, MontrealExtension Delivery: Make your PGEXT accessible to users
2025-05-12KeynotePGEXT.DAY, PGCon.Dev 2025The Missing Package Manager and Extension Repo for PostgreSQL Ecosystem
2025-04-19WorkshopPostgreSQL Database Technology SummitUsing Pigsty to Deploy PG Ecosystem Partners: Dify, Odoo, Supabase
2025-04-11Live HostOSCHINA Data Intelligence TalkIs the Viral MCP Hype or Revolutionary?
2025-01-15Live StreamOpen Source Veterans & Newcomers Episode 4PostgreSQL Extensions Devouring DB World? PG Package Manager pig & Self-hosted RDS
2025-01-09AwardOSCHINA 2024 Outstanding Contribution ExpertOutstanding Contribution Expert Award
2025-01-06PanelChina PostgreSQL Database Ecosystem ConferencePostgreSQL Extensions are Devouring the Database World
2024-11-23PodcastTech Hotpot PodcastFrom the Linux Foundation: Why the Recent Focus on ‘Chokepoints’?
2024-08-21InterviewBlue Tech WaveInterview with Feng Ruohang: Simplifying PG Management
2024-08-15Tech SummitGOTC Global Open Source Technology SummitPostgreSQL AI/ML/RAG Extension Ecosystem and Best Practices
2024-07-12Keynote13th PG China Technical ConferenceThe Future of Database World: Extensions, Service, and Postgres
2024-05-31UnconferencePGCon.Dev 2024 Global PG Developer ConferenceBuilt-in Prometheus Metrics Exporter
2024-05-28SeminarPGCon.Dev 2024 Extension SummitExtension in Core & Binary Packing
2024-05-10Live DebateThree-way Talk: Cloud Mudslide Series Episode 3Is Public Cloud a Scam?
2024-04-17Live DebateThree-way Talk: Cloud Mudslide Series Episode 2Are Cloud Databases a Tax on Intelligence?
2024-04-16PanelCloudflare Immerse ShenzhenCyber Bodhisattva Panel Discussion
2024-04-12Tech Summit2024 Data Technology CarnivalPigsty: Solving PostgreSQL Operations Challenges
2024-03-31Live DebateThree-way Talk: Cloud Mudslide Series Episode 1Luo Selling Cloud While We’re Moving Off Cloud?
2024-01-24Live HostOSCHINA Open Source Talk Episode 9Will DBAs Be Eliminated by Cloud?
2023-12-20Live DebateOpen Source Talk Episode 7To Cloud or Not: Cost Cutting or Value Creation?
2023-11-24Tech SummitVector Databases in the LLM EraPanel: New Future of Vector Databases in the AI Age
2023-09-08InterviewMotianlun Feature InterviewFeng Ruohang: A Tech Enthusiast Who Makes Great Open Source Founders
2023-08-16Tech SummitDTCC 2023DBA Night: PostgreSQL vs MySQL Open Source License Issues
2023-08-09Live DebateOpen Source Talk Episode 1MySQL vs PostgreSQL: Which is World’s No.1?
2023-07-01Tech SummitSACC 2023Workshop 8: FinOps Practice: Cloud Cost Management & Optimization
2023-05-12MeetupPostgreSQL China Wenzhou MeetupPG With DB4AI: Vector Database PGVECTOR & AI4DB: Self-Driving Database Pigsty
2023-04-08Tech SummitDatabase Carnival 2023A Better Open Source RDS Alternative: Pigsty
2023-04-01Tech SummitPostgreSQL China Xi’an MeetupPG High Availability & Disaster Recovery Best Practices
2023-03-23Live StreamBytebase x PigstyBest Practices for Managing PostgreSQL: Bytebase x Pigsty
2023-03-04Tech SummitPostgreSQL China ConferenceChallenging RDS, Pigsty v2.0 Release
2023-02-01Tech SummitDTCC 2022Open Source RDS Alternative: Battery-Included, Self-Driving Database Distro Pigsty
2022-07-21Live DebateCloud Swallows Open SourceCan Open Source Strike Back Against Cloud?
2022-07-04InterviewCreator’s StoryPost-90s Developer Quits to Start Up, Aiming to Challenge Cloud Databases
2022-06-28Live StreamBass’s RoundtableDBA’s Gospel: SQL Audit Best Practices
2022-06-12Demo DayMiraclePlus S22 Demo DayUser-Friendly Cost-Effective Database Distribution Pigsty
2022-06-05Live StreamPG Chinese Community SharingPigsty v1.5 Quick Start, New Features & Production Cluster Setup

4.4 - Roadmap

Future feature planning, new feature release schedule, and todo list.

Release Strategy

Pigsty uses semantic versioning: <major>.<minor>.<patch>. Alpha/Beta/RC versions will have suffixes like -a1, -b1, -c1 appended to the version number.

Major version updates signify incompatible foundational changes and major new features; minor version updates typically indicate regular feature updates and small API changes; patch version updates mean bug fixes and package version updates.

Pigsty plans to release one major version update per year. Minor version updates usually follow PostgreSQL’s minor version update rhythm, catching up within a month at the latest after a new PostgreSQL version is released. Pigsty typically plans 4-6 minor versions per year. For complete release history, please refer to Release Notes.

Deploy with Specific Version Numbers

Pigsty develops using the main trunk branch. Please always use Releases with version numbers.

Unless you know what you’re doing, do not use GitHub’s main branch. Always check out and use a specific version.


Features Under Consideration

  • Agent Native CLI - PIG
  • DBA Agent - basic integration
  • Grafana dashboard improvements
  • Boar management console

Here are our Active Issues and Roadmap.


Extensions and Packages

For the extension support roadmap, you can find it here: /ext/e/roadmap

Under Consideration

Not Considering for Now

4.5 - Join the Community

Pigsty is a Build in Public project. We are very active on GitHub, and Chinese users are mainly active in WeChat groups.

GitHub

Our GitHub repository is: https://github.com/pgsty/pigsty. Please give us a ⭐️ star!

We welcome anyone to submit new Issues or create Pull Requests, propose feature suggestions, and contribute to Pigsty.

Star History Chart

Please note that for issues related to Pigsty documentation, please submit Issues in the github.com/pgsty/pigsty.cc repository.

Press with K on macOS, or Ctrl with K, to search the documentation, extension catalog, and blog directly.


Maintainers

Pigsty is built by its maintainers and community.

2 contributors GitHub

WeChat Groups

Chinese users are mainly active in WeChat groups. Currently, there are seven active groups. Groups 1-4 are full; for other groups, you need to add the assistant’s WeChat to be invited.

To join the WeChat community, search for “Pigsty小助手” (WeChat ID: pigsty-cc), note or send “加群” (join group), and the assistant will invite you to the group.

Pigsty Chinese community

International Community

Telegram: https://t.me/joinchat/gV9zfZraNPM3YjFh

Discord: https://discord.gg/j5pG8qfKxU

You can also contact me via email: [email protected]


Community Help

When you encounter problems using Pigsty, you can seek help from the community. The more information you provide, the more likely you are to get help from the community.

Please refer to the Community Help Guide and provide as much information as possible so that community members can help you solve the problem. Here is a reference template for asking for help:

What happened? (Required)

Pigsty version and OS version (Required)

$ grep version pigsty.yml

$ cat /etc/os-release

$ uname -a

Some cloud providers have customized standard OS distributions. You can tell us which cloud provider’s OS image you are using. If you have customized and modified the environment after installing the OS, or if there are specific security rules and firewall configurations in your LAN, please also inform us when asking questions.

Pigsty configuration file

Please don’t forget to redact any sensitive information: passwords, internal keys, sensitive configurations, etc.

cat ~/pigsty/pigsty.yml

What did you expect to happen?

Please describe what should happen under normal circumstances, and how the actual situation differs from expectations.

How to reproduce this issue?

Please tell us in as much detail as possible how to reproduce this issue.

Monitoring screenshots

If you are using the monitoring system provided by Pigsty, you can provide relevant screenshots.

Error logs

Please provide logs related to the error as much as possible. Please do not paste content like “Failed to start xxx service” that has no informational value.

You can query logs from Grafana / VictoriaLogs, or get logs from the following locations:

  • Syslog: /var/log/messages (rhel) or /var/log/syslog (debian)
  • Postgres: /pg/log/postgres/*
  • Patroni: /pg/log/patroni/*
  • Pgbouncer: /pg/log/pgbouncer/*
  • Pgbackrest: /pg/log/pgbackrest/*
journalctl -u patroni
journalctl -u <service name>

Have you searched Issues/Website/FAQ?

In the FAQ, we provide answers to many common questions. Please check before asking.

You can also search for related issues from GitHub Issues and Discussions:

Is there any other information we need to know?

The more information and context you provide, the more likely we can help you solve the problem.

4.6 - Privacy Policy

What user data does Pigsty software and website collect, and how will we process your data and protect your privacy?

Pigsty Software

When you install Pigsty software, if you use offline package installation in a network-isolated environment, we will not receive any data about you.

If you choose online installation, when downloading related packages, our servers or cloud provider servers will automatically log the visiting machine’s IP address and/or hostname in the logs, along with the package names you downloaded.

We will not share this information with other organizations unless required by law. (Honestly, we’d have to be really bored to look at this stuff.)

Pigsty’s primary domain is: pigsty.io. For mainland China, please use the registered mirror site pigsty.cc.


Pigsty Website

When you visit our website, our servers will automatically log your IP address and/or hostname in Nginx logs.

We will only store information such as your email address, name, and location when you decide to send us such information by completing a survey or registering as a user on one of our websites.

We collect this information to help us improve website content, customize web page layouts, and contact people for technical and support purposes. We will not share your email address with other organizations unless required by law.

This website uses Google Analytics, a web analytics service provided by Google, Inc. (“Google”). Google Analytics uses “cookies,” which are text files placed on your computer to help the website analyze how users use the site.

The information generated by the cookie about your use of the website (including your IP address) will be transmitted to and stored by Google on servers in the United States. Google will use this information to evaluate your use of the website, compile reports on website activity for website operators, and provide other services related to website activity and internet usage. Google may also transfer this information to third parties if required by law or where such third parties process the information on Google’s behalf. Google will not associate your IP address with any other data held by Google. You may refuse the use of cookies by selecting the appropriate settings on your browser, however, please note that if you do this, you may not be able to use the full functionality of this website. By using this website, you consent to the processing of data about you by Google in the manner and for the purposes set out above.

If you have any questions or comments about this policy, or request deletion of personal data, you can contact us by sending an email to [email protected]




4.7 - License

Pigsty’s open-source licenses — Apache-2.0 and CC BY 4.0

License Summary

Pigsty core uses Apache-2.0; documentation uses CC BY 4.0.

Official License: https://github.com/pgsty/pigsty/blob/main/LICENSE


Pigsty Core

The Pigsty core is licensed under Apache License 2.0.

Apache-2.0 is a permissive open-source license. You may freely use, modify, and distribute the software for commercial purposes without opening your own source code or adopting the same license.

What This License GrantsWhat This License Does NOT GrantLicense Conditions
Commercial use Trademark use Include license and copyright notice
Modification Liability & warranty State changes
Distribution
Patent grant
Private use

Pigsty Documentation

Pigsty documentation sites (pigsty.cc, pigsty.io, pgsty.com) use Creative Commons Attribution 4.0 International (CC BY 4.0).

CC BY 4.0 permits free sharing and adaptation with appropriate credit, a license link, and indication of changes.

What This License GrantsWhat This License Does NOT GrantLicense Conditions
Commercial use Trademark use Attribution
Modification Liability & warranty Indicate changes
Distribution Patent grant Provide license link
Private use

SBOM Inventory

Open-source software used or related to the Pigsty project.

For 576 PostgreSQL extension plugin licenses, refer to PostgreSQL Extension License List.

ModuleSoftware NameLicensePurpose & DescriptionNecessity
PGSQLPostgreSQLPostgreSQL LicensePostgreSQL kernelRequired
PGSQLpatroniMIT LicensePostgreSQL high availabilityRequired
ETCDetcdApache License 2.0HA consensus and distributed config storageRequired
INFRAAnsibleGPLv3Executes playbooks and management commandsRequired
INFRANginxBSD-2Exposes Web UI and serves local repoRecommended
PGSQLpgbackrestMIT LicensePITR backup/recovery managementRecommended
PGSQLpgbouncerISC LicensePostgreSQL connection poolingRecommended
PGSQLvip-managerBSD 2-Clause LicenseAutomatic L2 VIP binding to PG primaryRecommended
PGSQLpg_exporterApache License 2.0PostgreSQL and PgBouncer monitoringRecommended
NODEnode_exporterApache License 2.0Host node monitoring metricsRecommended
NODEhaproxyHAPROXY’s License (GPLv2)Load balancing and service exposureRecommended
INFRAGrafanaAGPLv3Database visualization platformRecommended
INFRAVictoriaMetricsApache License 2.0TSDB, metric collection, alertingRecommended
INFRAVictoriaLogsApache License 2.0Centralized log collection, storage, queryRecommended
INFRADNSMASQGPLv2 / GPLv3DNS resolution and cluster name lookupRecommended
MINIOSiloAGPLv3The only object-storage service supported by the current MINIO moduleOptional
INFRAHistorical MinIO branchAGPLv3Historical/repository package; not a v4.5 MINIO backendOptional
INFRARustFSApache License 2.0Repository-retained package; not a v4.5 MINIO backendOptional
NODEkeepalivedMIT LicenseVIP binding on node clustersOptional
REDISRedisBSD 3-ClauseDefault cache engine, using the Redis 7.2 BSD branchOptional
REDISValkeyBSD 3-ClauseCache engine selected with redis_type: valkeyOptional
REDISRedis ExporterMIT LicenseRedis monitoringOptional
MONGOFerretDBApache License 2.0MongoDB compatibility over PostgreSQLOptional
DOCKERdocker-ceApache License 2.0Container managementOptional
CLOUDSealOSApache License 2.0Fast K8S cluster deployment and packagingOptional
DUCKDBDuckDBMITHigh-performance analyticsOptional
ExternalVagrantBusiness Source License 1.1Local test environment VMsOptional
ExternalTerraformBusiness Source License 1.1One-click cloud resource provisioningOptional
ExternalVirtualboxGPLv2Virtual machine management softwareOptional

Necessity Levels:

  • Required: Essential core capabilities, no option to disable
  • Recommended: Enabled by default, can be disabled via configuration
  • Optional: Not enabled by default, can be enabled via configuration

Apache-2.0 License Text

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright (C) 2018-2026  Ruohang Feng, @Vonng ([email protected])

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

4.8 - Sponsor Us

Pigsty sponsors and investors list - thank you for your support of this project!

Sponsor Us

Pigsty is a free and open-source software, passionately developed by PostgreSQL community members, aiming to integrate the power of the PostgreSQL ecosystem and promote the widespread adoption of PostgreSQL. If our work has helped you, please consider sponsoring or supporting our project:

  • Sponsor us directly with financial support - express your sincere support in the most direct and powerful way!
  • Consider purchasing our Technical Support Services. We can provide professional PostgreSQL high-availability cluster deployment and maintenance services, making your budget worthwhile!
  • Share your Pigsty use cases and experiences through articles, talks, and videos.
  • Allow us to mention your organization in “Users of Pigsty.”
  • Recommend/refer our project and services to friends, colleagues, and clients in need.
  • Follow our WeChat Official Account and share relevant technical articles to groups and your social media.

Angel Investors

Pigsty is a project invested by Miracle Plus (formerly YC China) S22. We thank Miracle Plus and Dr. Qi Lu for their support of this project!


Sponsors

Special thanks to Vercel for sponsoring pigsty and hosting the Pigsty website.

Vercel OSS Program

Special thanks to JetBrains for sponsoring Pigsty with JetBrains Open Source License

JetBrains logo.

4.9 - User Cases

Pigsty customer and application cases across various domains and industries

According to Google Analytics PV and download statistics, Pigsty currently has approximately 100,000 users, with half from mainland China and half from other regions globally. They span across multiple industries including internet, cloud computing, finance, autonomous driving, manufacturing, tech innovation, ISV, and defense. If you are using Pigsty and are willing to share your case and Logo with us, please contact us - we offer one free consultation session as a token of appreciation.

Internet

Tantan: 200+ physical machines for PostgreSQL and Redis services

Bilibili: Supporting PostgreSQL innovative business

Cloud Vendors

Bitdeer: Providing PG DBaaS

Oracle OCI: Using Pigsty to deliver PostgreSQL clusters

Finance

AirWallex: Monitoring 200+ GCP PostgreSQL databases

Media & Entertainment

Media Storm: Self-hosted PG RDS / Victoria Metrics

Autonomous Driving

Momenta: Autonomous driving, managing self-hosted PostgreSQL clusters

Manufacturing

Huafon Group: Using Pigsty to deliver PostgreSQL clusters as chemical industry time-series data warehouse

Tech Innovation

Beijing Lingwu Technology: Migrating PostgreSQL from cloud to self-hosted

Motphys: Self-hosted PostgreSQL supporting GitLab

Sailong Biotech: Self-hosted Supabase

Hangzhou Lingma Technology: Self-hosted PostgreSQL

ISV

Inner Mongolia Haode Tianmu Technology Co., Ltd.

Shanghai Yuanfang

DSG

4.10 - Subscription

Pigsty Professional/Enterprise subscription service - When you encounter difficulties related to PostgreSQL and Pigsty, our subscription service provides you with comprehensive support.

Pigsty aims to unite the power of the PostgreSQL ecosystem and help users make the most of the world’s most popular database, PostgreSQL, with self-driving database management software.

While Pigsty itself has already resolved many issues in PostgreSQL usage, achieving truly enterprise-grade service quality requires expert support and comprehensive coverage from the original provider. We deeply understand the importance of professional commercial support for enterprise customers. Therefore, Pigsty Enterprise Edition provides a series of value-added services on top of the open-source version, helping users better utilize PostgreSQL and Pigsty for customers to choose according to their needs.

If you have any of the following needs, please consider Pigsty subscription service:

  • Running databases in critical scenarios requiring strict SLA guarantees and comprehensive coverage.
  • Need comprehensive support for complex issues related to Pigsty and PostgreSQL.
  • Seeking guidance on PostgreSQL/Pigsty production environment best practices.
  • Want experts to help interpret monitoring dashboards, analyze and identify performance bottlenecks and fault root causes, and provide recommendations.
  • Need to plan database architectures that meet security/disaster recovery/compliance requirements based on existing resources and business needs.
  • Need to migrate from other databases to PostgreSQL, or migrate and transform legacy instances.
  • Building an observability system, data dashboards, and visualization applications based on the Victoria/Grafana technology stack.
  • Migrating off cloud and seeking open-source alternatives to RDS for PostgreSQL - cloud-neutral, vendor lock-in-free solutions.
  • Want professional support for Redis/ETCD/Silo, as well as extensions like TimescaleDB/Citus.
  • Want to perform secondary development and OEM branding with explicit commercial authorization.
  • Want to sell Pigsty as SaaS/PaaS/DBaaS, or provide technical services/consulting/cloud services based on this distribution.

Subscription Plans

In addition to the Open Source Edition, Pigsty offers two different subscription service tiers: Professional Edition and Enterprise Edition, which you can choose based on your actual situation and needs.

Note on /price: The /price page is a simplified global pricing landing page (USD pricing, includes the Standard tier and node-cap presets). This page is the detailed subscription reference (CNY pricing, delivery scope, and OS/PG compatibility matrix). For technical compatibility boundaries, this page and Supported Linux prevail.

Pigsty Open Source Edition (OSS)Free and Open Source

No scale limit, no warranty

License: Apache-2.0

PG Support: 18 (default), 14 - 18 available

Architecture Support: x86_64, Arm64

OS Support: Latest minor versions of three families

  • EL 9.8 / 10.2
  • Debian 12.15 / 13.6
  • Ubuntu 22.04.5 / 24.04.4 / 26.04.0

Features: Core Modules

SLA: No SLA commitment

Community support Q&A:

Support: No person-day support option

Repository: Global Cloudflare hosted repository

Self-sufficient open source veterans

Pigsty Professional Edition (PRO)Starting Price: ¥150,000 / year

Default choice for regular users

License: Commercial License

PG Support: 14 - 18

Architecture Support: x86_64, Arm64

OS Support: Mainstream OS major/minor versions

  • EL 8 / 9 / 10 compatible
  • Debian 12 / 13
  • Ubuntu 22 / 24 / 26

Features: All Modules (except domestic innovation kernels)

SLA: Response within business hours

Expert consulting services:

  • Software bug fixes
  • Complex issue analysis
  • Expert ticket support

Support: 1 person-day included per year

Delivery: Standard offline software package

Repository: China mainland mirror sites

Default choice for regular users

Pigsty Enterprise Edition (ENTERPRISE)Starting Price: ¥400,000 / year

Critical scenarios with strict SLA

License: Commercial License

PG Support: 14 - 18+ (legacy versions on request)

Architecture Support: x86_64, Arm64

OS Support: Customized on demand

  • EL, Debian, Ubuntu
  • Cloud Linux operating systems
  • Domestic OS and ARM

Features: All Modules

SLA: 7 x 24 (< 1h)

Enterprise-level expert consulting services:

  • Software bug fixes
  • Complex issue analysis
  • Expert Q&A support
  • Backup compliance advice
  • Upgrade path support
  • Performance bottleneck identification
  • Annual architecture review
  • Extension plugin integration
  • DBaaS & OEM use cases

Support: 2 person-days included per year

Repository: China mainland mirror sites

Delivery: Customized offline software package

Domestic Innovation: PolarDB-O support

Critical scenarios with strict SLA


Pigsty Open Source Edition (OSS)

Pigsty Open Source Edition uses the Apache-2.0 license, provides complete core functionality, requires no fees, but does not guarantee any warranty service. If you find defects in Pigsty, we welcome you to submit an Issue on Github.

Pigsty Open Source supports seven currently validated baselines: EL 9.8 / 10.2, Debian 12.15 / 13.6, and Ubuntu 22.04.5 / 24.04.4 / 26.04.0, across both x86_64 and aarch64. v4.5.0 publishes a dual-architecture offline bundle for each of those seven baselines, fourteen artifacts in total, all freely downloadable; see the offline installation guide.

Using the Pigsty open source version allows junior development/operations engineers to have 70%+ of the capabilities of professional DBAs. Even without database experts, they can easily set up a highly available, high-performance, easy-to-maintain, secure and reliable PostgreSQL database cluster.

CodeOS Distribution Versionx86_64aarch64PG18PG17PG16PG15PG14
EL10RHEL 10 / Rocky10 / Alma10el10.x86_64el10.aarch64
EL9RHEL 9 / Rocky9 / Alma9el9.x86_64el9.aarch64
U26Ubuntu 26.04 (resolute)u26.x86_64u26.aarch64
U24Ubuntu 24.04 (noble)u24.x86_64u24.aarch64
U22Ubuntu 22.04 (jammy)u22.x86_64u22.aarch64
D13Debian 13 (trixie)d13.x86_64d13.aarch64
D12Debian 12 (bookworm)d12.x86_64d12.aarch64

= Primary support, = Optional support


Pigsty Professional Edition (PRO)

Professional Edition Subscription: Starting Price ¥150,000 / year

Pigsty Professional Edition subscription provides complete functional modules and warranty for Pigsty itself. For defects in PostgreSQL itself and extension plugins, we will make our best efforts to provide feedback and fixes through the PostgreSQL global developer community.

Pigsty Professional Edition is built on the open source version, fully compatible with all open source features, and provides additional modules plus broader database/OS compatibility options: we provide build options for all minor versions of eight mainstream Linux releases (EL8/9/10, Debian 12/13, Ubuntu 22/24/26).

Pigsty Professional Edition includes support for PostgreSQL 14 - 18, and tracks upstream PostgreSQL minor updates continuously (for active majors, typically day-zero or near-day availability), ensuring smooth rolling upgrades to newer majors and minors.

Pigsty Professional Edition subscription allows you to use China mainland mirror site software repositories, accessible without VPN/proxy; we will also customize offline software installation packages for your exact operating system major/minor version, ensuring normal installation and delivery in air-gapped environments, achieving autonomous and controllable deployment.

Pigsty Professional Edition subscription provides standard expert consulting services, including complex issue analysis, DBA Q&A support, backup compliance advice, etc. We commit to responding to your issues within business hours (5x8), and provide 1 person-day support per year, with optional person-day add-on options.

Pigsty Professional Edition uses a commercial license, providing additional modules, technical support, and warranty services.

Pigsty Professional Edition starting price is ¥150,000 / year, equivalent to the annual fee for 9 vCPU AWS high-availability RDS PostgreSQL, or a junior operations engineer with a monthly salary of 10,000 yuan.

CodeOS Distribution Versionx86_64aarch64PG18PG17PG16PG15PG14
EL10RHEL 10 / Rocky10 / Alma10el10.x86_64el10.aarch64
EL9RHEL 9 / Rocky9 / Alma9el9.x86_64el9.aarch64
EL8RHEL 8 / Rocky8 / Alma8 / Anolis8el8.x86_64el8.aarch64
U26Ubuntu 26.04 (resolute)u26.x86_64u26.aarch64
U24Ubuntu 24.04 (noble)u24.x86_64u24.aarch64
U22Ubuntu 22.04 (jammy)u22.x86_64u22.aarch64
D13Debian 13 (trixie)d13.x86_64d13.aarch64
D12Debian 12 (bookworm)d12.x86_64d12.aarch64

Pigsty Enterprise Edition

Enterprise Edition Subscription: Starting Price ¥400,000 / year

Pigsty Enterprise Edition subscription includes all service content provided by the Pigsty Professional Edition subscription, plus the following value-added service items:

Pigsty Enterprise Edition subscription provides the broadest range of database/operating system version support, including extended support for EOL operating systems (EL7, D11), domestic operating systems, cloud vendor operating systems, and legacy PostgreSQL major versions (PG12+ on request), as well as full support for Arm64 architecture chips.

Pigsty Enterprise Edition subscription provides domestic innovation and localization solutions, allowing you to use PolarDB v2.0 (this kernel license needs to be purchased separately) kernel to replace the native PostgreSQL kernel and meet local compliance requirements.

Pigsty Enterprise Edition subscription provides higher-standard enterprise-level consulting services, committing to 7x24 with (< 1h) response time SLA, and can provide more types of consulting support: version upgrades, performance bottleneck identification, annual architecture review, extension plugin integration, etc.

Pigsty Enterprise Edition subscription includes 2 person-days of support per year, with optional person-day add-on options, for resolving more complex and time-consuming issues.

Pigsty Enterprise Edition allows you to use Pigsty for DBaaS purposes, building cloud database services for external sales.

Pigsty Enterprise Edition starting price is ¥400,000 / year, equivalent to the annual fee for 24 vCPU AWS high-availability RDS, or an operations expert with a monthly salary of 30,000 yuan.

CodeOS Distribution Versionx86_64aarch64PG18PG17PG16PG15PG14PG13PG12
EL10RHEL 10 / Rocky10 / Alma10el10.x86_64el10.aarch64
EL9RHEL 9 / Rocky9 / Alma9el9.x86_64el9.aarch64
EL8RHEL 8 / Rocky8 / Alma8 / Anolis8el8.x86_64el8.aarch64
U26Ubuntu 26.04 (resolute)u26.x86_64u26.aarch64
U24Ubuntu 24.04 (noble)u24.x86_64u24.aarch64
U22Ubuntu 22.04 (jammy)u22.x86_64u22.aarch64
D13Debian 13 (trixie)d13.x86_64d13.aarch64
D12Debian 12 (bookworm)d12.x86_64d12.aarch64
D11Debian 11 (bullseye)d11.x86_64d11.aarch64
EL7RHEL7 / CentOS7 / UOS …el7.x86_64-

Pigsty Subscription Notes

Feature Differences

Pigsty Professional/Enterprise Edition includes the following additional features compared to the open source version:

  • Command Line Management Tool: Unlock the full functionality of the Pigsty command line tool (pig)
  • System Customization Capability: Provide pre-built offline installation packages for exact mainstream Linux operating system distribution major/minor versions
  • Offline Installation Capability: Complete Pigsty installation in environments without Internet access (air-gapped environments)
  • Multi-version PG Kernel: Allow users to freely specify and install PostgreSQL major versions within the lifecycle (14 - 18)
  • Kernel Replacement Capability: Allow users to use other PostgreSQL-compatible kernels to replace the native PG kernel, and the ability to install these kernels offline
    • Babelfish: Provides Microsoft SQL Server wire protocol-level compatibility
    • IvorySQL: Based on PG, provides Oracle syntax/type/stored procedure compatibility
    • PolarDB PG: Provides support for open-source PolarDB for PostgreSQL kernel
    • PolarDB O: Domestic innovation database with Oracle-compatible kernel for local compliance requirements (Enterprise Edition subscription only)
  • Extension Support Capability: Provides out-of-the-box installation for 576 available PG extensions for PG 14-18 on mainstream operating systems.
  • Complete Functional Modules: Provides all functional modules:
    • Supabase: Reliably self-host production-grade open-source Firebase
    • Silo: Enterprise PB-level object storage planning and self-hosting
    • DuckDB: Provides comprehensive DuckDB support, and PostgreSQL + DuckDB OLAP extension plugin support
    • Kafka: Provides high-availability Kafka cluster deployment and monitoring
    • Kubernetes, VictoriaMetrics & VictoriaLogs
  • Domestic Operating System Support: Provides domestic innovation OS support options (Enterprise Edition subscription only)
  • Domestic ARM Architecture Support: Provides domestic ARM64 architecture support options (Enterprise Edition subscription only)
  • China Mainland Mirror Repository: Smooth installation without VPN, providing domestic YUM/APT repository mirrors and DockerHub access proxy.
  • Chinese Interface Support: Monitoring system Chinese interface support (Beta)

Payment Model

Pigsty subscription uses an annual payment model. After signing the contract, the one-year validity period is calculated from the contract date. If payment is made before the subscription contract expires, it is considered automatic renewal. Consecutive subscriptions have discounts. The first renewal (second year) enjoys a 95% discount, the second and subsequent renewals enjoy a 90% discount on subscription fees, and one-time subscriptions for three years or more enjoy an overall 85% discount.

After the annual subscription contract terminates, you can choose not to renew the subscription service. Pigsty will no longer provide software updates, technical support, and consulting services, but you can continue to use the already installed version of Pigsty Professional Edition software. If you subscribed to Pigsty professional services and choose not to renew, when re-subscribing you do not need to make up for the subscription fees during the interruption period, but all discounts and benefits will be reset.

Pigsty’s pricing strategy ensures value for money - you can immediately get top DBA’s database architecture construction solutions and management best practices, with their consulting support and comprehensive coverage; while the cost is highly competitive compared to hiring database experts full-time or using cloud databases. Here are market references for enterprise-level database professional service pricing:

The fair price for decent database professional services is 10,000 ~ 20,000 yuan / year, with the billing unit being vCPU, i.e., one CPU thread (1 Intel core = 2 vCPU threads). Pigsty provides top-tier PostgreSQL expert services in China and adopts a per-node billing model. On commonly seen high-core-count server nodes, it brings users an unparalleled cost reduction and efficiency improvement experience.


Pigsty Expert Services

In addition to Pigsty subscription, Pigsty also provides on-demand Pigsty x PostgreSQL expert services - industry-leading database experts available for consultation.

Expert Advisor: ¥300,000 / three years


Within three years, provides 10 complex case handling sessions related to PostgreSQL and Pigsty, and unlimited Q&A.

Expert Support: ¥30,000 / person·day


Industry-leading expert on-site support, available for architecture consultation, fault analysis, problem troubleshooting, database health checks, monitoring interpretation, migration assessment, teaching and training, cloud migration/de-cloud consultation, and other continuous time-consuming scenarios.

Expert Consultation: ¥3,000 / case


Consult on any questions you want to know about Pigsty, PostgreSQL, databases, cloud computing, AI… Database veterans, cloud computing maverick sharing industry-leading insights, cognition, and judgment.

Quick Consultation: ¥300 / question


Get a quick diagnostic opinion and response to questions related to PostgreSQL / Pigsty / databases, not exceeding 5 minutes.


Contact Information

Please send an email to [email protected]. Users in mainland China are welcome to add WeChat ID RuohangFeng.

4.11 - FAQ

Answers to frequently asked questions about the Pigsty project itself.

What is Pigsty, and what is it not?

Pigsty is a PostgreSQL database distribution, a local-first open-source RDS cloud database solution. Pigsty is not a Database Management System (DBMS), but rather a tool, distribution, solution, and best practice for managing DBMS.

Analogy: The database is the car, then the DBA is the driver, RDS is the taxi service, and Pigsty is the autonomous driving software.


What problem does Pigsty solve?

The ability to use databases well is extremely scarce: either hire database experts at high cost to self-build (hire drivers), or rent RDS from cloud vendors at sky-high prices (hail a taxi), but now you have a new option: Pigsty (autonomous driving). Pigsty helps users use databases well: allowing users to self-build higher-quality and more efficient local cloud database services at less than 1/10 the cost of RDS, without a DBA!


Who are Pigsty’s target users?

Pigsty has two typical target user groups. The foundation is medium to large companies building ultra-large-scale enterprise/production-grade PostgreSQL RDS / DBaaS services. Through extreme customizability, Pigsty can meet the most demanding database management needs and provide enterprise-level support and service guarantees.

At the same time, Pigsty also provides “out-of-the-box” PG RDS self-building solutions for individual developers, small and medium enterprises lacking DBA capabilities, and the open-source community.


Why can Pigsty help you use databases well?

Pigsty embodies the experience and best practices of top experts refined in the most complex and largest-scale client PostgreSQL scenarios, productized into replicable software: Solving extension installation, high availability, connection pooling, monitoring, backup and recovery, parameter optimization, IaC batch management, one-click installation, automated operations, and many other issues at once. Avoiding many pitfalls in advance and preventing repeated mistakes.


Why is Pigsty better than RDS?

Pigsty provides a feature set and infrastructure support far beyond RDS, including 576 extension plugins and 12+ kernel support. Pigsty provides a unique professional-grade monitoring system in the PG ecosystem, along with architectural best practices battle-tested in complex scenarios, simple and easy to use.

Moreover, forged in top-tier client scenarios like Tantan, Apple, and Alibaba, continuously nurtured with passion and love, its depth and maturity are incomparable to RDS’s one-size-fits-all approach.


Why is Pigsty cheaper than RDS?

Pigsty allows you to use 10 ¥/core·month pure hardware resources to run 400¥-1400¥/core·month RDS cloud databases, and save the DBA’s salary. Typically, the total cost of ownership (TCO) of a large-scale Pigsty deployment can be over 90% lower than RDS.

Pigsty can simultaneously reduce software licensing/services/labor costs. Self-building requires no additional staff, allowing you to spend costs where it matters most.


How does Pigsty help developers?

Pigsty integrates the most comprehensive extensions in the PG ecosystem (576), providing an All-in-PG solution: a single component replacing specialized components like Redis, Kafka, MySQL, ES, vector databases, OLAP / big data analytics.

Greatly improving R&D efficiency and agility while reducing complexity costs, and developers can achieve self-service management and autonomous DevOps with Pigsty’s support, without needing a DBA.


How does Pigsty help operations?

Pigsty’s self-healing high-availability architecture ensures hardware failures don’t need immediate handling, letting ops and DBAs sleep well; monitoring aids problem analysis and performance optimization; IaC enables automated management of ultra-large-scale clusters.

Operations can moonlight as DBAs with Pigsty’s support, while DBAs can skip the system building phase, saving significant work hours and focusing on high-value work, or relaxing, learning PG.


Who is the author of Pigsty?

Pigsty is primarily developed by Feng Ruohang alone, an open-source contributor, database expert, and evangelist who has focused on PostgreSQL for 10 years, formerly at Alibaba, Tantan, and Apple, a full-stack expert. Now the founder of a one-person company, providing professional consulting services.

He is also a tech KOL, the founder of the top WeChat database personal account “非法加冯” (Illegally Add Feng), with 60,000+ followers across all platforms.


What is Pigsty’s ecosystem position and influence?

Pigsty is the most influential Chinese open-source project in the global PostgreSQL ecosystem, with about 100,000 users, half from overseas. Pigsty is also one of the most active open-source projects in the PostgreSQL ecosystem, currently dominating in extension distribution and monitoring systems.

PGEXT.Cloud is a PostgreSQL extension repository maintained by Pigsty, with the world’s largest PostgreSQL extension distribution volume. It has become an upstream software supply chain for multiple international PostgreSQL vendors.

Pigsty is currently one of the major distributions in the PostgreSQL ecosystem and a challenger to cloud vendor RDS, now widely used in defense, government, healthcare, internet, finance, manufacturing, and other industries.


What scale of customers is Pigsty suitable for?

Pigsty originated from the need for ultra-large-scale PostgreSQL automated management but has been deeply optimized for ease of use. Individual developers and small-medium enterprises lacking professional DBA capabilities can also easily get started.

The largest deployment is 25K vCPU, 4.5 million QPS, 6+ years; the smallest deployment can run completely on a 1c1g VM for Demo / Devbox use.


What capabilities does Pigsty provide?

Pigsty focuses on integrating the PostgreSQL ecosystem and providing PostgreSQL best practices, but also supports a series of open-source software that works well with PostgreSQL. For example:

  • Etcd, Redis, Silo, DuckDB, Prometheus
  • FerretDB, Babelfish, IvorySQL, PolarDB, OrioleDB
  • OpenHalo, Supabase, Greenplum, Dify, Odoo, …

What scenarios is Pigsty suitable for?

  • Running large-scale PostgreSQL clusters for business
  • Self-building RDS, object storage, cache, data warehouse, Supabase, …
  • Self-building enterprise applications like Odoo, Dify, Wiki, GitLab
  • Running monitoring infrastructure, monitoring existing databases and hosts
  • Using multiple PG extensions in combination
  • Dashboard development and interactive data application demos, data visualization, web building

Is Pigsty open source and free?

Pigsty is 100% open-source software + free software. Under the premise of complying with the open-source license, you can use it freely and for various commercial purposes.

We value software freedom. Pigsty uses the Apache-2.0 license. Please see the license for details.


Does Pigsty provide commercial support?

Pigsty software itself is open-source and free, and provides commercial subscriptions for all budgets, providing quality assurance for Pigsty & PostgreSQL. Subscriptions provide broader OS/PG/chip architecture support ranges, as well as expert consulting and support. Pigsty commercial subscriptions deliver industry-leading management/technical experience/solutions, helping you save valuable time, shouldering risks for you, and providing a safety net for difficult problems.


Does Pigsty support domestic innovation (信创)?

Pigsty software itself is not a database and is not subject to domestic innovation catalog restrictions, and already has multiple military use cases. However, the Pigsty open-source edition does not provide any form of domestic innovation support. Commercial subscription provides domestic innovation solutions in cooperation with Alibaba Cloud, supporting the use of PolarDB-O with domestic innovation qualifications (requires separate purchase) as the RDS kernel, capable of running on domestic innovation OS/chip environments.


Can Pigsty run as a multi-tenant DBaaS?

Pigsty uses the Apache-2.0 license. You may use it for DBaaS purposes under the license terms. For explicit commercial authorization, consider the Pigsty Enterprise subscription.


Can Pigsty’s Logo be rebranded as your own product?

When redistributing Pigsty, you must retain copyright notices, patent notices, trademark notices, and attribution notices from the original work, and attach prominent change descriptions in modified files while preserving the content of the LICENSE file. Under these premises, you can replace PIGSTY’s Logo and trademark, but you must not promote it as “your own original work.” We provide commercial licensing support for OEM and rebranding in the enterprise edition.


Pigsty’s Business Entity

Pigsty is a project invested by Miracle Plus S22. The original entity Panji Cloud Data (Beijing) Technology Co., Ltd. has been liquidated and divested of the Pigsty business.

Pigsty is currently independently operated and maintained by author Feng Ruohang. The business entities are:

  • Hainan Zhuxia Cloud Data Co., Ltd. / 91460000MAE6L87B94
  • Haikou Longhua Piji Data Center / 92460000MAG0XJ569B
  • Haikou Longhua Yuehang Technology Center / 92460000MACCYGBQ1N

PIGSTY® and PGSTY® are registered trademarks of Haikou Longhua Yuehang Technology Center.

4.12 - Release Note

Pigsty historical version release notes

The latest Pigsty release is v4.5.0.

VersionRelease DateSummaryRelease Page
v4.5.02026-08-15Silo, Kafka, MySQL, Valkey, 575 extensions, and safer orchestrationv4.5.0
v4.4.02026-07-10PG 19 beta support, 531 extensions, kernel updates, pig CLI improvementsv4.4.0
v4.3.02026-05-01510 extensions, batch Infra / PGSQL / kernel package updates, Ubuntu 26 supportv4.3.0
v4.2.22026-03-23Insforge template, pdu, pgdog, tigerfs, ivorysql 5.3v4.2.2
v4.2.12026-03-06Maintenance release: 3 new extensions, drop PG13, bug fixesv4.2.1
v4.2.02026-02-28Routine minor release with six PG kernel updatesv4.2.0
v4.1.02026-02-12Major/minor upgrade support, Agent-Native CLI, stricter default firewall policyv4.1.0
v4.0.02026-01-28Observability revolution, security hardening, JUICE/VIBE modules, Apache-2.0v4.0.0
v3.7.02025-12-02PG18 default, 437 extensions, EL10 & Debian 13 support, PGEXT.CLOUDv3.7.0
v3.6.12025-08-15Routine PG minor updates, PGDG China mirror, EL10/D13 stubsv3.6.1
v3.6.02025-07-30pgactive, MinIO/ETCD improvements, simplified install, config cleanupv3.6.0
v3.5.02025-06-16PG18 beta, 421 extensions, monitoring upgrade, code refactorv3.5.0
v3.4.12025-04-05OpenHalo & OrioleDB, MySQL compatibility, pgAdmin improvementsv3.4.1
v3.4.02025-03-30Backup improvements, auto certs, AGE, IvorySQL all platformsv3.4.0
v3.3.02025-02-24404 extensions, extension directory, App playbook, Nginx customizationv3.3.0
v3.2.22025-01-23390 extensions, Omnigres, Mooncake, Citus 13 & PG17 supportv3.2.2
v3.2.12025-01-12350 extensions, Ivory4, Citus enhancements, Odoo templatev3.2.1
v3.2.02024-12-24Extension CLI, Grafana enhancements, ARM64 extension completionv3.2.0
v3.1.02024-11-24PG17 default, config simplification, Ubuntu24 & ARM supportv3.1.0
v3.0.42024-10-30PG17 extensions, OLAP suite, pg_duckdbv3.0.4
v3.0.32024-09-27PostgreSQL 17, Etcd improvements, IvorySQL 3.4, PostGIS 3.5v3.0.3
v3.0.22024-09-07Mini install mode, PolarDB 15 support, monitoring view updatesv3.0.2
v3.0.12024-08-31Routine bug fixes, Patroni 4 support, Oracle compatibility improvementsv3.0.1
v3.0.02024-08-25333 extensions, pluggable kernels, MSSQL/Oracle/PolarDB compatibilityv3.0.0
v2.7.02024-05-20Extension explosion, 20+ new powerful extensions, Docker appsv2.7.0
v2.6.02024-02-28PG16 as default, ParadeDB & DuckDB extensions introducedv2.6.0
v2.5.12023-12-01Routine minor update, PG16 key extension supportv2.5.1
v2.5.02023-09-24Ubuntu/Debian support: bullseye, bookworm, jammy, focalv2.5.0
v2.4.12023-09-24Supabase/PostgresML support with graphql, jwt, pg_net, vaultv2.4.1
v2.4.02023-09-14PG16, RDS monitoring, new extensions: FTS/graph/HTTP/embeddingv2.4.0
v2.3.12023-09-01PGVector with HNSW, PG16 RC1, doc refresh, Chinese docs, bug fixesv2.3.1
v2.3.02023-08-20Node VIP, FerretDB, NocoDB, MySQL stub, CVE fixesv2.3.0
v2.2.02023-08-04Dashboard & provisioning overhaul, UOS compatibilityv2.2.0
v2.1.02023-06-10PostgreSQL 12-16beta supportv2.1.0
v2.0.22023-03-31Added pgvector support, fixed MinIO CVEv2.0.2
v2.0.12023-03-21v2 bug fixes, security enhancements, Grafana upgradev2.0.1
v2.0.02023-02-28Major architecture upgrade, compatibility/security/maintainabilityv2.0.0
v1.5.12022-06-18Grafana security hotfixv1.5.1
v1.5.02022-05-31Docker application supportv1.5.0
v1.4.12022-04-20Bug fixes & full English documentation translationv1.4.1
v1.4.02022-03-31MatrixDB support, separated INFRA/NODES/PGSQL/REDIS modulesv1.4.0
v1.3.02021-11-30PGCAT overhaul & PGSQL enhancement & Redis beta supportv1.3.0
v1.2.02021-11-03Default PGSQL version upgraded to 14v1.2.0
v1.1.02021-10-12Homepage, JupyterLab, PGWEB, Pev2 & pgbadgerv1.1.0
v1.0.02021-07-26v1 GA, Monitoring System Overhaulv1.0.0
v0.9.02021-04-04Pigsty GUI, CLI, Logging Integrationv0.9.0
v0.8.02021-03-28Service Provisionv0.8.0
v0.7.02021-03-01Monitor only deploymentv0.7.0
v0.6.02021-02-19Architecture Enhancementv0.6.0
v0.5.02021-01-07Database Customize Templatev0.5.0
v0.4.02020-12-14PostgreSQL 13 Support, Official Documentationv0.4.0
v0.3.02020-10-22Provisioning Solution GAv0.3.0
v0.2.02020-07-10PGSQL Monitoring v6 GAv0.2.0
v0.1.02020-06-20Validation on Testing Environmentv0.1.0
v0.0.52020-08-19Offline Installation Modev0.0.5
v0.0.42020-07-27Refactor playbooks into Ansible rolesv0.0.4
v0.0.32020-06-22Interface enhancementv0.0.3
v0.0.22020-04-30First Commitv0.0.2
v0.0.12019-05-15POCv0.0.1

v4.5.0

Pigsty v4.5.0 is a feature release focused on new pilot modules, replaceable data services, cluster-identity-aware orchestration, observability, and the software supply chain. It introduces Kafka KRaft and MySQL 8.4 modules, adds Valkey to REDIS, converges the MINIO module on Silo, and expands the packaged extension catalog from 531 to 575 extensions. Released on 2026-08-15. See the GitHub release and the complete source comparison at v4.4.0...v4.5.0.

Highlights

  • 575 extensions: Compared with v4.4.0’s 531 entries, the current catalog adds 46 and removes 2, for a net gain of 44. It now contains 575 extensions across 406 non-contrib package families, with RPM/DEB coverage tracked per platform.
  • Kafka KRaft module: Adds native Pigsty orchestration for Kafka, with multi-cluster support, dynamic member enrollment and retirement, SCRAM/TLS, secure credential rotation, monitoring metrics, and Grafana dashboards.
  • MySQL 8.4 module: Adds standalone and three-node InnoDB Cluster deployments, MySQL Router, XtraBackup, user and database provisioning, monitoring and alerting, and idempotent reconciliation.
  • Valkey and Silo: REDIS adds redis_type: valkey; the final MINIO source accepts only minio_type: silo. The RustFS integration developed during this cycle was fully withdrawn before the candidate baseline.
  • 51 standalone configuration templates: Adds demo/kafka, demo/mysql, and the eight-node ha/octo simulation template to the 48 standalone templates in v4.4.0. The compatibility symlink conf/app/supa.yml../supabase.yml remains available.
  • Safer cluster-identity orchestration: PGSQL, REDIS, MINIO, KAFKA, and MYSQL initialization playbooks, plus every corresponding removal playbook except mysql-rm.yml, skip unrelated hosts by explicit cluster identity. mysql-rm.yml instead fails closed for any wrongly selected host. etcd delegation and DBSU key exchange now use actual cluster members as well.
  • Observability and supply chain: Re-exports Grafana dashboards to Dashboard API v2, moves MinIO/Silo collection to Metrics V3, and generates local repositories atomically with SOW instead of synthetic ModuleMD metadata.
  • Kernel and toolchain updates: Completes pgBackRest support for PostgreSQL 19 beta2, enables cluster mode for Percona PostgreSQL TDE, fixes IvorySQL initialization and WAL compression, and refreshes extension package maps, exporters, and build tooling.

New Modules and Data Services

  • The Kafka module uses node state as the source of truth for dynamic KRaft orchestration. It manages one or more clusters in one inventory and also supports an unbounded kafka.yml run; partial --limit selections are rejected. The destructive kafka-rm.yml instead requires a non-empty -l/--limit and validates a safe absolute data path plus surviving broker/controller anchors before any partial retirement can stop services. Nodes retain authoritative manifests and secrets, with dynamic controller joins, broker admission, member retirement, three-step dead-node replacement, SCRAM-SHA-512/TLS, credential and certificate rotation, and self-tested partition health gates.
  • The MySQL pilot module targets a fixed MySQL 8.4 LTS platform and accepts either a standalone node or a three-node InnoDB Cluster. It includes MySQL Shell and Router, scheduled full XtraBackup backups, TLS, account and database provisioning, primary-key policy checks, conservative member removal, and idempotent reconciliation.
  • The REDIS module retains redis as its default engine and can deploy Valkey with redis_type: valkey. Service units now use Type=notify with a 1,800-second startup timeout, plus stronger topology validation, password handling, tag-scoped removal semantics, and rebuild protection.
  • The MINIO module now deploys Silo and only Silo. minio_type remains an extension point, but silo is the sole accepted value in this release. Startup checks the systemd Invocation ID and ActiveState=active for the current restart, waits about 600 seconds by default, and then runs Silo’s cluster health check. The Infra package line adds silo and mcli while preserving the S3/Admin APIs, /minio/* routes, MINIO_* environment variables, and disk format.
  • Object-storage topology is grouped by minio_cluster; its inventory group name may differ, and one inventory may declare multiple object-storage clusters. Use distinct minio_alias, minio_domain, and minio_endpoint values for each to avoid overwriting shared client aliases on INFRA nodes. demo/minio now selects Silo explicitly and trims its local repository to the infra,node modules.
  • The standalone FERRET module is replaced by PostgreSQL Mongo mode and the FerretDB Docker APP. PostgreSQL provides the DocumentDB data layer, while Docker Compose provides the FerretDB protocol layer.

Orchestration, Security, and Tooling

  • deploy.yml, slim.yml, and the PGSQL, REDIS, MINIO, KAFKA, and MYSQL initialization playbooks now skip unrelated hosts according to the corresponding *_cluster identity. The PGSQL, REDIS, MINIO, and KAFKA removal playbooks do the same. MySQL removal is intentionally different: mysql-rm.yml does not skip hosts without identity and instead fails closed in mysql_rm_check. Every host that enters a role still receives an internal identity check.
  • PGSQL configuration, PITR, and removal workflows delegate only when the canonical etcd group exists and has at least one member; they no longer silently fall back to localhost when no etcd target exists. DBSU SSH keys are exchanged through the actual pg_cluster_members, correctly covering cross-inventory-group topologies such as Citus.
  • PGSQL PITR and removal now delete only the etcd subtree bounded by /<cluster>/, avoiding adjacent clusters whose names share a prefix. The initial pgBackRest marker /etc/pgbackrest/initial.done is written only after the backup command succeeds.
  • HAProxy uses the fixed /etc/haproxy/haproxy.cfg and /etc/haproxy/conf.d layout, upstream master-worker mode, a master socket, and Type=notify. dnsmasq now binds dynamically, answers private reverse lookups locally, and handles node addresses added after INFRA initialization.
  • Rendered systemd units managed by Pigsty are consistently placed under /etc/systemd/system; permissions on sensitive configuration and privileged files are tightened further. Removal workflows stop services before entering the data-cleanup phase.
  • The REPO and CACHE roles now use sow create --pigsty to atomically generate RPM/APT metadata and the SHA-256 repo_complete marker, and no longer generate synthetic ModuleMD metadata. pg_id also compares cluster size as an explicit integer for older Ansible releases.
  • RPM exporter package names move from underscores to hyphens, for example node_exporternode-exporter. Debian repository naming and PGDG YUM extension package mappings are corrected as well.
  • Tuned profiles now use the OS-specific directory: /etc/tuned/profiles on EL 10, Debian 13, and Ubuntu 26, and /etc/tuned on EL 8/9, Debian 12, and Ubuntu 22/24. Debian/Ubuntu package installation also suppresses premature starts of Silo, Redis/Valkey, and legacy log services.
  • China-region repository routing receives a systematic refresh. OS, Docker, Grafana, Percona, supported MongoDB APT, and uv/PyPI paths prefer Tencent Cloud; EL and Docker entries retain Huawei Cloud and Aliyun fallbacks where appropriate. MySQL and Kubernetes use USTC mirrors, and ClickHouse uses Huawei Cloud. MongoDB RPM no longer advertises an unavailable China-region alternative. The final per-platform choices remain defined in roles/node_id/vars/<os>.<arch>.yml.
  • The Docker image moves to Debian 13.6 and Pigsty v4.5.0. Vagrant enforces a 32 GiB root disk, accepts pinned box versions, and adds the eight-node ha/octo lab. docker/Makefile fixes its data directory at ./data, and make purge deletes that directory directly.
  • GitHub Actions for checkout, CodeQL, Docker build/login, and Cosign are upgraded in one batch. Release, bootstrap, install, and validation scripts also tighten file and argument handling. Release archives now derive top-level pigsty.yml from conf/meta.yml, include the Kafka/MySQL playbooks, and drop the legacy Mongo playbook.
  • The release-signing workflow must be dispatched from main and signs only the pigsty-<tag>.tgz source archive; multi-gigabyte offline bundles are outside that workflow. The package-build bootstrap matrix now matches conf/build/oss.yml: EL 9/10, Debian 12/13, and Ubuntu 22/24/26.

Observability

  • Re-exports the dashboard set through the Pig/Grafana tooling to Dashboard API v2. Adds four Kafka and five MySQL dashboards, and refreshes links, variables, and layouts across Node, PostgreSQL, Redis, and Infra dashboards.
  • Migrates the MinIO/Silo Overview and Instance dashboards to Metrics V3. Victoria scrapes the /minio/metrics/v3 root endpoint and drops high-cardinality samples carrying a non-empty bucket label.
  • Updates the pg_exporter configuration to 1.4.0 and fixes duplicate time series from the 1.4.1 pg_subrel query. For PG19 it adds pg_sub_19, pg_recovery_state, pg_wal_19, pg_lock_stat, and pg_vacuum_score; PG10+ gains the pg_xact_age transaction-age histogram, and replication-slot idle_timeout plus WAL Receiver connecting state encoding are covered. Kafka JMX/protocol exporters and the MySQL exporter also join the standard target and alert pipelines.

PostgreSQL Kernels and Extension Packages

  • PostgreSQL 19 beta3 templates now include pgBackRest packages and backup support.

  • All four standard Patroni templates add the PostgreSQL 18.6 logical-decoding allowlist output_plugin_libraries: 'pgoutput, test_decoding, wal2json'; Patroni filters it on older PostgreSQL versions that do not support the setting.

  • Percona PostgreSQL 18 TDE now uses cluster mode and retains Pigsty-prefixed packages to avoid conflicts with native PostgreSQL packages.

  • IvorySQL now initializes its default database correctly and enables compatible WAL compression in workload templates.

  • The PostgreSQL fact loader, per-platform package_map, and default extension groups are refreshed to fill package gaps and correct PGDG/YUM naming. Comparing names between the v4.4.0 PIG v1.5.1 catalog and the current catalog yields 46 additions and 2 removals:

    • 32 new primary extensions: argm, cat_tools, cron_utils, fbsql, oidc_validator, online_advisor, pg_cjk_parser, pg_column_tetris, pg_describe, pg_disorder, pg_fts, pg_jieba, pg_kpart, pg_lake, pg_local_cache, pg_mentat, pg_oidc_validator, pg_policy, pg_roast, pg_tiktoken_c, pg_turbovec, pg_vault_tde, pgcontext, pgfr_record, pgmemento, pgmonitor, pgsqlmock, pgwasm, plruby, plx, postbis, and qdgc.
    • 13 child extensions from those package families: hstore_plruby, jsonb_plruby, ltree_plruby, pg_extension_base, pg_extension_updater, pg_lake_copy, pg_lake_engine, pg_lake_iceberg, pg_lake_table, pg_map, pgcontext_pgvector, pgfr_analyze, and qdgc_postgis.
    • One new PGDG extension, pg_statviz. Its package is hidden from the default install group, but the extension remains in the online catalog.
    • Two catalog removals: pg_analytics and spat. The total therefore rises from 531 to 575, a net gain of 44.
  • Cumulative notable upgrades include citus 14.2.0, pg_search 0.25.2, timescaledb 2.29.1, vector 0.8.6, documentdb 0.114, pg_partman 5.5.0, pgmnemo 0.16.1, plpgsql_check 2.10.4, provsql 1.12.0, and pgbson 2.1.0, plus a broad pgrx 0.19.1 rebuild.

  • Full build records and platform differences appear in the merged table below and the original RPM changelog and DEB changelog. New catalog entries include pg_local_cache and pg_policy. Changelog dates identify package batches and should not be equated one-for-one with the current CSV mtime.

  • pg_statviz is excluded only from the default install group in db/reload.sql; its detail page, platform coverage, and package-name differences remain in the online catalog.

Extension Package Update Log

The table below merges the RPM changelog and DEB changelog after v4.4.0, with 231 rows aligned by batch and extension name. Records that are identical in RPM and DEB are merged; version or note differences are shown separately. An unchanged version still indicates a rebuild, package-name change, license-metadata change, or platform-coverage change.

The first extension batch after July 10 is July 24. That original batch covers July 7–24 without per-item dates, so it is included in full to avoid omitting post-release pgrx rebuilds and package-matrix fixes. “RPM only” or “DEB only” means only that the other changelog has no same-batch row for that extension.

BatchExtensionVersion ChangeNotes
2026-08-14asn1oidRPM only: 1.61.6License metadata: GPL-3.0-or-later; r2; PG14-18
2026-08-14emailaddr00License metadata: LicenseRef-Upstream-No-License; r3; PG14-18
2026-08-14explain_ui0.0.20.0.2License metadata: LicenseRef-Upstream-No-License; r4; PG14-18
2026-08-14numeralRPM only: 1.31.3License metadata: GPL-2.0-or-later; r6; PG14-18
2026-08-14oidc_validator0.1.00.1.0Rust module; LicenseRef-Upstream-No-License; r2; PG18
2026-08-14pg_failover_slots1.2.11.2.1License metadata: PostgreSQL; r2; preload; PG14-18
2026-08-14pg_geohash1.01.0License metadata: MIT; r4; fix SQL filename and target-PG ABI; PG14-18
2026-08-14pg_oidc_validator0.21.1.0RPM: PG18 OAuth validator module; add discovery_url_override; EL10 only
DEB: PG18 OAuth validator module; add discovery_url_override and GSSAPI build dependency
2026-08-14pg_relation_sql-0.2.2RPM: Standalone SQL; no CREATE EXTENSION; noarch; PG14-18
DEB: Standalone SQL; no CREATE EXTENSION; Architecture: all; PG14-18
2026-08-14pg_summarize0.0.10.0.1License metadata: LicenseRef-Upstream-No-License; r6; PG14-18
2026-08-14pg_when0.1.90.1.10GitHub/PGXN release; upstream pgrx 0.18.1, packaged with 0.19.1; PG14-18
2026-08-14pre_prepareRPM only: 0.90.9License metadata: PostgreSQL; r2; PG14-18
2026-08-14smlar1.01.0License metadata: LicenseRef-Upstream-No-License; r2; PG14-18
2026-08-14unit7.107.10License metadata: GPL-3.0-or-later; r7; PG14-18
2026-08-12biscuit2.4.33.0.0PG16-18; 2.x indexes require REINDEX
2026-08-12cat_tools-0.3.0SQL-only; PG14-18
2026-08-12citus14.1.014.2.0Includes citus_columnar; PG16-18
2026-08-12pg_clickhouse0.3.20.10.0PG14-18
2026-08-12pg_describe-1.0.0PG17-18
2026-08-12pg_disorder-0.1.0PG14-18
2026-08-12pg_local_cache-1.3.0PG14-18; preload; single-primary
2026-08-12pg_mentat-1.5.7PG14-18
2026-08-12pg_policy-0.1.0SQL-only; PG14-18
2026-08-12pg_rational0.0.20.0.3RPM: PIGSTY; PG14-18
DEB: PGDG; PG14-18
2026-08-12pg_readme0.7.00.7.1RPM: Catalog 0.7.1; RPM remains PGDG 0.7.0
DEB: Includes pg_readme_test_extension; PG14-18
2026-08-12pg_search0.25.00.25.2PG15-18; pgrx 0.19.1; preload
2026-08-12pg_squeeze1.9.21.9.4PGDG; PG14-18
2026-08-12pg_statvizRPM: -0.9
DEB: -1.1
RPM: PGDG; PG14-16 and EL10 PG18; no PG17; not in default groups
DEB: PGDG; PG14-18 except Ubuntu 22.04; not in default groups
2026-08-12pg_turbovec-1.29.0PG14-18; pgrx 0.19.1
2026-08-12pg_uuid_v81.0.01.1.0PG14-18; includes 1.0-to-1.1 upgrade script
2026-08-12pg_vault_tde-1.7.0RPM: PG17-18; EL9/10; preload
DEB: PG17-18; preload
2026-08-12pgbson2.0.42.1.0RPM: RPM package postgresbson; PG14-18
DEB: Source package postgresbson; PG14-18
2026-08-12pgmnemo0.15.00.16.1PG17-18
2026-08-12plpgsql_check2.10.32.10.4PG14-18
2026-08-12plruby-2.5.0Includes jsonb_plruby, hstore_plruby, ltree_plruby; PG14-18
2026-08-12polardb-1717.10.1.0-1PIGSTY17.10.1.0-2PGSTYRebuild; PG17
2026-08-12polarstore1.2.42-1PIGSTY1.2.42-2PGSTYRebuild
2026-08-12provsql1.11.01.12.0PG14-18
2026-08-12q3cRPM: 2.0.22.0.5
DEB: 2.0.42.0.5
RPM: PGDG; PIGSTY remains 2.0.2; PG14-18
DEB: PGDG; PG14-18
2026-08-12timescaledb2.29.02.29.1PG16-18
2026-08-12vector0.8.60.8.6PGDG repository refresh; PG14-18
2026-08-12zlog1.2.18-1PIGSTY1.2.18-2PGSTYRebuild
2026-07-30emajRPM: -5.0.0
DEB: 4.7.15.0.0
RPM: Renamed to e-maj; Provides/Obsoletes emaj; r2
DEB: PG14-18
2026-07-30graph0.1.81.0.0pggraph; PG14-18; pgrx 0.19.1
2026-07-30nominatim_fdw2.0.02.1.0PG14-18
2026-07-30numeralRPM only: 1.31.3Renamed to postgresql-numeral; Provides/Obsoletes numeral; r3
2026-07-30pg_ai_queryRPM only: 0.1.10.1.1EL9/10 only (GCC 13/OpenSSL 3); r2 not indexed
2026-07-30pg_column_tetris-0.1.0SQL-only; PG14-18
2026-07-30pg_net0.20.50.20.5RPM: EL8/9: 0.9.2; EL10: 0.20.5; r3 not indexed
DEB: D12/D13/U24/U26: 0.20.5; U22: 0.9.2; r2 not indexed
2026-07-30pg_partmanRPM: 5.4.05.5.0
DEB: 5.4.25.5.0
RPM: PG14-18
DEB: Use postgresql-PGVERSION-partman package name
2026-07-30pg_search0.24.30.25.0PG15-18; pgrx 0.19.1; add pgvector/OpenBLAS dependencies
2026-07-30pgcontext-0.2.0PG17-18; pgrx 0.19.1; optional pgvector bridge
2026-07-30pgedgeRPM only: 18.418.4PG15-18 ABI fix; r2 not indexed
2026-07-30pgmnemo0.13.00.15.0PG17-18; requires pgvector >= 0.7.0
2026-07-30pgmp-1.0.6PG14-18; GMP dependency
2026-07-30pgpcreRPM only: 0.201905090.20190509EL8/9 only; r2 not indexed
2026-07-30pgwasm-0.1.0PG14-18
2026-07-30plpgsql_check2.10.12.10.3PG14-18; optional preload
2026-07-30postbis-1.0PG14-18 compatibility patch; r2
2026-07-30qdgc-0.1.0PG14-18; includes qdgc_postgis
2026-07-30rdf_fdw2.6.02.7.0PG14-18
2026-07-30timescaledb2.28.32.29.0PG16-18
2026-07-30uriRPM only: 1.202510291.20251029Renamed to pguri; Provides/Obsoletes pg_uri; r2
2026-07-30vector0.8.50.8.6PG14-18; 0.8.6 not indexed
2026-07-30pg_rewriteDEB only: 2.0.02.2Renamed to postgresql-PGVERSION-pg-rewrite; PG14-18
2026-07-30pgactiveDEB only: 2.1.72.1.7PG14-18 build fix; r2 not indexed
2026-07-30pgzintDEB only: -0.2.0D13/U26 only; requires Zint >= 2.14; not indexed
2026-07-30timeseriesDEB only: 0.2.10.2.1Fix partman/cron Recommends and docs; r3
2026-07-24argm-1.1.1PG14-18
2026-07-24cron_utils-0.1.0SQL-only; PG14-18
2026-07-24fbsql-0.1.0PL/R; PG16-18
2026-07-24oidc_validator-0.1.0Rust OIDC; PG18
2026-07-24online_advisor-1.0PG14-18
2026-07-24pg_cjk_parser-0.1.0PG14-18
2026-07-24pg_extension_base-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_extension_updater-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_fts-0.2.0PG17-18
2026-07-24pg_jieba-1.1.0pkg 2.0.1; SQL 1.1.0; PG14-18
2026-07-24pg_kpart-1.0PG14-18
2026-07-24pg_lake-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_lake_copy-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_lake_engine-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_lake_iceberg-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_lake_table-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_map-3.4pg_lake 3.4; PG16-18; RPM EL9/10
2026-07-24pg_oidc_validator-0.2Percona OIDC; PG18; DEB all, RPM EL10
2026-07-24pg_roast-1.0PG14-18
2026-07-24pg_tiktoken_c-1.1PG14-18
2026-07-24pgfr_analyze-2.29.2pg_flight_recorder; PG15-18
2026-07-24pgfr_record-2.29.2pg_flight_recorder; PG15-18
2026-07-24pgmemento-0.7.4SQL-only; PG14-18
2026-07-24pgmonitor-2.2.0PG14-18
2026-07-24pgsqlmock-1.0.1PG14-18
2026-07-24plx-1.3.1PG14-18
2026-07-24anon3.1.13.1.3pgrx 0.19.1; PG14-18
2026-07-24block_copy_command0.1.50.1.5pgrx 0.19.1; PG14-18
2026-07-24convert0.1.00.1.0pgrx 0.19.1; PG14-18
2026-07-24etcd_fdw0.0.10.0.1pgrx 0.19.1; PG14-18
2026-07-24explain_ui0.0.20.0.2pgrx 0.19.1; PG14-18
2026-07-24graph0.1.70.1.8pgrx 0.19.1; PG14-18
2026-07-24jsonschema0.1.90.1.9pgrx 0.19.1; PG14-18
2026-07-24pg_base580.0.10.0.1pgrx 0.19.1; PG14-18
2026-07-24pg_bestmatch0.0.20.0.2pgrx 0.19.1; PG14-18
2026-07-24pg_cardano1.2.01.2.0pgrx 0.19.1; PG15-18
2026-07-24pg_command_fw0.1.00.1.0pgrx 0.19.1; PG15-18
2026-07-24pg_durable0.2.20.2.3pgrx 0.19.1; PG14-18
2026-07-24pg_enigma0.5.00.5.0pgrx 0.19.1; PG14-18
2026-07-24pg_eviltransform0.0.20.0.4pgrx 0.19.1; PG14-18
2026-07-24pg_graphql1.6.11.6.1pgrx 0.19.1; PG14-18
2026-07-24pg_idkit0.4.00.4.0pgrx 0.19.1; PG14-18
2026-07-24pg_jsonschema0.3.40.3.4pgrx 0.19.1; PG14-18
2026-07-24pg_kazsearch2.2.02.3.0pgrx 0.19.1; PG16-18
2026-07-24pg_later0.4.00.4.0pgrx 0.19.1; PG14-18
2026-07-24pg_mooncake0.2.00.2.0pgrx 0.19.1; PG14-18
2026-07-24pg_parquet0.5.10.5.1pgrx 0.19.1; PG14-18
2026-07-24pg_pinyin0.0.40.0.5pgrx 0.19.1; PG14-18
2026-07-24pg_polyline0.0.10.0.1pgrx 0.19.1; PG14-18
2026-07-24pg_render0.1.30.1.3pgrx 0.19.1; PG14-18
2026-07-24pg_rrf0.0.30.0.3pgrx 0.19.1; PG14-18
2026-07-24pg_search0.24.00.24.3pgrx 0.19.1; PG15-18
2026-07-24pg_session_jwt0.5.00.5.0pgrx 0.19.1; PG14-18
2026-07-24pg_smtp_client0.2.10.2.1pgrx 0.19.1; PG14-18
2026-07-24pg_strict1.0.51.0.5pgrx 0.19.1; PG14-18
2026-07-24pg_summarize0.0.10.0.1pgrx 0.19.1; PG14-18
2026-07-24pg_tiktoken0.0.10.0.1pgrx 0.19.1; PG14-18
2026-07-24pg_tokenizer0.1.10.1.1pgrx 0.19.1; PG14-18
2026-07-24pg_trickle0.81.00.81.0pgrx 0.19.1; PG18
2026-07-24pg_when0.1.90.1.9pgrx 0.19.1; PG14-18
2026-07-24pgdd0.6.10.6.1pgrx 0.19.1; PG14-18
2026-07-24pglinter2.0.02.0.0pgrx 0.19.1; PG14-18
2026-07-24pglite_fusion0.0.60.0.6pgrx 0.19.1; PG14-18
2026-07-24pgmqtt0.3.00.4.1pgrx 0.19.1; PG14-18
2026-07-24pgrdf0.6.40.6.20pgrx 0.19.1; PG14-18
2026-07-24pgsmcrypto0.1.10.1.1pgrx 0.19.1; PG14-18
2026-07-24pgx_ulid0.2.30.2.3pgrx 0.19.1; PG14-18
2026-07-24plprql18.0.118.0.1pgrx 0.19.1; PG14-18
2026-07-24timescaledb_toolkit1.23.01.23.0pgrx 0.19.1; PG15-18
2026-07-24typeid0.3.00.3.0pgrx 0.19.1; PG14-18
2026-07-24tzf0.3.00.3.0pgrx 0.19.1; PG14-18
2026-07-24vchord1.1.11.1.1pgrx 0.19.1; PG14-18
2026-07-24vchord_bm250.3.00.3.0pgrx 0.19.1; PG14-18
2026-07-24vectorize0.26.20.26.2pgrx 0.19.1; PG14-18
2026-07-24vectorscale0.9.00.9.0pgrx 0.19.1; PG14-18
2026-07-24wrappers0.6.10.6.2pgrx 0.19.1; PG14-18
2026-07-24ageRPM only: 1.7.01.8.0PG18: 1.8.0-rc0; PG17: 1.7.0
2026-07-24babelfishpg_tsql5.5.05.4.0Catalog fix: 5.4.0; PG17-18
2026-07-24biscuit2.4.12.4.3pkg 2.4.3; SQL 2.4.1; PG16-18
2026-07-24decoderbufs3.5.03.6.0DEB 3.6.0; RPM 3.5.0; PG14-18
2026-07-24documentdb0.1130.114PG15-18; 16 targets
2026-07-24documentdb_core0.1130.114PG15-18; 16 targets
2026-07-24documentdb_distributed0.1130.114PG15-18; 16 targets
2026-07-24documentdb_extended_rum0.1130.114PG15-18; 16 targets
2026-07-24http1.7.11.7.2PG14-18
2026-07-24jdbc_fdw0.4.00.5.0pkg 0.5.0; SQL 1.2; PG14-18; 16 targets
2026-07-24nominatim_fdw1.32.0.0PG14-18; 16 targets
2026-07-24odbc_fdw0.5.10.6.1pkg 0.6.1; SQL 0.5.2; PG14-18
2026-07-24ogr_fdw1.1.81.1.9PG14-18
2026-07-24pg_csvRPM only: 1.0.11.0.2+RPM; pkg 1.0.2; SQL 1.0.1; PG14-18
2026-07-24pg_dbms_errlog2.22.4PG14-18
2026-07-24pg_ivm1.141.15PG14-18
2026-07-24pg_net0.20.30.20.5RPM: pkg 0.20.5; SQL 0.20.4; PG14-18; RPM EL10
DEB: D12/D13/U24/U26: 0.20.5; U22: 0.9.2 (libcurl); PG14-18
2026-07-24pg_rewriteRPM only: 2.0.02.2PG14-18
2026-07-24pg_statement_rollback1.51.6PG14-18
2026-07-24pg_tde2.12.2Percona; PG17-18
2026-07-24pgnodemxRPM only: 1.72.0.1pkg 2.0.1; SQL 2.0; PG14-18; cgroup-safe
2026-07-24pgauditlogtofile1.8.41.8.5PG14-18
2026-07-24pgbson2.0.22.0.4pkg 2.0.4; SQL 2.0; PG14-18
2026-07-24pgclone4.3.24.4.2PG14-18
2026-07-24pgextwlist1.191.20PG14-18
2026-07-24pgmnemo0.12.10.13.0PG17-18
2026-07-24pgmq1.11.11.12.0PG14-18
2026-07-24pgsentinel1.4.11.4.2RPM 1.4.2; DEB 1.4.0; U26 1.4.1; PG14-18
2026-07-24plpgsql_check2.9.22.10.1PG14-18
2026-07-24plproxy2.11.02.12.0PG14-18
2026-07-24powa5.1.25.2.0DEB 5.2.0; RPM 5.1.0; PG14-18
2026-07-24provsql1.10.01.11.0PG14-18
2026-07-24re20.3.00.4.1PG16-18
2026-07-24snowflake2.42.5.0pgEdge; PG15-18
2026-07-24spock5.0.65.0.10pgEdge; PG15-18
2026-07-24tdigest1.4.31.4.4PG14-18
2026-07-24timescaledb2.28.22.28.3PG15-18: 2.28.3; PG14: 2.19.3; 6 EL
2026-07-24vector0.8.40.8.5PG14-18
2026-07-24babelfishpg_money1.1.01.1.0Babelfish: +PG18
2026-07-24babelfishpg_tds1.0.01.0.0Babelfish: +PG18
2026-07-24citus14.1.014.1.0Citus 13.0.0; EL10 RPM PG14, 2 arch
2026-07-24dbt20.61.70.61.7+DEB PG14-18; +EL8 RPM PG17-18, 2 arch
2026-07-24decoder_raw1.01.0EL10/D13; PG14-16; 2 arch
2026-07-24faker0.5.30.5.3RPM: +DEB PG14-18
DEB: +DEB PG14-18; D12/U22: python3-fake-factory 22.0.0
2026-07-24gb18030_20221.01.0IvorySQL 5.4; PG18; 16 targets
2026-07-24h34.2.34.2.3EL8 x86_64 RPM PG17-18
2026-07-24hdfs_fdw2.3.32.3.3+DEB PG14-18
2026-07-24hstore_pllua2.0.122.0.12+RPM 6 EL PG14-18
2026-07-24hstore_plluau2.0.122.0.12+RPM 6 EL PG14-18
2026-07-24hunspell_cs_cz1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_de_de1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_en_us1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_fr1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_ne_np1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_nl_nl1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_nn_no1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_pt_pt1.01.016 targets; pt_pt.stop avoids core conflict
2026-07-24hunspell_ru_ru1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24hunspell_ru_ru_aot1.01.0hunspell bundle; 10 dictionaries; 16 targets; PG14-18
2026-07-24imgsmlr1.01.0EL10/D13; PG14-18; 2 arch
2026-07-24ivorysql_ora1.01.0IvorySQL 5.4; PG18; 16 targets
2026-07-24mobilitydb1.3.01.3.0+RPM 6 EL PG14-18; +U22 DEB PG18
2026-07-24mobilitydb_datagen1.3.01.3.0mobilitydb bundle; +RPM 6 EL; +U22 DEB PG18
2026-07-24omni0.2.140.2.14omnigres 20251108; EL10 PG14-18; EL8/9,D12/U22 PG18
2026-07-24ora_btree_gin1.01.0IvorySQL 5.4; PG18; 16 targets
2026-07-24ora_btree_gist1.01.0IvorySQL 5.4; PG18; 16 targets
2026-07-24pg_dbms_job2.02.0+DEB PG14-18
2026-07-24pg_dbms_lock2.02.0+DEB PG14-18
2026-07-24pg_dbms_metadata1.0.01.0.0+DEB PG14-18; +EL8 aarch64 RPM PG15
2026-07-24pg_fact_loader2.0.12.0.1U26 DEB PG14-18
2026-07-24pg_get_functiondef1.01.0IvorySQL 5.4; PG18; 16 targets
2026-07-24pg_strom6.16.1pg_strom 3.5; EL10 x86_64 PG14
2026-07-24pgautofailover2.22.26 EL RPM: +PG18
2026-07-24pgbouncer_fdw1.4.01.4.0+DEB PG14-18
2026-07-24pg_wait_samplingRPM only: 1.1.111.1.11+RPM PG14-18; SQL 1.1
2026-07-24pgl_ddl_deploy2.2.12.2.1RPM: +RPM PG14-18; +U26 DEB PG14-17
DEB: 10 DEB: +PG18; U26 PG14-17
2026-07-24pglogical_ticker1.4.11.4.16 EL RPM PG14-17
2026-07-24pgmemcache2.3.02.3.0EL8 aarch64 RPM PG14-15
2026-07-24pgml2.10.02.10.0EL10/D13/U26; PG14-17; 2 arch
2026-07-24pgspider_ext1.3.01.3.0RPM: +RPM PG14-18; PG18 compatible
DEB: 10 DEB: +PG18; PG15-18
2026-07-24plisql1.01.0IvorySQL 5.4; PG18; 16 targets
2026-07-24pllua2.0.122.0.126 EL: +PG18; EL8 aarch64: +PG14-15
2026-07-24rdkit202503.6202503.6RPM: 202303.3; EL8/9, D12/U22; PG14-18
DEB: D12/U22 PG17-18: 202303.3; U26 PG14-17: 202503.6; runtimes unchanged
2026-07-24sqlite_fdw2.5.02.5.0RPM: RPM r3: +PG18, EL8 SQLite; PG14-18
DEB: 10 DEB: +PG18; PG14-18
2026-07-24sslutils1.41.4EL8 RPM PG18, 2 arch
2026-07-24wal2mongo1.0.71.0.7RPM: +RPM PG14-18; PG17-18 compatible
DEB: 10 DEB: +PG17-18; PG14-18
2026-07-24system_statsDEB only: 4.04.1PG14-18; 10 DEB targets

Infrastructure Package Update Log

The following table contains all 144 Infra log records after v4.4.0, from 2026-07-16 through the latest 2026-08-12 batch. It also includes the ferretdb2 rebuild and RPM exporter package-name migration recorded in the changelog prose. Consecutive upgrades of the same package are retained as separate batch entries.

Build, download, and verification status follows the wording of the original log; it does not establish repository indexing, signing, synchronization, or offline-bundle acceptance. See the Infra changelog for full context.

BatchPackageOld VersionNew VersionNotes
2026-08-12claude2.1.2262.1.227Official manifest verified via proxy; dual-arch RPM/DEB built
2026-08-12code-server4.131.04.132.0Official dual-architecture RPM/DEB downloaded and verified
2026-08-12grafana-infinity-ds3.11.23.11.3Built as dual-architecture RPM/DEB
2026-08-12mtail3.4.63.4.7Built as dual-architecture RPM/DEB
2026-08-12opencode1.18.151.18.16Built as dual-architecture RPM/DEB
2026-08-12pg-hardstorage1.1.11.2.1Official dual-architecture RPM/DEB downloaded and verified
2026-08-12pig1.6.11.8.0Official dual-architecture RPM/DEB downloaded and verified
2026-08-12postgrest16.016.1Static dual-architecture RPM/DEB; requires PostgreSQL 14+
2026-08-12redis-exporter1.88.01.89.0Built as dual-architecture RPM/DEB
2026-08-12sow0.2.00.3.0Official dual-architecture RPM/DEB downloaded and verified
2026-08-12stalwart0.16.160.16.17Built as dual-architecture RPM/DEB
2026-08-08claude2.1.2232.1.226Official manifest verified via proxy; dual-arch built
2026-08-08codex0.146.10.147.0Stable tag rust-v0.147.0; dual-arch built
2026-08-08crush0.88.00.88.1Official tarballs repacked as 1PGSTY with license
2026-08-08grafana13.1.213.1.3Official dual-architecture RPM/DEB artifacts
2026-08-08opencode1.18.141.18.15Built as dual-architecture RPM/DEB
2026-08-08postgrest14.1616.0Static dual-architecture assets; requires PostgreSQL 14+
2026-08-08rainfrog0.4.20.4.3Built as dual-architecture RPM/DEB
2026-08-08rustfs1.0.0-b121.0.0-rc1Upstream rc.1-preview.1; dual-arch RPM/DEB built
2026-08-08uv0.12.20.12.3Built as dual-architecture RPM/DEB
2026-08-07claude2.1.2222.1.223Official manifest verified via proxy; built
2026-08-07codex0.146.00.146.1Stable tag rust-v0.146.1; built
2026-08-07code1.131.01.132.0Official dual-architecture RPM/DEB verified
2026-08-07dblab0.47.20.47.4Built as dual-architecture RPM/DEB
2026-08-07grafana-infinity-ds3.11.13.11.2Built as dual-architecture RPM/DEB
2026-08-07grafana-victorialogs-ds0.30.10.31.0Built as dual-architecture RPM/DEB
2026-08-07k3s1.36.21.36.3Official stable channel v1.36.3+k3s1; built
2026-08-07k3s-images1.36.21.36.3Exact-match dual-architecture airgap images; built
2026-08-07mcli2026080400000020260806000000Official pgsty fork dual-architecture RPM/DEB verified
2026-08-07opencode1.18.131.18.14Built as dual-architecture RPM/DEB
2026-08-07pgschema1.12.11.12.2Official dual-architecture RPM/DEB verified
2026-08-07seaweedfs4.404.41Built as dual-architecture RPM/DEB
2026-08-07silominio 2026080400000020260806000000Official replacement; dual-architecture RPM/DEB verified
2026-08-07uv0.12.10.12.2Built as dual-architecture RPM/DEB
2026-08-07victoria-metrics1.148.01.149.0Main, cluster, and vmutils packages built for both arches
2026-08-07ferretdb22.7.02.7.0Rebuilt at the current version for dual-architecture RPM/DEB
2026-08-05agentsview0.39.00.40.1Built as dual-architecture RPM/DEB
2026-08-05claude2.1.2202.1.222Official manifest verified via proxy; built
2026-08-05code-server4.130.04.131.0Official artifacts downloaded and verified
2026-08-05crush0.87.00.88.0Official links only; redistribution blocked
2026-08-05grafana13.1.113.1.2Official artifacts verified; security fix
2026-08-05juicefs1.4.01.4.1Built as dual-architecture RPM/DEB
2026-08-05mcli2026041700000020260804000000pgsty fork artifacts downloaded and verified
2026-08-05minio2026061800000020260804000000pgsty fork artifacts downloaded and verified
2026-08-05mongodb-exporter0.51.00.52.0Built as dual-architecture RPM/DEB
2026-08-05mtail3.0.83.4.6Built as dual-architecture RPM/DEB
2026-08-05nodejs24.18.124.19.0Node.js 24.x LTS; built
2026-08-05opencode1.18.91.18.13Built as dual-architecture RPM/DEB
2026-08-05pg-hardstorage1.0.171.1.1Official artifacts downloaded and verified
2026-08-05pgbackrest-exporter0.23.00.24.0Built as dual-architecture RPM/DEB
2026-08-05pgstream1.2.51.3.1Built as dual-architecture RPM/DEB
2026-08-05rclone1.74.41.75.0Official artifacts downloaded and verified
2026-08-05rustfs1.0.0-b111.0.0-b12Beta line; built as dual-architecture RPM/DEB
2026-08-05stalwart0.16.150.16.16Built as dual-architecture RPM/DEB
2026-08-05uv0.12.00.12.1Built as dual-architecture RPM/DEB
2026-08-05vray5.51.25.52.0Latest stable; built as dual-architecture RPM/DEB
2026-08-05xray26.3.2726.7.28Latest dated release; built as dual-architecture RPM/DEB
2026-08-05prometheus3.13.13.13.2Security and stability release
2026-08-05pig1.6.01.6.1Refreshed extension catalog
2026-07-30agentsview0.38.10.39.0
2026-07-30claude2.1.2182.1.220
2026-07-30cloudflared2026.7.22026.7.3
2026-07-30code1.130.01.131.0
2026-07-30code-server4.129.04.130.0
2026-07-30codex0.145.00.146.0Release tag rust-v0.146.0
2026-07-30crush0.86.00.87.0
2026-07-30dblab0.46.00.47.2
2026-07-30etcd3.7.03.7.1
2026-07-30genai-toolbox1.7.01.8.0Source build; Rocky 8/9 and Debian 12 verified
2026-07-30headscale0.29.20.29.3
2026-07-30nodejs24.18.024.18.1Security release
2026-07-30opencode1.18.41.18.9
2026-07-30pg-exporter1.4.01.4.1Official release artifacts
2026-07-30pg-hardstorage1.0.131.0.17
2026-07-30pgschema1.12.01.12.1
2026-07-30pgstream1.2.21.2.5
2026-07-30pig1.5.11.6.0
2026-07-30postgrest14.1514.16
2026-07-30rainfrog0.3.200.4.2
2026-07-30redis-exporter1.87.01.88.0
2026-07-30rustfs1.0.0-beta.101.0.0-beta.11Preview releases excluded
2026-07-30stalwart0.16.140.16.15
2026-07-30uv0.11.310.12.0
2026-07-30victoria-traces0.9.40.10.0
2026-07-23claude2.1.2152.1.218Verified against the official manifest via proxy
2026-07-23codex0.144.60.145.0Release tag rust-v0.145.0
2026-07-23dblab0.44.10.46.0
2026-07-23duckdb1.5.41.5.5
2026-07-23grafana-infinity-ds3.8.03.11.1
2026-07-23grafana-victorialogs-ds0.30.00.30.1
2026-07-23opencode1.18.31.18.4
2026-07-23pg-timetable6.3.07.0.0Major release
2026-07-23pgstream1.2.01.2.2
2026-07-23stalwart0.16.130.16.14
2026-07-23uv0.11.290.11.31
2026-07-23grafana13.1.013.1.1Direct-download artifacts
2026-07-23pg-hardstorage1.0.121.0.13Direct-download artifacts
2026-07-23crush0.85.00.86.0Direct-download artifacts
2026-07-23code1.129.11.130.0Direct-download artifacts
2026-07-20RPM exporter package namesxxx_exporterxxx-exporterRenamed underscore-style RPM packages to hyphenated names to match DEB naming
2026-07-20pg-exporter1.3.01.4.0Repackaged from the upstream Linux tarball
2026-07-20victoria-metrics1.147.01.148.0VictoriaMetrics main package
2026-07-20victoria-metrics-cluster1.147.01.148.0VictoriaMetrics companion package
2026-07-20vmutils1.147.01.148.0VictoriaMetrics companion package
2026-07-20victoria-logs1.51.01.52.0VictoriaLogs main package
2026-07-20vlogscli1.51.01.52.0VictoriaLogs companion package
2026-07-20vlagent1.51.01.52.0VictoriaLogs companion package
2026-07-20grafana-victorialogs-ds0.29.00.30.0
2026-07-20seaweedfs4.394.40
2026-07-20rustfs1.0.0-b91.0.0-b10Prerelease line; preview releases excluded
2026-07-20sabiql1.14.01.15.1
2026-07-20timescaledb-tools0.19.0-10.19.0-2Bundles timescaledb-parallel-copy 0.13.0
2026-07-20claude2.1.2112.1.215Downloaded through the 8118 proxy and verified
2026-07-20codex0.144.40.144.6Release tag rust-v0.144.6
2026-07-20genai-toolbox1.6.01.7.0External build from official GCS binary and arm64 container artifact
2026-07-20opencode1.18.21.18.3
2026-07-20pg-hardstorage1.0.101.0.12Direct-download artifacts
2026-07-20code1.129.01.129.1Direct-download artifacts
2026-07-20code-server4.128.04.129.0Direct-download artifacts
2026-07-20pev21.22.01.23.0Noarch package
2026-07-20k3s-1.36.2Upstream v1.36.2+k3s1; amd64 and arm64
2026-07-20k3s-images-1.36.2Exact-match system image package for both architectures
2026-07-16jmx-exporter-1.6.0New noarch package
2026-07-16node_exporter1.11.11.12.1
2026-07-16redis_exporter1.86.01.87.0
2026-07-16etcd3.6.133.7.0
2026-07-16dblab0.43.00.44.1
2026-07-16pgstream1.1.11.2.0
2026-07-16rainfrog0.3.190.3.20
2026-07-16rustfs1.0.0-b81.0.0-b9Prerelease line
2026-07-16agentsview0.37.50.38.1
2026-07-16claude2.1.2062.1.211Downloaded through the 8118 proxy and verified
2026-07-16codex0.144.10.144.4Release tag rust-v0.144.4
2026-07-16stalwart0.16.120.16.13
2026-07-16npgsqlrest3.20.03.21.0
2026-07-16postgrest14.1414.15
2026-07-16opencode1.17.181.18.2
2026-07-16uv0.11.280.11.29
2026-07-16vector0.56.00.57.0Direct-download artifacts
2026-07-16pg-hardstorage1.0.81.0.10Direct-download artifacts
2026-07-16crush0.84.00.85.0Direct-download artifacts
2026-07-16code1.128.01.129.0Direct-download artifacts
2026-07-16code-server4.127.04.128.0Direct-download artifacts
2026-07-16cloudflared2026.7.12026.7.2Direct-download artifacts

Compatibility Changes and Upgrade Notes

  • Existing FERRET deployments should remove the legacy ferretdb systemd service and redeploy the protocol layer with docker.yml and app.yml. The old mongo.yml playbook, mongo_* parameters, scrape job, and dedicated dashboard are no longer provided.
  • Pigsty no longer renders /etc/default/haproxy for the HAProxy unit, although the unit can read it when present. Use only EXTRAOPTS for process arguments, not OPTIONS. Any EXTRAOPTS override must retain -S /run/haproxy-master.sock and must not include -f.
  • New module playbooks require target hosts to define the corresponding pg_cluster, redis_cluster, minio_cluster, kafka_cluster, or mysql_cluster explicitly. Custom inventories that relied on fixed group names without cluster identity variables must add those identities first.
  • The MINIO role now accepts only minio_type: silo; minio and rustfs fail during identity validation. Silo retains MinIO protocol and on-disk compatibility, but the package, binary, and systemd service names change. Back up existing object storage and validate in-place compatibility and rollback before upgrading; do not treat package replacement as a migration that has already passed acceptance.
  • Valkey remains opt-in. redis_type: valkey installs valkey-server and valkey-cli, while configuration paths, service names, monitoring jobs, and other module-facing interfaces remain under redis for compatibility.
  • Pigsty’s core REPO/CACHE roles require SOW and use sow create --pigsty to generate local repositories. Older offline bundles or local repositories without SOW 0.3.0 must first install or refresh it from the Pigsty INFRA repository. pig repo create is a separate CLI path whose fallback behavior depends on its own version.
  • MySQL mysql_databases entries accept only name, encoding, and collate, and databases are created with DEFAULT ENCRYPTION='N'. mysql_parameters cannot use loose_, skip_, disable_, or enable_ prefixes to bypass platform-owned, replication, or TLS option protection.
  • Custom RPM repositories and external automation that still reference underscore names such as node_exporter or redis_exporter must move to the hyphenated node-exporter and redis-exporter package names.
  • docker/Makefile no longer accepts DATA to redirect the cleanup target. make purge deletes repository-local ./data immediately without a countdown; preserve any required data first.
  • KAFKA and MYSQL remain pilot modules. Kafka clients must resolve and reach each broker directly rather than putting the data plane behind HAProxy, a VIP, or an L4 load balancer. MySQL currently accepts exactly one or three members.

All 14 validated offline artifacts are published on GitHub for this release, one per recommended OS version and architecture, alongside a checksums manifest and a detached PGP signature (.asc) for every file.

Checksums

e042059379bdfae8f774022b89e8d1e3  pigsty-pkg-v4.5.0.el9.aarch64.tgz
997e812a433a6b969b976fad2c023a1f  pigsty-pkg-v4.5.0.el9.x86_64.tgz
1e1045db965282d564680534bd7d72e2  pigsty-pkg-v4.5.0.el10.aarch64.tgz
9a53f1e85cbb2d4f85969a6112ae4b05  pigsty-pkg-v4.5.0.el10.x86_64.tgz
b7501783c90311176f21bdd35390c746  pigsty-pkg-v4.5.0.d12.aarch64.tgz
f3ecaa449a0bf8e0f01907f83831e74a  pigsty-pkg-v4.5.0.d12.x86_64.tgz
863165dba76b044ed8615d6743710005  pigsty-pkg-v4.5.0.d13.aarch64.tgz
d86655361ccad7aa95a345a82bb37d10  pigsty-pkg-v4.5.0.d13.x86_64.tgz
017f2d7931eb644d2d0fa2f71930134e  pigsty-pkg-v4.5.0.u26.aarch64.tgz
61451ee610134423ff08f1a69dfced33  pigsty-pkg-v4.5.0.u26.x86_64.tgz
5d9cfc52a25545b56e73e94ab5b5e175  pigsty-pkg-v4.5.0.u24.aarch64.tgz
dba0eef49899509d1524b3a1c37d0ddc  pigsty-pkg-v4.5.0.u24.x86_64.tgz
5564841c7c099489708cd1fe49ffa1b9  pigsty-pkg-v4.5.0.u22.aarch64.tgz
dc52b6cee50cf6226e23b065e5aa8395  pigsty-pkg-v4.5.0.u22.x86_64.tgz
afb5cd77903613cb945bd519e4059c76  pigsty-v4.5.0.tgz

v4.4.0

Pigsty v4.4.0 is a maintenance release centered on PostgreSQL 18.4, PostgreSQL 19 beta readiness, 531 extensions, refreshed kernel variants, and broader platform coverage.

Released on 2026-07-10. See the GitHub release and all changes since v4.3.0.

Highlights

  • PostgreSQL 18.4 / 19 beta: PostgreSQL 18.4 is now the production default, with a minimal PostgreSQL 19 beta template for evaluation.
  • 531 extensions and refreshed kernels: The catalog adds 21 extensions and updates major PostgreSQL variants across the supported platform matrix.
  • Safer operations with Pig 1.5.1: New clone, fork, and PITR workflows arrive alongside automatic VIP discovery, Zstandard pgBackRest compression, and dedicated Patroni log collection.
  • Security, applications, and tooling: Secret handling and repository automation are hardened, with new app templates, a redesigned portal, and optional Codex support.
  • Platform validation: All 14 offline deployment tests pass across seven OS baselines on both x86_64 and aarch64.
  • Offline artifacts: The Community Edition publishes six dual-architecture offline packages for Debian 13, EL 10, and Ubuntu 24.04 on GitHub. Prebuilt packages for the other validated baselines are available with the Professional Edition.

Upgrade Notes

  • Generated pgBackRest configurations now use compress-type=zst; preserve intentional local overrides before re-rendering them. #744
  • Patroni logs now use /pg/log/patroni and job=patroni; update custom log queries and alert rules that use the old syslog selector.
  • VIP interfaces now default to auto, dnsmasq records move to /etc/dnsmasq.d/pigsty, and Pigsty manages /etc/default/haproxy; preserve explicit network overrides where needed.
  • The default etcd backend quota drops from 16 GiB to 8 GiB; check existing backend usage before applying the new configuration.
  • pig automation must use -y/--yes for destructive commands, while pig pb restore and pig pitr require one explicit recovery target. See the pig v1.5 notes.
  • Supabase analytics moves to the _supabase database and _analytics schema; existing deployments should create them before switching stacks.

Security and Operations

  • The pg-pitr wrapper adds safer target selection, timelines, dry runs, and stronger checks against unsafe recovery targets.
  • Application secrets are hidden from Ansible output, generated .env files use mode 0600, and Grafana no longer prints the administrator password.
  • The dbsu sudo policy gains controlled journal access, while the repository adds a security policy, CodeQL, Dependabot, pinned actions, and release-signing automation.

Applications and Tooling

  • Added Immich, Maybe, and JumpServer templates; refreshed Supabase, Dify, InsForge, Registry, Jupyter, Kong, Odoo, Teable, Mattermost, and related launch helpers.
  • Rebuilt the bilingual infrastructure portal and added opt-in Codex CLI support to the experimental VIBE module; Claude Code remains its default managed coding agent.
  • Removed the legacy FerretDB Compose template; the FERRET module remains available.

Bug Fixes

  • Fixed EL10 PostgreSQL/libpq provider conflicts, EPEL path handling, and PGDG minor-version repository rules. #752
  • Reused an existing /www directory during bootstrap and fixed Redis Sentinel HA password rendering. #753 #748
  • Corrected RPM naming and package groups for pg_http, pg_gzip, apache-age, and odbc_fdw. #750
  • Prevented unexpected service starts during Debian and Ubuntu package installation, and improved EL9 aarch64 Patroni package handling.
  • Fixed VirtualBox private-network routing and default NIC selection.
  • Fixed shell portability and Vector log lifecycle issues, along with PG19 io_workers, Teable HBA, and application runtime defaults.

PostgreSQL and Extension Package Changes

The release adds 21 extensions, updates the PostgreSQL 18.4 package graph, introduces the PostgreSQL 19 beta template, and refreshes major kernel variants. Versions below are verified against final repository metadata and, where bundled, the v4.4.0 artifacts; PG major ranges describe catalog and repository coverage.

PostgreSQL RPM changes · PostgreSQL DEB changes · Infrastructure package changes

PackageOld VersionNew VersionNotes
polardb-1717.9.1.017.10.1.0PG 17; RPM added
agensgraph-172.16.02.17.0PG 17.10
openhalodb-141.0-beta1.0-2OpenHaloDB
babelfish-175.4.05.4.0PG 17.7; rebuild
babelfish-18-6.0.0PG 18.3
pgedge17.9 / 18.315.18 / 16.14 / 17.10 / 18.4PG 15/16 added; PG 17/18 updated; Spock 5.0.10
ivorysql-185.05.4PG 18; RPM added
cloudberry2.1.0-12.1.0-2 / 2.1.0-3DEB/RPM rebuild; RPM path /usr/cloudberry
cloudberry-backup2.1.0-12.1.0-2 / 2.1.0-3backup subpackage
cloudberry-pxf2.1.0-12.1.0-2 / 2.1.0-3PXF subpackage
pg_ducklake-1.0.0PG 14-18
psql_bm25s-0.4.13BM25 retrieval; PG 17-18
mongo_fdw5.5.35.5.3new DEB packaging; existing PGDG RPM, PG 14-18
multicorn3.23.2new DEB packaging; existing PGDG RPM, PG 14-18
pg_orca-1.0.0PG 18 only
pg_sorted_heap-0.14.0PG 16-18
pg_stl-1.0.0PG 16-18
fsm_core-1.1.0PG 15-18
pg_projection-1.0.0PG 14-18
graph-0.1.7PG 14-18
jsonschema-0.1.9PG 14-18
pg_durable-0.2.2PG 14-18
pg_stat_log-0.1PG 18 only
pg_stat_plans-2.1.0PG 16-18
pg_task1.0.02.1.29PG 14-18, pcre2grep fix
pg_stat_backtrace-1.0.0PG 14-18; libunwind
pg_mockable-1.1.0PG 14-18
db2fce-0.0.17PG 14-18
pg_uuid_v8-1.0.0PG 14-18
pg_extra_time2.0.02.1.0PG 14-18
pg_pinyin0.0.20.0.4PG 14-18
passwordpolicy-2.0.5PG 14-18
pgdisablelogerror-1.0PG 14-18
plpgsql_wrap-1.0PG 14-18
timescaledb2.26.42.28.2PG 15-18
documentdb0.1100.113PG 15-18
citus14.0.0-414.1.0PG 16-18
pgvector0.8.20.8.4PG 14-18
orioledb1.7-beta151.8-beta16Build for PG 16, 17, 18
pg_search0.23.10.24.0PG 15-18
pg_textsearch1.1.01.2.0BM25 full-text search, PG 17-18
storage_engine1.3.42.4.0PGXN 2.x bump, PG 15-18
pg_clickhouse0.2.00.3.2PGXN bump, ClickHouse integration
provsql1.2.31.10.0PGXN bump, PG 14-18
pgclone4.0.04.3.2PGXN bump, PG 14-18
biscuit2.2.22.4.0 DEB / 2.4.1 RPMPG 16-18
pgmnemo0.7.20.12.1PG 14-18
rdf_fdw2.5.02.6.0PG 14-18, libcurl compatibility patch
roaringbitmap1.1.01.2.0-2PG 14-18, llvm-lto packaging fix
plpgsql_check2.9.02.9.2PG 14-18
timescaledb_toolkit1.22.01.23.0PG 15-18, pgrx 0.18.1
wrappers0.6.00.6.1PG 14-18, pgrx 0.18.1
pgrdf0.5.00.6.4PG 14-17, pgrx 0.18.1
pg_graphql1.5.121.6.1PG 14-18, pgrx 0.18.1
pg_anon3.0.133.1.1PG 14-18, pgrx 0.18.1
pg_kazsearch2.0.02.2.0PG 16-18, pgrx 0.18.1
pg_session_jwt0.4.00.5.0PG 14-18, pgrx 0.18.1
pg_tzf0.2.40.3.0PG 14-18, pgrx 0.18.1
pg_vectorize0.26.10.26.2PG 14-18, pgrx 0.18.1
pglinter1.1.22.0.0PG 14-18, pgrx 0.18.1
pgmqtt0.1.00.3.0PG 14-18, pgrx 0.18.1
etcd_fdw0.0.00.0.1PG 14-18, pgrx 0.18.1
pg_http1.7.01.7.1PG 14-18, RPM rename to pgsql_http_$v
pg_gzip1.0.01.1.0PG 14-18, RPM rename to pgsql_gzip_$v
age1.7.01.7.0PG 17-18, RPM rename to age_$v
pg_trickle0.40.00.81.0PG 18 only
re20.1.10.4.0PG 16-18
pg_background1.9.22.0.2 DEB / 2.0 RPMPG 14-18
firebird_fdw1.4.11.4.2PG 14-18
pg_net0.20.20.20.3DEB + EL10 RPM; EL8/9 RPM stays on 0.9.2
pg_dirtyread2.72.8PG 14-18
pg_stat_ch0.3.60.3.6PG 16-18, rebuild
pggraph0.1.50.1.7PG 14-18
pgsql_tweaks1.0.21.0.5PG 14-18; PGDG RPM also carries 1.0.3
pgfincore1.3.11.4.0PG 14-18
toastinfo1.51.7PG 14-18
pg_ivm1.141.15 DEB / 1.14 RPMPG 14-18
timeseries0.2.00.2.1PG 14-18

Infrastructure Package Changes

PackageOld VersionNew VersionNotes
pig1.4.11.5.1
pg_exporter1.2.21.3.0
pgschema1.9.01.12.0
pgstream1.0.11.1.1
pg-hardstorage-1.0.8
codex0.125.00.144.1
claude2.1.1232.1.206
opencode1.14.301.17.18
agentsview0.26.00.37.5
genai-toolbox1.1.01.6.0packaged as mcp-toolbox
crush0.64.00.84.0
code1.118.11.128.0
code-server4.117.04.127.0
victoria-metrics1.142.01.147.0
victoria-metrics-cluster1.142.01.147.0
vmutils1.142.01.147.0
victoria-logs1.50.01.51.0
vlagent1.50.01.51.0
vlogscli1.50.01.51.0
victoria-traces0.8.20.9.4
prometheus3.11.33.13.1
alertmanager0.32.10.33.1
pushgateway1.11.21.11.3
node_exporter1.11.11.11.1tarball cache; version metadata fix
redis_exporter1.82.01.86.0
mongodb_exporter0.50.00.51.0
grafana13.0.113.1.0
grafana-victorialogs-ds0.26.30.29.0
grafana-victoriametrics-ds0.24.00.25.2
vector0.55.00.56.0
minio2026041700000020260618000000
seaweedfs4.224.39
rustfs1.0.0-b11.0.0-b8prerelease line
duckdb1.5.21.5.4
kafka4.2.04.3.1
etcd3.6.103.6.13
restic0.18.10.19.1
juicefs1.3.11.4.0
tigerbeetle0.17.20.17.9
tigerfs0.6.00.7.0
caddy2.11.22.11.4
cloudflared2026.2.02026.7.1
headscale0.28.00.29.2
v2ray5.48.05.51.2
nodejs24.15.024.18.0
golang1.26.21.26.5
hugo0.161.10.164.0
uv0.11.80.11.28
rclone1.73.51.74.4
asciinema3.2.03.2.1
stalwart0.16.20.16.12
maddy0.9.30.9.5
dblab0.38.00.43.0
npgsqlrest3.12.03.20.0
postgrest14.1014.14
sabiql1.11.11.14.0
pev21.21.01.22.0
rainfrog0.3.180.3.19

The MD5 list below covers all 14 validated artifacts. Six Community Edition artifacts are published on GitHub, while the remaining eight are delivered with the Professional Edition. GitHub records SHA-256 digests for the uploaded Community Edition artifacts.

Checksums

7de8b932412f1863fd9c033a7be355d7  pigsty-pkg-v4.4.0.d12.aarch64.tgz
2e5006a8d35eb1c087dc0ed11cf14d14  pigsty-pkg-v4.4.0.d12.x86_64.tgz
955308c00d3890f6e82a6a83bc624760  pigsty-pkg-v4.4.0.d13.aarch64.tgz
350f31c66de0aafff3bd91c2c9d740a0  pigsty-pkg-v4.4.0.d13.x86_64.tgz
0b4817a8edbab0bdf37ecee730fb0412  pigsty-pkg-v4.4.0.el10.aarch64.tgz
4584a61e4456749e68d86e4817cfe526  pigsty-pkg-v4.4.0.el10.x86_64.tgz
21621daf510a532829c36464d48f9198  pigsty-pkg-v4.4.0.el9.aarch64.tgz
504afd5030e2738a25e1b4c570d0e654  pigsty-pkg-v4.4.0.el9.x86_64.tgz
461c999424dee587ca33fe1a63df40d7  pigsty-pkg-v4.4.0.u22.aarch64.tgz
20ccc5ab8f9f4648b05bcd304f9fb5fc  pigsty-pkg-v4.4.0.u22.x86_64.tgz
d092c48ee55116ed5e2c99a3d909ccdd  pigsty-pkg-v4.4.0.u24.aarch64.tgz
24fa5399d8421305961fcaf91325b382  pigsty-pkg-v4.4.0.u24.x86_64.tgz
36f69b699d8b3041d35384970e157631  pigsty-pkg-v4.4.0.u26.aarch64.tgz
330047d117b20f04317dce506edd5d9a  pigsty-pkg-v4.4.0.u26.x86_64.tgz
3077203c0c656ec99abc32b227f6566b  pigsty-v4.4.0.tgz

v4.3.0

Highlights

  • Added about 50 PostgreSQL extensions, bringing the total available extension count to 510.
  • Added Ubuntu 26.04 x86_64/arm64 support, deprecated Ubuntu 20.04 support, and refreshed minor OS variants to Debian 13.4 / Ubuntu 24.04.4.
  • Kernel updates: Supabase is updated to the latest version, pgEdge to PG 18, and PolarDB to PG 17.
  • Grafana is updated to 13.0.1, and MinIO now uses the pgsty branch with CVE fixes.
  • Vagrant templates now consistently use cloud-image series images.

Bug Fixes

  • Relaxed PostgreSQL username validation to allow @.- in usernames.
  • Fixed IPv6 nameserver parsing so DNS configuration is not limited to legacy IPv4 DNS server extraction.
  • Changed the VictoriaTraces Grafana datasource path to /select/jaeger.
  • Made Vagrant disk probing more robust and added bin/el-fix, a guest-network fix script for EL Vagrant images.

PostgreSQL and Extension Package Changes

PackageOld VersionNew VersionNotes
block_copy_command-0.1.5New; PG 14-18; Rust/pgrx 0.17.0
cloudberry2.0.02.1.0Kernel package group; RPM release 2 fixes initdb errno issue
cloudberry-backup-2.1.0New Cloudberry backup tool package
cloudberry-pxf-2.1.0New Cloudberry PXF package
credcheck4.64.7Upgrade; PG 14-18; PGDG
datasketches-1.7.0New; PG 14-18
ddl_historization0.0.70.2Upgrade
documentdb0.1090.110Upgraded to upstream version; PG 15-18
external_file-1.2New; PG 14-18
logical_ddl-0.1.0New; PG 14-18
nominatim_fdw1.1.01.2Upgrade
onesparse-1.0.0New; PG 18 only
orioledbbeta15 1.7beta15 1.7Paired with OriolePG 17.18
oriolepg17.1617.18Kernel patch set update
parray_gin-1.5.0Added, then upgraded; PG 14-18
pg_accumulator-1.1.3New; PG 14-18
pg_anon3.0.13.0.13Upgrade; Rust/pgrx 0.16.1 -> 0.17.0
pg_background1.81.9.2DEB only
pg_bikram_sambat-0.1.0New; Bikram Sambat date type and AD/BS conversion functions
pg_byteamagic-0.2.4New; PG 14-18
pg_cardano1.1.11.2.0Upgrade; Rust/pgrx 0.17.0
pg_clickhouse0.1.50.2.0Upgrade
pg_datasentinel-1.0New; PG 15-18
pg_dbms_job1.52.0Upgrade; PG 14-18; PGDG
pg_dispatch-0.1.5New; PG 14-18
pg_failover_slots1.2.01.2.1Upgrade
pg_fsql-1.1.0New; PG 14-18
pg_incremental1.4.11.5.0Upgrade
pg_isok-1.4.1New; PG 14-18
pg_ivm1.131.14Upgrade; PG 14-18
pg_kazsearch-2.0.0New; PG 16-18; Rust/pgrx 0.17.0
pg_liquid-0.1.7New; PG 14-18
pg_pathcheck-0.9.1New; PG 17-18; requires shared_preload_libraries
pg_query_rewrite-0.0.5New; PG 14-18
pg_regresql-2.0.0New; PG 14-18
pg_rrf-0.0.3New; PG 14-17; Rust/pgrx 0.16.1 -> 0.17.0
pg_savior0.0.10.1.0Upgrade; high-risk DDL/DML guard hook; requires preload or LOAD
pg_search0.22.20.23.1Upgrade; PG 15-18; pgrx 0.18.0
pg_slug_gen-1.0.0New; PG 15-18
pg_stat_ch-0.3.6Added, then upgraded; PG 16-18; EL8 break
pg_store_plans1.91.10Upgrade
pg_strict1.0.31.0.5Upgrade; Rust/pgrx 0.16.1 -> 0.17.0
pg_text_semver-1.2.1New; PG 14-18
pg_textsearch0.5.01.1.0Upgrade; PG 17-18; requires shared_preload_libraries
pg_trickle0.16.00.40.0Upgrade; PG 18 only; pgrx 0.18.0
pg_tzf0.2.30.2.4Upgrade; Rust/pgrx 0.17.0
pg_vectorize0.26.00.26.1Upgrade; Rust/pgrx 0.16.1 -> 0.17.0
pg_variables-1.2.5New; PG 14-18
pg_when-0.1.9New; PG 14-18; Rust/pgrx 0.17.0
pgxicor0.1.00.1.1Upgrade
pgcalendar-1.1.0New; PG 14-18
pgclone-4.0.0Added, then upgraded; PG 14-18
pgelog-1.0.2New; PG 14-18
pglinter1.1.11.1.2Upgrade; Rust/pgrx 0.16.1 -> 0.17.0
pglock-1.0.0New; PG 14-18
pgmq1.11.01.11.1Upgrade; PG 14-18
pgmqtt-0.1.0New; PG 14-18; Rust/pgrx 0.16.1 -> 0.17.0
pgproto-0.5.0Added, then upgraded; native Protobuf support
pghydro-6.6New; PG 14-18
pgx_ulid0.2.20.2.3Upgrade; Rust/pgrx 0.17.0
plv83.2.43.2.4-2RPM only; EL10 build fix
PolarDB15.1517.9.1.0PG 15 -> 17
postgresbson-2.0.2New; PG 14-18
postgis3.6.23.6.3DEB only
prefix1.2.101.2.11Upgrade; PG 14-18; PGDG
provsql-1.2.3New; PG 14-18
rdf_fdw-2.5.0Added, then upgraded; PG 14-18
rdkit-202503.6New; PG 14-18
re2-0.1.1New; PG 16-18
storage_engine-1.3.4Added, then upgraded; columnar and row-compression table access methods
supautils3.1.03.2.1Upgrade
system_stats3.24.0Upgrade
timescaledb2.25.22.26.4Upgrade; TSL minor update
ulak-0.0.2New; PG 14-18
wrappers0.5.70.6.0Upgrade; Rust/pgrx 0.16.1 -> 0.17.0

Infrastructure Package Updates

PackageOld VersionNew VersionNotes
alertmanager0.31.10.32.1
agentsview0.15.00.26.0
claude2.1.812.1.123Downloaded through the 8118 proxy and verified
code1.112.01.118.1Direct-link metadata update
code-server4.112.04.117.0Direct-link metadata update
codex0.116.00.125.0Moved from prerelease track to stable, then upgraded further
crush0.51.20.64.0Direct-link metadata update
dblab0.34.30.38.0
duckdb1.5.01.5.2
etcd3.6.93.6.10Unified package version
garage2.2.02.3.0
genai-toolbox0.27.01.1.0Upstream renamed to mcp-toolbox
golang1.26.11.26.2
grafana12.4.113.0.1Metadata refreshed after major upgrade
grafana-infinity-ds3.7.43.8.0
grafana-plugins12.3.013.0.0Noarch plugin bundle, manually collected
grafana-victoriametrics-ds0.23.10.24.0
hugo0.158.00.161.1
maddy0.8.20.9.3
mcli2026032100000020260417000000pgsty branch, CVE fixed
minio2026032500000020260417000000pgsty branch, CVE fixed
mongodb_exporter0.49.00.50.0
node_exporter1.10.21.11.1
nodejs24.14.024.15.0Stays on the 24.x policy line
npgsqlrest3.11.13.12.0
opencode1.2.271.14.30Switched to versioned cache and rebuilt
pg_exporter1.2.11.2.2Direct-link metadata update
pgflo0.0.15-Removed
pgschema1.7.41.9.0
pig1.3.21.4.1Metadata only
postgrest14.714.10
prometheus3.10.03.11.3
rainfrog0.3.170.3.18
rclone1.73.21.73.5Direct-link metadata update
rustfs1.0.0-alpha.891.0.0-b1Prerelease line
sabiql1.8.21.11.1
seaweedfs4.174.22
sqlcmd1.9.01.10.0
stalwart0.15.50.16.2
tigerbeetle0.16.770.17.2
tigerfs0.5.00.6.0
timescaledb-tools0.18.20.19.0Rebuilt timescaledb-tune
uv0.10.120.11.8
victoria-logs1.48.01.50.0Main package
victoria-metrics1.138.01.142.0
victoria-metrics-cluster1.138.01.142.0VictoriaMetrics companion component
victoria-traces0.8.00.8.2
vip-manager4.0.04.2.0Direct-link metadata update
vlagent1.48.01.50.0VictoriaLogs companion component
vlogscli1.48.01.50.0VictoriaLogs companion component
vmutils1.138.01.142.0VictoriaMetrics companion component
vector0.54.00.55.0Direct-link metadata update
v2ray5.47.05.48.0
xray26.2.626.3.27

Checksums

58a914fce7bc521b65e167f66e7961a3  pigsty-v4.3.0.tgz
9ce070efb0420057a83c632b2856d1b3  pigsty-pkg-v4.3.0.d12.aarch64.tgz
bf21c36d3aff94a1a6353130597ffa85  pigsty-pkg-v4.3.0.d12.x86_64.tgz
81b4790c4e5567cee9d1beadd06e48e6  pigsty-pkg-v4.3.0.d13.aarch64.tgz
06baab9341ab683eaeea2e066b28a0f4  pigsty-pkg-v4.3.0.d13.x86_64.tgz
fb4bf751df5e09f547c49b8ab7cac9a0  pigsty-pkg-v4.3.0.el10.aarch64.tgz
a3e752c8148122d1eaea74a6d8d8df0d  pigsty-pkg-v4.3.0.el10.x86_64.tgz
cb2a9af36615513e66fd5ac3e9f4d797  pigsty-pkg-v4.3.0.el9.aarch64.tgz
e24641a879dec7a8eea74dab42f85920  pigsty-pkg-v4.3.0.el9.x86_64.tgz
6b675fd8d9e039193481f0838aa4b92c  pigsty-pkg-v4.3.0.u22.aarch64.tgz
c0e344ccb9d190a619591e5d46116424  pigsty-pkg-v4.3.0.u22.x86_64.tgz
3e0ec9534cf595201ec79eb1fc6549d8  pigsty-pkg-v4.3.0.u24.aarch64.tgz
0a3d19513eca9615bdd66a4b2bf66f1d  pigsty-pkg-v4.3.0.u24.x86_64.tgz
683a10ff8fd993358d6befa9f4e02913  pigsty-pkg-v4.3.0.u26.aarch64.tgz
fd1ea5cd5554bfe91fadd51ad80860e3  pigsty-pkg-v4.3.0.u26.x86_64.tgz

v4.2.2

Highlights

  • Insforge 2.0.1 self-hosted template
  • Batch infra package updates, MinIO/MCLI updated to 20260321
  • New infra packages: tigerfs, pgstream, sql-studio, rainfog, crush
  • New PG tools: data recovery pdu, connection pooler pgdog
  • Update PG extensions: pg_search, pgsentinel, pg_track_optimizer, pgcollection, pg_ttl_index, pg_clickhouse
  • Update PG Kernel: ivorysql 5.1 -> 5.3

PostgreSQL Package Updates

NameOld VerNew VerNote
pg_search0.21.120.22.2
pgsentinel1.4.01.4.1rpm only
pg_track_optimizer0.9.10.9.2
pgcollection1.0.02.0.0
pg_ttl_index2.0.03.0.0
pg_clickhouse0.1.40.1.5
pdu3.0.25.12new
pgdog0.1.32new

Infrastructure Package Updates

NameOld VerNew VerNote
grafana12.4.012.4.1
pgbackrest_exporter0.22.00.23.0
redis_exporter1.81.01.82.0
victoria-logs1.47.01.48.0
vlagent1.47.01.48.0
vlogscli1.47.01.48.0
victoria-traces0.7.10.8.0
duckdb1.4.41.5.0
pg_timetable6.2.06.3.0
pgschema1.4.21.7.4
pgstream-1.0.1new
tigerbeetle0.16.750.16.77
grafana-victorialogs-ds0.26.20.26.3
grafana-infinity-ds3.7.33.7.4
caddy2.11.12.11.2
npgsqlrest3.10.03.11.1
postgrest14.514.7
opencode1.2.171.2.27
pev21.20.21.21.0
golang1.26.01.26.1
vector0.53.00.54.0
rclone1.73.11.73.2
code-server4.109.54.112.0
code1.109.41.112.0
seaweedfs4.154.17
uv0.10.80.10.12
codex0.110.00.116.0
v2ray5.44.15.47.0
sabiql1.6.21.8.2
sql-studio-0.1.51new
rainfrog-0.3.17new
agentsview0.10.00.15.0
crush-0.51.2new
tigerfs-0.5.0new
victoria-metrics1.137.01.138.0
victoria-metrics-cluster1.137.01.138.0
vmutils1.137.01.138.0
hugo0.157.00.158.0
rustfs1.0.0-alpha.851.0.0-alpha.89
mysqld_exporter0.18.00.19.0
pg_exporter1.2.01.2.1
pig1.3.11.3.2
minio2026021420260321
mcli2026021320260321
claude2.1.682.1.81
ivroysql5.15.3

Checksums

0d9f907ff626203578c687d1418b38ba  pigsty-pkg-v4.2.2.d12.aarch64.tgz
4129baf773c3005f4d697cf452f927a0  pigsty-pkg-v4.2.2.d12.x86_64.tgz
40d5a0d9c2a97615bf0421bae42458ae  pigsty-pkg-v4.2.2.d13.aarch64.tgz
cf91113a2296ad11fff79802ac9b1483  pigsty-pkg-v4.2.2.d13.x86_64.tgz
dbccfeb3978ffb928bd0b501c3c0d42d  pigsty-pkg-v4.2.2.el10.aarch64.tgz
8c848a4e3fa93c2455285fbcad5ddd78  pigsty-pkg-v4.2.2.el10.x86_64.tgz
7c15c9a36f7d2dd740019c20e8c75a4b  pigsty-pkg-v4.2.2.el9.aarch64.tgz
7d6e9e529236a0db2382f42660790ed9  pigsty-pkg-v4.2.2.el9.x86_64.tgz
8f64bb14885ce330603172b186062671  pigsty-pkg-v4.2.2.u22.aarch64.tgz
16d4c36c9e1ff848848c34a257b1025c  pigsty-pkg-v4.2.2.u22.x86_64.tgz
401230741af5b04f163ffc8e688315ab  pigsty-pkg-v4.2.2.u24.aarch64.tgz
5312aa0841694fc560778b9377a32c89  pigsty-pkg-v4.2.2.u24.x86_64.tgz
cabeeb898b56b26c0855f33d5e60411a  pigsty-v4.2.2.tgz

v4.2.1

A maintenance release that adds 3 new extensions.

Major Changes

  • New Extensions: pg_eviltransform is added to the GIS package group, pg_pinyin to the FTS group, and pg_qos to the admin group — all for PG 14–18.
  • PG13 Removed: All pgdg13, pgdg13-nonfree repo entries and PG13 package aliases (pg13-*) are removed from every platform variant (EL7/8/9/10, Debian 12/13, Ubuntu 22/24/26, both x86_64 and aarch64).
  • Config templates (fat.yml, pro.yml, dev.yml, el.yml, debian.yml) no longer reference PG13 packages or repos. Extension version comments are updated to reflect PG 14–18 coverage only.
  • Percona Repo: Origin URL updated from ppg-18.1 to ppg-18.3 to track the latest Percona PostgreSQL distribution.
  • Nginx Repo: Module tag for the Nginx upstream APT repo corrected from infra to nginx on Debian/Ubuntu platforms.
  • UV Venv Fix: roles/node/tasks/pkg.yml now checks for an existing virtualenv before running uv venv, preventing redundant re-creation and potential errors on re-provisioning.
  • Docker Image: less is added to the Pigsty Docker image base packages.
  • Demo Config: Default firewall rules in el.yml and debian.yml demo configs now include port 5432 for direct PostgreSQL access.

Compatibility Notes

PostgreSQL 13 reached its end of life on 2025-11-13. The PGDG YUM repository has archived and removed the pg13 / pg12 directories. If you install Pigsty on EL systems (even without using PG 13), repo access failures may cause installation or update errors.

You can either upgrade directly to Pigsty v4.2.1, or manually edit the repo_upstream_default variable in your corresponding OS file under roles/node_id/vars/ and remove the pg13 repo line.

Additionally, EL8 remains in the Pigsty compatible OS list, but starting from this release, offline packages for EL8 will no longer be published.

No other breaking API or configuration changes in this release.

7 commits, 84 files changed, +4,925 / -5,351 lines (v4.2.0..v4.2.1, 2026-03-04 ~ 2026-03-06)

PostgreSQL Package Updates

PackageOld VersionNew VersionNotes
timescaledb2.25.12.25.2
vchord1.1.01.1.1Added clang build dependency, bug fixes
vchord_bm250.3.0-10.3.0-2Fix the CI version injection issue
aggs_for_vecs1.4.01.4.1
pg_search0.21.90.21.12
pg_pinyin-0.0.2New extension
pg_eviltransform-0.0.2New extension
pg_qos-1.0.0New extension, QoS resource governance

Infrastructure Package Updates

NameOld VersionNew VersionNotes
asciinema3.1.03.2.0
grafana-infinity-ds3.7.23.7.3
victoria-metrics1.136.01.137.0
victoria-metrics-cluster1.136.01.137.0
vmutils1.136.01.137.0
hugo0.155.30.157.0
opencode1.2.151.2.17
rustfs1.0.0-alpha.831.0.0-alpha.85
seaweedfs4.134.15
tigerbeetle0.16.740.16.75
uv0.10.40.10.8
codex0.105.00.110.0
claude2.1.592.1.68
xray-26.2.6New
gost-2.12.0New
sabiql-1.6.2New
agentsview-0.10.0New

Checksums

262b7671424a38b208872582fe835ef8  pigsty-v4.2.1.tgz
62edcca1d1e572a247be018e1c26eda8  pigsty-pkg-v4.2.1.d12.aarch64.tgz
1d55367e2fd9106e6f18b7ee112be736  pigsty-pkg-v4.2.1.d12.x86_64.tgz
f122b1e5ba8a7ae8e3dc6e6dd53eba65  pigsty-pkg-v4.2.1.d13.aarch64.tgz
617a76bfc8df8766e78abf24339152eb  pigsty-pkg-v4.2.1.d13.x86_64.tgz
908509b350403ad1a4a27a88795fee06  pigsty-pkg-v4.2.1.el10.aarch64.tgz
70cb4afd90ed7aea6ab43a264f8eb4a8  pigsty-pkg-v4.2.1.el10.x86_64.tgz
98fbd67334f5c674b12e6af81ef76923  pigsty-pkg-v4.2.1.el9.aarch64.tgz
687fa741ccd9dcf611a2aa964bcf1de8  pigsty-pkg-v4.2.1.el9.x86_64.tgz
a2a30f4b1146b3e79be91d5be57615b6  pigsty-pkg-v4.2.1.u22.aarch64.tgz
7a1f571bd8526106775c175ba728eee1  pigsty-pkg-v4.2.1.u22.x86_64.tgz
a5574071bac1955798265f71ad73c3d4  pigsty-pkg-v4.2.1.u24.aarch64.tgz
59a7632c650a3c034f1fe6cd589d7ab5  pigsty-pkg-v4.2.1.u24.x86_64.tgz

v4.2.0

Highlights

  • Aligned with PostgreSQL out-of-band minor updates: 18.3, 17.9, 16.13, 15.17, 14.22.
  • Total PostgreSQL extension coverage reaches 461 packages.
  • Kernel updates across Babelfish, AgensGraph, pgEdge, OriolePG, OpenHalo, and Cloudberry.
  • Babelfish template now uses a Pigsty-maintained PG17-compatible build, with no WiltonDB repo dependency.
  • Supabase images and self-hosted templates are refreshed to the latest stack, using Pigsty-maintained pgsty/minio.

Major Changes

  • mssql now defaults to Babelfish PG17 (pg_version: 17, pg_packages: [babelfish, pgsql-common, sqlcmd]) and no longer requires an extra mssql repo.
  • Kernel install paths are normalized in pg_home_map: mssql -> /usr/babelfish-$v/, gpsql -> /usr/local/cloudberry.
  • package_map adds a dedicated cloudberry mapping and fixes babelfish* aliases to versioned RPM/DEB package names.
  • Redis data root default changes from /data to /data/redis; deployment blocks legacy defaults, while redis_remove keeps backward-compatible cleanup.
  • configure now supports absolute -o output paths with auto-created parent directories, tri-state region detection (CN/global/offline fallback), and a fix for behind_gfw() hangs.
  • Debian/Ubuntu default repo URL mappings (updates/backports/security) and China mirror components are corrected to prevent bootstrap package failures.
  • Supabase stack is updated (including PostgREST 14.5 and Vector 0.53.0) and now includes missing S3 protocol credential variables.
  • Rich/Sample templates explicitly define dbuser_meta defaults; node.sh systemd completion is simplified.
  • pgbackrest stanza initialization now retries (2 attempts, 5-second interval) to reduce lock contention with archive-push.
  • Vibe template now ships @anthropic-ai/claude-code, @openai/codex, and happy-coder, and includes age in the default example.

PG Software Updates

  • PostgreSQL 18.3, 17.9, 16.13, 15.17, 14.22
  • RPM Changelog 2026-02-27
  • DEB Changelog 2026-02-27
  • Core upgrades: timescaledb 2.25.0 -> 2.25.1, citus 14.0.0-3 -> 14.0.0-4, pg_search -> 0.21.9
  • New/rebuilt: pgedge 17.9, spock 5.0.5, lolor 1.2.2, snowflake 2.4, babelfish 5.5.0, cloudberry 2.0.0
  • Kernel-side updates: oriolepg 17.11 -> 17.16, orioledb beta12 -> beta14, openhalo 14.10 -> 1.0(14.18)
PackageOld VersionNew VersionNotes
timescaledb2.25.02.25.1
citus14.0.0-314.0.0-4Rebuilt from the latest official release
age1.7.01.7.0Added PG 17 support for version 1.7.0
pgmq1.10.01.10.1Package currently unavailable
pg_search0.21.7 / 0.21.60.21.9Previous RPM/DEB versions differ
oriolepg17.1117.16OriolePG kernel update
orioledbbeta12beta14Matches OriolePG 17.16
openhalo14.101.0Updated and renamed, based on 14.18
pgedge-17.9New multi-master edge-distributed kernel
spock-5.0.5New core pgEdge extension
lolor-1.2.2New core pgEdge extension
snowflake-2.4New core pgEdge extension
babelfishpg-5.5.0New BabelfishPG package group
babelfish-5.5.0New Babelfish compatibility package
antlr4-runtime413-4.13New runtime dependency for Babelfish
cloudberry-2.0.0RPM build only
pg_background-1.8DEB build only

Infrastructure Software Updates

NameOld VersionNew Version
grafana12.3.212.4.0
prometheus3.9.13.10.0
mongodb_exporter0.47.20.49.0
victoria-metrics1.135.01.136.0
victoria-metrics-cluster1.135.01.136.0
vmutils1.135.01.136.0
victoria-logs1.45.01.47.0
vlagent1.45.01.47.0
vlogscli1.45.01.47.0
loki3.6.53.6.7
promtail3.6.53.6.7
logcli3.6.53.6.7
grafana-victorialogs-ds0.24.10.26.2
grafana-victoriametrics-ds0.21.00.23.1
grafana-infinity-ds3.7.03.7.2
redis_exporter1.80.21.81.0
etcd3.6.73.6.8
dblab0.34.20.34.3
tigerbeetle0.16.720.16.74
seaweedfs4.094.13
rustfs1.0.0-alpha.821.0.0-alpha.83
uv0.10.00.10.4
kafka4.1.14.2.0
npgsqlrest3.7.03.10.0
postgrest14.414.5
caddy2.10.22.11.1
rclone1.73.01.73.1
pev21.20.11.20.2
genai-toolbox0.25.00.27.0
opencode1.1.591.2.15
claude2.1.372.1.59
codex0.104.00.105.0
code1.109.21.109.4
code-server4.108.24.109.2
nodejs24.13.124.14.0
pig1.1.21.3.0
stalwart-0.15.5
maddy-0.8.2

API Changes

  • pg_mode now includes agens and pgedge.
  • mssql defaults are updated to pg_version: 17 and pg_packages: [babelfish, pgsql-common, sqlcmd].
  • Kernel/package alias mappings are updated in pg_home_map and package_map (Babelfish, OpenHalo, IvorySQL, Cloudberry, pgEdge family).
  • redis_fs_main now defaults to /data/redis, with deployment guardrails and backward-compatible cleanup behavior.
  • configure output path handling and region detection logic are updated, with offline fallback warnings and unified SSH probe timeouts.
  • grafana.ini.j2 is updated for Grafana 12.4 config changes and deprecations.

Compatibility Notes

  • If existing Redis configs still use redis_fs_main: /data, migrate to /data/redis before deployment.
  • Grafana 12.4 changes data link merge behavior. This release moves key links into field overrides; review custom dashboards accordingly.

26 commits, 122 files changed, +2,116 / -2,215 lines (v4.1.0..v4.2.0, 2026-02-15 ~ 2026-02-28)

Checksums

24a90427a7e7351ca1a43a7d53289970  pigsty-v4.2.0.tgz
d980edf5eeb0419d4f1aa7feb0100e14  pigsty-pkg-v4.2.0.d12.aarch64.tgz
24bc237d841457fbdcc899e1d0a3f87e  pigsty-pkg-v4.2.0.d12.x86_64.tgz
e395b38685e2ecbe9c3a2850876d9b7b  pigsty-pkg-v4.2.0.d13.aarch64.tgz
c5c8776f9bead9f29528b26058801f83  pigsty-pkg-v4.2.0.d13.x86_64.tgz
28ea40434bd06135fc8adc0df1c8407d  pigsty-pkg-v4.2.0.el10.aarch64.tgz
58ad715ac20dc1717d1687daecfcf625  pigsty-pkg-v4.2.0.el10.x86_64.tgz
008f955439ea311581dd0ebcf5b8bd34  pigsty-pkg-v4.2.0.el8.aarch64.tgz
2acfd127a517b09f07540f808fe9547a  pigsty-pkg-v4.2.0.el8.x86_64.tgz
58e62a92f35291a40e3f05839a1b6bc4  pigsty-pkg-v4.2.0.el9.aarch64.tgz
d311bfdf5d5f60df5fe6cb3d4ced4f9c  pigsty-pkg-v4.2.0.el9.x86_64.tgz
c98972fe9226657ac1faa7b72a22498b  pigsty-pkg-v4.2.0.u22.aarch64.tgz
44a174ee9ba030ac1ea386cf0b85f6e7  pigsty-pkg-v4.2.0.u22.x86_64.tgz
143e404f4681c7d0bbd78ef7982cd652  pigsty-pkg-v4.2.0.u24.aarch64.tgz
00dfa86f477f3adff984906211ab3190  pigsty-pkg-v4.2.0.u24.x86_64.tgz

v4.1.0

curl https://pigsty.io/get | bash -s v4.1.0

72 commits, 252 files changed, +5,744 / -5,015 lines (v4.0.0..v4.1.0, 2026-02-02 ~ 2026-02-13)

Highlights

  • PostgreSQL minor update: 18.2, 17.8, 16.12, 15.16, 14.21.
  • Default EL minors updated to 9.7 / 10.1, Debian minors updated to 12.13 / 13.3.
  • Added 7 new extensions, bringing total support to 451 extensions.
  • pig moved from a traditional script interface to an Agent-Native CLI (1.0.0 -> 1.1.0), with explicit context and JSON/YAML output.
  • pig now provides unified major/minor upgrade workflows for PostgreSQL and OS lifecycle updates.
  • pg_exporter upgraded to v1.2.0 (1.1.2 -> 1.2.0), with PG17/18 metric pipeline and unit fixes.
  • Default firewall security policy updated: node_firewall_mode now defaults to zone, and node_firewall_public_port default changed from [22,80,443,5432] to [22,80,443].
  • Focused PGSQL/PGCAT Grafana usability fixes: dynamic datasource $dsn, schema-level drilldown, age metrics, link mapping consistency.
  • Added one-click Mattermost application template, including database/storage/portal and optional PGFS/JuiceFS options.
  • Refactored infra-rm uninstall flow with segmented deregister cleanup for Victoria targets, Grafana datasources, and Vector logs.
  • Optimized default PostgreSQL autovacuum thresholds to reduce excessive vacuum/analyze on small tables.
  • Fixed FD limit chain: added fs.nr_open=8M and unified LimitNOFILE=8M to avoid startup failures from systemd/setrlimit.
  • Updated VIBE defaults: Jupyter disabled by default; Claude Code managed via npm package.

Version Updates

  • Pigsty version: v4.0.0 -> v4.1.0
  • pig CLI: 1.0.0 -> 1.1.0 (Agent-Native + major/minor upgrade support)
  • pg_exporter: 1.1.2 -> 1.2.0
  • Default EL minors: 9.6/10.0 -> 9.7/10.1
  • Default Debian minors: 12.12/13.1 -> 12.13/13.3

Extension Updates

  • RPM Changelog 2026-02-12
  • DEB Changelog 2026-02-12
  • timescaledb 2.24.0 -> 2.25.0
  • pg_search 0.21.4 -> 0.21.7
  • pgmq 1.9.0 -> 1.10.0
  • pg_textsearch 0.4.0 -> 0.5.0
  • pljs 1.0.4 -> 1.0.5
  • pg_track_optimizer 0.9.1 (new)
  • nominatim_fdw 1.1.0 (new)
  • pg_utl_smtp 1.0.0 (new)
  • pg_strict 1.0.2 (new)
  • pgmb 1.0.0 (new)
  • pg_pwhash (new support)
  • informix_fdw (new support)

INFRA Component Versions

Infra Changelog 2026-02-12

PackageVersionPackageVersion
victoria-metrics1.135.0victoria-logs1.45.0
vector0.53.0grafana12.3.2
alertmanager0.31.1etcd3.6.7
duckdb1.4.4pg_exporter1.2.0
pig1.1.0claude2.1.37
opencode1.1.59uv0.10.0
code-server4.108.2caddy2.10.2
hugo0.155.2cloudflared2026.2.0
headscale0.28.0

API Changes

  • Corrected template guard for io_method / io_workers from pg_version >= 17 to pg_version >= 18.
  • Fixed PG18 guards for idle_replication_slot_timeout / initdb --no-data-checksums.
  • Broadened maintenance_io_concurrency effective range to PG13+.
  • Raised autovacuum_vacuum_threshold: oltp/crit/tiny from 50 to 500, olap to 1000.
  • Raised autovacuum_analyze_threshold: oltp/crit/tiny from 50 to 250, olap to 500.
  • Increased default checkpoint_completion_target from 0.90 to 0.95.
  • Added fs.nr_open=8388608 in node tuned templates and aligned fs.file-max / fs.nr_open / LimitNOFILE.
  • Changed postgres/patroni/minio systemd LimitNOFILE from 16777216 to 8388608.
  • Added fs.nr_open: 8388608 into default node_sysctl_params.
  • Changed node_firewall_mode default from none to zone: firewall enabled by default, intranet trusted, and only node_firewall_public_port exposed publicly; set none for fully self-managed firewall.
  • Changed node_firewall_public_port default from [22,80,443,5432] to [22,80,443]; add 5432 explicitly only when public DB access is required. Firewall rules are add-only, so existing nodes that already exposed 5432 must remove it manually. Single-node experience templates (such as meta / vibe) explicitly override and keep 5432 for remote usage.
  • Added bin/validate checks for pg_databases[*].parameters and pg_hba_rules[*].order; fixed HBA validation not returning failure properly.
  • Added segmented tags in infra-rm.yml: deregister, config, env, etc.
  • Updated VIBE defaults: jupyter_enabled=false, npm_packages include @anthropic-ai/claude-code and happy-coder, plus CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1.
  • PgBouncer alias cleanup: pool_size_reserve -> pool_reserve, pool_max_db_conn -> pool_connlimit.

Compatibility Fixes (Deduplicated)

  • Note: repeated regressions/re-fixes of the same issue are counted once and merged by problem domain below.
  • Fixed Redis replicaof empty-guard logic and systemd stop behavior.
  • Fixed schema/table/sequence qualification, identifier quoting, and logging format safety in pg_migration.
  • Fixed restart targets and variable usage in pgsql role handlers.
  • Fixed blackbox config filename cleanup item and pgAdmin pgpass file format.
  • Made pg_exporter startup non-blocking to avoid slowing main flow when exporter fails.
  • Simplified VIP CIDR parsing: default mask 24 when omitted.
  • Increased MinIO health-check retries from 3 to 5.
  • Switched node hostname setup to Ansible hostname module instead of shell calls.
  • Fixed .env format for app/electric and app/pg_exporter to standard KEY=VALUE.
  • Fixed pg_crontab syntax error in pigsty.yml.
  • Updated ETCD docs to clarify default TLS vs optional mTLS semantics.
  • Fixed repo-add argument passing, Debian CN mirror component compatibility, and bin/psql.py Python 3 compatibility.
  • Hardened redis-exporter credential file permissions.
  • pgsql-user.yml now masks credential logs (no_log) on sensitive steps.
  • Fixed gate conditions when pg_monitor registers Victoria targets.
  • Changed pg_remove backup cleanup to cluster-level directory to avoid deleting other cluster backups.

Commit List (v4.0.0..v4.1.0, 72 commits, 2026-02-02 ~ 2026-02-13)

7410de401 v4.1.0 release
fa31213ce conf(node): default firewall to zone with single-node 5432 override
bb8382c58 update default extension list to 451
770d01959 hide user credential in pgsql-user playbook
7219a896c pg_monitor: fix victoria registration gate conditions
084c98432 remove one cluster in backup dir during pg_remove
7005617f1 pgsql: drop legacy pgbouncer pool parameter aliases
f8165a886 docs(roles): fix typos and align juice role documentation
06a589218 chore(meta): normalize platform versions for current lint schema
e0a208248 fix(roles): harden redis exporter file permissions
fd0469881 terraform/vagrant: parameterize aliyun region/zone, fix vagrant scripts
74c59aabe grafana: fix dashboard links, descriptions, and overrides
443e58724 conf: clean legacy params and fix template references
536c4b39d adjust grafana dashboard dead links
f3b9866ce grafana(pgsql): fix panel typos and title consistency
bcb69be11 grafana(pgsql): fix drilldown links and variable mappings
1ce4374a1 grafana: fill pglog panel titles and normalize wording
2d127f9f4 grafana: fix minio traffic metrics and pigsty dashboard links
9d3ca0118 grafana: align victoria instance dashboards with query scope
55bc61622 grafana: fix infra dashboard copy, links, and table semantics
607b75535 grafana(node): fix panel drilldown links and clean dashboard metadata
1321de532 grafana(redis): fix dashboard links and blocked-clients panel semantics
91e0c8437 fix(grafana): correct Redis alert drill-down dashboard links
0fde78c02 fix(tooling): improve Python3 compatibility and enforce vagrant scale lower bound
fa3454a52 fix(bootstrap): use Debian-compatible components for CN apt mirror
36c95c749 fix(cli): restore repo-add execution and HBA validation failure propagation
797385929 add macbook local vagrant image override
f9c928e32 fix(grafana): restore reverted dashboard bugfixes
c11af8b6a Bump version to v4.1.0
307a236ba update extension list
f17024807 override el9/u24 vagrant box for convient testing
c2ada1283 terraform: bump Aliyun Debian images to 12.13/13.3
25bd8210f fix(node): add daemon_reload to systemd tasks for keepalived, chronyd, and cron
6f2576fd0 fix(node): set default fs.nr_open via node_sysctl_params
43a71245e add pg_bgwriter_buffers_backend for pg 17-
da832a47b fix(monitor): keep checkpointer metrics for checkpoint stats
90434ca8a fix(monitor): add pg_bgwriter fallback for checkpointer metrics
e2d75e787 fix(monitor): use pg_checkpointer metrics for checkpoint stats
a0b7474f8 fix grafana dashboard metrics and lengend
27ddacbc6 vagrant: refresh box selector and OS shortcuts
26e108788 fix(monitor): correct unit for time metrics scaled by pg_exporter
ee90044b5 fix(pgsql): correct min_parallel scan size params in oltp/crit templates
d439464b2 pgsql: fix pg_version guards for PG18-only settings
26320f120 docs: recommend RockyLinux 10.1
1e9b9f33a terraform: bump Aliyun Rocky images to 9.7/10.1
d6e9c7122 monitor: optimize table/index bloat estimators
42d45d32e fix(grafana): align panel semantics across node/infra/redis
3972d2c45 fix(grafana/pgsql): align dashboard semantics for query monitoring
cb52375ac bump checkpoint_completion_target from 0.90 to 0.95
13115a95d fix legend in pgsql-persist checkpoint panel
102cd2edb fix(pg_migration): make template logging format-safe
c402f0e6d fix: correct io_method/io_workers version guard from PG17 to PG18
3bf676546 vibe: disable jupyter by default and install claude-code via npm_packages
613c4efa9 fix: set fs.nr_open in tuned profiles and reduce LimitNOFILE to 8M
07e499d4d new app conf template matter most
4cc68ed61 Refine infra removal playbook
7cfb98f69 fix: app docker .env file format
9b36b1875 Fix config templates and validation
318d85e6e Simplify VIP parsing and make pg_exporter non-blocking
571cd9e70 Use hostname module for nodename
de98f073c Fix blackbox config filename and pgpass format
4bff01100 Fix redis replicaof guard and systemd stop
38445b68d minio: increase health check retries
c99854969 docs(etcd): clarify TLS vs mTLS
41229124a fix pgsql roles typo
e575d17c6 fix pg_migration scripts to use fully qualified identifiers
ec4207202 fix pgsql-schema broken links
a237e6c99 tune autovacuum threshold to reduce small table vacuum frequency
e80754760 fix pgcat-database links to pgcat-table https://github.com/pgsty/pigsty/issues/690
0060f5346 fix pgsql-database / pgsql-databases age metric fix https://github.com/pgsty/pigsty/issues/695
43cdf72bc fix pigsty.yml typo
0d9db7b08 fix: update datasource to $dsn - fix https://github.com/pgsty/pigsty/issues/692#issuecomment-3835461620

Thanks

  • Thanks to @l2dy for many valuable suggestions and issues.

Checksums

8bc75e8df0e3830931f2ddab71b89630  pigsty-v4.1.0.tgz
da10de99d819421630f430d01bc9de62  pigsty-pkg-v4.1.0.d12.aarch64.tgz
e1f2ed2da0d6b8c360f9fa2faaa7e175  pigsty-pkg-v4.1.0.d12.x86_64.tgz
382bb38a81c138b1b3e7c194211c2138  pigsty-pkg-v4.1.0.d13.aarch64.tgz
13ceaa728901cc4202687f03d25f1479  pigsty-pkg-v4.1.0.d13.x86_64.tgz
92d061de4d495d05d42f91e4283e7502  pigsty-pkg-v4.1.0.el10.aarch64.tgz
be629ea91adf86bbd7e1c59b659d0069  pigsty-pkg-v4.1.0.el10.x86_64.tgz
c14be706119ba33dd06c71dda6c02298  pigsty-pkg-v4.1.0.el8.aarch64.tgz
0c8b6952ffc00e3b169896129ea39184  pigsty-pkg-v4.1.0.el8.x86_64.tgz
cfcc63b9ecc525165674f58f9365aa19  pigsty-pkg-v4.1.0.el9.aarch64.tgz
34f733080bfa9c8515d1573c35f3e870  pigsty-pkg-v4.1.0.el9.x86_64.tgz
ad52ce9bf25e4d834e55873b3f9ada51  pigsty-pkg-v4.1.0.u22.aarch64.tgz
300b2185c61a03ea7733248e526f3342  pigsty-pkg-v4.1.0.u22.x86_64.tgz
2e561e6ae9abb14796872059d2f694a8  pigsty-pkg-v4.1.0.u24.aarch64.tgz
c462bb4cb2359e771ffcad006888fbd4  pigsty-pkg-v4.1.0.u24.x86_64.tgz

v4.0.0

curl https://pigsty.io/get | bash -s v4.0.0

318 commits, 604 files changed, +118,655 / -327,552 lines

Highlights

  • Observability Revolution: Prometheus → VictoriaMetrics (10x perf), Loki+Promtail → VictoriaLogs+Vector
  • Security Hardening: Auto-generated passwords, etcd RBAC, firewall/SELinux modes, permission tightening, Nginx Basic Auth
  • Docker Support: Run Pigsty in Docker containers with full systemd support (macOS & Linux)
  • New Module: JUICE - Mount PostgreSQL as filesystem with PITR recovery capability
  • New Module: VIBE - AI coding sandbox with Claude Code, JupyterLab, VS Code Server, Node.js
  • Database Management: pg_databases state (create/absent/recreate), instant clone with strategy
  • PITR & Fork: /pg/bin/pg-fork for instant CoW cloning, enhanced pg-pitr with pre-backup
  • HA Enhancement: pg_rto_plan with 4 RTO presets (fast/norm/safe/wide), pg_crontab scheduled tasks
  • Multi-Cloud Terraform: AWS, Azure, GCP, Hetzner, DigitalOcean, Linode, Vultr, TencentCloud templates
  • License Change: AGPL-3.0 → Apache-2.0

Infra Software Versions - MinIO now uses pgsty/minio fork RPM/DEB.

PackageVersionPackageVersion
victoria-metrics1.134.0victoria-logs1.43.1
vector0.52.0grafana12.3.1
alertmanager0.30.1etcd3.6.7
duckdb1.4.4pg_exporter1.1.2
pgbackrest_exporter0.22.0blackbox_exporter0.28.0
node_exporter1.10.2minio20251203
pig1.0.0claude2.1.19
opencode1.1.34uv0.9.26
asciinema3.1.0prometheus3.9.1
pushgateway1.11.2juicefs1.4.0
code-server4.100.2caddy2.10.2
hugo0.154.5cloudflared2026.1.1
headscale0.27.1

New Modules

  • JUICE Module: JuiceFS distributed filesystem using PostgreSQL as metadata engine, supports PITR recovery for filesystem. Multiple storage backends (PG large objects, MinIO, S3), multi-instance deployment with Prometheus metrics, new node-juice dashboard.
  • VIBE Module: AI coding sandbox with Code-Server (VS Code in browser), JupyterLab (interactive computing), Node.js (JavaScript runtime), Claude Code (AI coding assistant with OpenTelemetry observability). New claude-code dashboard for usage monitoring.

PostgreSQL Extension Updates

Major extensions add PG 18 support: age, citus, documentdb, pg_search, timescaledb, pg_bulkload, rum, etc.

New: pg_textsearch 0.4.0, pg_clickhouse 0.1.3, pg_ai_query 0.1.1, etcd_fdw, pg_ttl_index 0.1.0, pljs 1.0.4, pg_retry 1.0.0, pg_weighted_statistics 1.0.0, pg_enigma 0.5.0, pglinter 1.0.1, documentdb_extended_rum 0.109, mobilitydb_datagen 1.3.0

Updated: timescaledb 2.24.0, pg_search 0.21.4, citus 14.0.0, documentdb 0.109, age 1.7.0, pg_duckdb 1.1.1, vchord 1.0.0, vchord_bm25 0.3.0, pg_biscuit 2.2.2, pg_anon 2.5.1, wrappers 0.5.7, pg_vectorize 0.26.0, pg_session_jwt 0.4.0, pg_partman 5.4.0, pgmq 1.9.0, pg_bulkload 3.1.23, pg_timeseries 0.2.0, pg_convert 0.1.0, pgBackRest 2.58

Breaking Changes

BeforeAfter
PrometheusVictoriaMetrics
Loki + PromtailVictoriaLogs + Vector
node_disable_firewallnode_firewall_mode
node_disable_selinuxnode_selinux_mode
pg_pwd_encremoved (always scram-sha-256)
infra_pip_packagesnode_pip_packages
grafana_clean defaulttrue → false
install.ymlrenamed to deploy.yml

Observability

  • VictoriaMetrics replaces Prometheus — several times the performance with a fraction of the resources
  • VictoriaLogs + Vector replaces Promtail + Loki for log collection
  • Unified log format for all components, PG logs use UTC timestamp (log_timezone)
  • PostgreSQL log rotation changed to weekly truncated rotation mode
  • Added Vector parsing configs for Nginx/Syslog/PG CSV/Pgbackrest/Grafana/Redis/etcd/MinIO logs
  • Datasource registration now runs on all Infra nodes, Victoria datasources auto-registered in Grafana
  • New grafana_pgurl parameter for using PG as Grafana backend storage
  • New grafana_view_password parameter for Grafana Meta datasource password
  • pg_exporter updated to 1.1.2 with new pg_timeline collector and numerous fixes
  • New dashboards: node-vector, node-juice, claude-code

Interface Improvements

  • install.yml playbook renamed to deploy.yml, new vibe.yml playbook for VIBE module
  • pg_databases: added state field (create/absent/recreate), strategy for cloning, newer locale params support
  • pg_users: added admin parameter with ADMIN OPTION, set and inherit options
  • pg_hba: support order field for priority, IPv6 localhost access
  • New node_crontab auto-restores original crontab on node-rm

Parameter Optimization

  • pg_io_method: auto, sync, worker, io_uring options, default worker
  • pg_rto_plan: RTO presets (fast/norm/safe/wide) integrating Patroni & HAProxy config
  • pg_crontab: scheduled tasks for postgres dbsu
  • idle_replication_slot_timeout: default 7d, crit template 3d
  • file_copy_method: set to clone for PG18 instant database cloning
  • Crit template enables Patroni strict sync mode
  • PITR default archive_mode changed to preserve

Architecture Improvements

  • Fixed /infra symlink pointing to /data/infra on Infra nodes
  • Local repo at /data/nginx/pigsty, /www symlinks to /data/nginx
  • New scripts: /pg/bin/pg-fork (CoW cloning), /pg/bin/pg-drop-role, bin/pgsql-ext
  • Enhanced /pg/bin/pg-pitr for instance-level PITR with pre-backup
  • UV Python manager moved from infra to node module with node_uv_env parameter
  • Terraform templates: AWS, Azure, GCP, Hetzner, DigitalOcean, Linode, Vultr, TencentCloud
  • Simu template simplified from 36 to 20 nodes, new 10-node and Citus templates

Security Improvements

  • configure -g auto-generates strong random passwords
  • Replaced node_disable_firewall with node_firewall_mode (off/none/zone)
  • Replaced node_disable_selinux with node_selinux_mode (disabled/permissive/enforcing)
  • Nginx Basic Auth support for optional HTTP authentication
  • Enabled etcd RBAC, each cluster can only manage its own PG cluster
  • etcd root password stored in /etc/etcd/etcd.pass, admin-readable only
  • New node_admin_sudo parameter for admin sudo mode (all/nopass)
  • Fixed ownca certificate validity for Chrome recognition

Bug Fixes

  • Fixed ownca certificate validity for Chrome compatibility
  • Fixed Vector 0.52 syslog_raw parsing issue
  • Fixed pg_pitr multiple replica clonefrom timing issues
  • Fixed Ansible SELinux race condition in dnsmasq
  • Fixed EL9 aarch64 patroni & llvmjit issues
  • Fixed pgbouncer pid path (/run/postgresql)
  • Fixed HAProxy service template variable path
  • Fixed MinIO reload handler ineffective
  • Fixed vmetrics_port default value to 8428
  • Fixed pg-failover-callback for all Patroni callback events

New Parameters

ParameterTypeDefaultDescription
node_firewall_modeenumnone (v4.0)Firewall mode: off/none/zone (default is zone since v4.1)
node_selinux_modeenumpermissiveSELinux mode
node_admin_sudoenumnopassAdmin sudo privilege level
pg_io_methodenumworkerI/O method: auto/sync/worker/io_uring
pg_rto_plandict-RTO presets: fast/norm/safe/wide
pg_crontablist[]postgres dbsu scheduled tasks
grafana_view_passwordstringDBUser.ViewerGrafana Meta datasource password
juice_cachepath/data/juiceJuiceFS cache directory
juice_instancesdict{}JuiceFS instance definitions
vibe_datapath/fsVIBE workspace directory
code_enabledbooltrueEnable Code-Server
code_passwordstringVibe.CodingCode-Server password
jupyter_enabledbooltrueEnable JupyterLab
jupyter_passwordstringVibe.CodingJupyterLab access token
claude_enabledbooltrueEnable Claude Code configuration
nodejs_enabledbooltrueEnable Node.js installation
nodejs_registrystring''npm registry, auto china mirror
node_uv_envpath/data/venvNode UV venv path, empty to skip
node_pip_packagesstring''pip packages for UV venv

Removed Parameters: node_disable_firewall, node_disable_selinux, infra_pip_packages, pg_pwd_enc, pgbackrest_clean, code_home, jupyter_home

Checksums

bc48405075b3ec6a85fc2c99a1f77650  pigsty-v4.0.0.tgz
db9797c3c8ae21320b76a442c1135c7b  pigsty-pkg-v4.0.0.d12.aarch64.tgz
1eed26eee42066ca71b9aecbf2ca1237  pigsty-pkg-v4.0.0.d12.x86_64.tgz
03540e41f575d6c3a7c63d1d30276d49  pigsty-pkg-v4.0.0.d13.aarch64.tgz
36a6ee284c0dd6d9f7d823c44280b88f  pigsty-pkg-v4.0.0.d13.x86_64.tgz
f2b6ec49d02916944b74014505d05258  pigsty-pkg-v4.0.0.el10.aarch64.tgz
73f64c349366fe23c022f81fe305d6da  pigsty-pkg-v4.0.0.el10.x86_64.tgz
287f767fbb66a9aaca9f0f22e4f20491  pigsty-pkg-v4.0.0.el8.aarch64.tgz
c0886aab454bd86245f3869ef2ab4451  pigsty-pkg-v4.0.0.el8.x86_64.tgz
094ab31bcf4a3cedbd8091bc0f3ba44c  pigsty-pkg-v4.0.0.el9.aarch64.tgz
235ccba44891b6474a76a81750712544  pigsty-pkg-v4.0.0.el9.x86_64.tgz
f2791c96db4cc17a8a4008fc8d9ad310  pigsty-pkg-v4.0.0.u22.aarch64.tgz
3099c4453eef03b766d68e04b8d5e483  pigsty-pkg-v4.0.0.u22.x86_64.tgz
49a93c2158434f1adf0d9f5bcbbb1ca5  pigsty-pkg-v4.0.0.u24.aarch64.tgz
4acaa5aeb39c6e4e23d781d37318d49b  pigsty-pkg-v4.0.0.u24.x86_64.tgz

v3.7.0

Highlights

  • PostgreSQL 18 Deep Support: Now the default major PG version, with full extension readiness!
  • Expanded OS Support: Added EL10 and Debian 13, bringing the total supported operating systems to 14.
  • Extension Growth: The PostgreSQL extension library now includes 437 entries.
  • Ansible 2.19 Compatibility: Full support for Ansible 2.19 following its breaking changes.
  • Kernel Updates: Latest versions for Supabase, PolarDB, IvorySQL, and Percona kernels.
  • Optimized Tuning: Refined logic for default PG parameters to maximize resource utilization.
  • PGEXT.CLOUD: Dedicated extension website open-sourced under Apache-2.0 license

Version Updates

  • PostgreSQL 18.1, 17.7, 16.11, 15.15, 14.20, 13.23
  • Patroni 4.1.0
  • Pgbouncer 1.25.0
  • pg_exporter 1.0.3
  • pgbackrest 2.57.0
  • Supabase 2025-11
  • PolarDB 15.15.5.0
  • FerretDB 2.7.0
  • DuckDB 1.4.2
  • Etcd 3.6.6
  • pig 0.7.4

For detailed version changes, please refer to:

API Changes

  • Implemented a refined optimization strategy for parallel execution parameters. See Tuning Guide.
  • The citus extension is no longer installed by default in rich and full templates (PG 18 support pending).
  • Added duckdb extension stubs to PostgreSQL parameter templates.
  • Capped min_wal_size, max_wal_size, and max_slot_wal_keep_size at 200 GB, 2000 GB, and 3000 GB, respectively.
  • Capped temp_file_limit at 200 GB (2 TB for OLAP workloads).
  • Increased the default connection count for the connection pool.
  • Added prometheus_port (default: 9058) to avoid conflicts with the EL10 RHEL Web Console port.
  • Changed alertmanager_port default to 9059 to avoid potential conflicts with Kafka SSL ports.
  • Added a pg_pre subtask to pg_pkg: removes conflicting LLVM packages (bpftool, python3-perf) on EL9+ prior to PG installation.
  • Added the llvm module to the default repository definition for Debian/Ubuntu.
  • Fixed package removal logic in infra-rm.yml.

Compatibility Fixes

  • Ubuntu/Debian CA Trust: Fixed incorrect warning return codes when trusting Certificate Authorities.
  • Ansible 2.19 Support: Resolved numerous compatibility issues introduced by Ansible 2.19 to ensure stability across versions:
    • Added explicit int type casting for sequence variables.
    • Migrated with_items syntax to loop.
    • Nested key exchange variables in lists to prevent character iteration on strings in newer versions.
    • Explicitly cast range usage to list.
    • Renamed reserved variables such as name and port.
    • Replaced play_hosts with ansible_play_hosts.
    • Added string casting for specific variables to prevent runtime errors.
  • EL10 Adaptation:
    • Fixed missing ansible-collection-community-crypto preventing key generation.
    • Fixed missing ansible logic packages.
    • Removed modulemd_tools, flamegraph, and timescaledb-tool.
    • Replaced java-17-openjdk with java-21-openjdk.
    • Resolved aarch64 YUM repository naming issues.
  • Debian 13 Adaptation:
    • Replaced dnsutils with bind9-dnsutils.
  • Ubuntu 24 Fixes:
    • Temporarily removed tcpdump due to upstream dependency crashes.

Checksums

e00d0c2ac45e9eff1cc77927f9cd09df  pigsty-v3.7.0.tgz
987529769d85a3a01776caefefa93ecb  pigsty-pkg-v3.7.0.d12.aarch64.tgz
2d8272493784ae35abeac84568950623  pigsty-pkg-v3.7.0.d12.x86_64.tgz
090cc2531dcc25db3302f35cb3076dfa  pigsty-pkg-v3.7.0.d13.x86_64.tgz
ddc54a9c4a585da323c60736b8560f55  pigsty-pkg-v3.7.0.el10.aarch64.tgz
d376e75c490e8f326ea0f0fbb4a8fd9b  pigsty-pkg-v3.7.0.el10.x86_64.tgz
8c2deeba1e1d09ef3d46d77a99494e71  pigsty-pkg-v3.7.0.el8.aarch64.tgz
9795e059bd884b9d1b2208011abe43cd  pigsty-pkg-v3.7.0.el8.x86_64.tgz
08b860155d6764ae817ed25f2fcf9e5b  pigsty-pkg-v3.7.0.el9.aarch64.tgz
1ac430768e488a449d350ce245975baa  pigsty-pkg-v3.7.0.el9.x86_64.tgz
e033aaf23690755848db255904ab3bcd  pigsty-pkg-v3.7.0.u22.aarch64.tgz
cc022ea89181d89d271a9aaabca04165  pigsty-pkg-v3.7.0.u22.x86_64.tgz
0e978598796db3ce96caebd76c76e960  pigsty-pkg-v3.7.0.u24.aarch64.tgz
48223898ace8812cc4ea79cf3178476a  pigsty-pkg-v3.7.0.u24.x86_64.tgz

v3.6.1

curl https://repo.pigsty.io/get | bash -s v3.6.1

Highlights

  • PostgreSQL 17.6, 16.10, 15.14, 14.19, 13.22, and 18 Beta 3 Released!
  • PGDG APT/YUM mirror for Mainland China Users
  • New home website https://pgsty.com
  • Add el10, debian 13 stub, add el10 terraform images

Infra Package Updates

  • Grafana 12.1.0
  • pg_exporter 1.0.2
  • pig 0.6.1
  • vector 0.49.0
  • redis_exporter 1.75.0
  • mongo_exporter 0.47.0
  • victoriametrics 1.123.0
  • victorialogs: 1.28.0
  • grafana-victoriametrics-ds 0.18.3
  • grafana-victorialogs-ds 0.19.3
  • grafana-infinity-ds 3.4.1
  • etcd 3.6.4
  • ferretdb 2.5.0
  • tigerbeetle 0.16.54
  • genai-toolbox 0.12.0

Extension Package Updates

  • pg_search 0.17.3

API Changes

  • remove br_filter from default node_kernel_modules
  • do not use OS minor version dir for pgdg yum repos

Checksums

045977aff647acbfa77f0df32d863739  pigsty-pkg-v3.6.1.d12.aarch64.tgz
636b15c2d87830f2353680732e1af9d2  pigsty-pkg-v3.6.1.d12.x86_64.tgz
700a9f6d0db9c686d371bf1c05b54221  pigsty-pkg-v3.6.1.el8.aarch64.tgz
2aff03f911dd7be363ba38a392b71a16  pigsty-pkg-v3.6.1.el8.x86_64.tgz
ce07261b02b02b36a307dab83e460437  pigsty-pkg-v3.6.1.el9.aarch64.tgz
d598d62a47bbba2e811059a53fe3b2b5  pigsty-pkg-v3.6.1.el9.x86_64.tgz
13fd68752e59f5fd2a9217e5bcad0acd  pigsty-pkg-v3.6.1.u22.aarch64.tgz
c25ccfb98840c01eb7a6e18803de55bb  pigsty-pkg-v3.6.1.u22.x86_64.tgz
0d71e58feebe5299df75610607bf428c  pigsty-pkg-v3.6.1.u24.aarch64.tgz
4fbbab1f8465166f494110c5ec448937  pigsty-pkg-v3.6.1.u24.x86_64.tgz
083d8680fa48e9fec3c3fcf481d25d2f  pigsty-v3.6.1.tgz

v3.6.0

curl https://repo.pigsty.io/get | bash -s v3.6.0

Highlights

  • Brand-new documentation site: https://doc.pgsty.com
  • Added pgsql-pitr playbook and backup/restore tutorial, improved PITR experience
  • Added kernel support: Percona PG TDE (PG17)
  • Optimized self-hosted Supabase experience, updated to the latest version, and fixed issues with the official template
  • Simplified installation steps, online install by default, bootstrap now part of install script

Improvements

  • Refactored ETCD module with dedicated remove playbook and bin utils
  • Refactored MinIO module with plain HTTP mode, better bucket provisioning options.
  • Reorganized and streamlined all configuration templates for easier use
  • Faster Docker Registry mirror for users in mainland China
  • Optimized tuned OS parameter templates for modern hardware and NVMe disks
  • Added extension pgactive for multi-master replication and sub-second failover
  • Adjusted default values for pg_fs_main / pg_fs_backup, simplified file directory structure design

Bug Fixes

  • Fixed pgbouncer configuration file error by @housei-zzy
  • Fixed OrioleDB issues on Debian platform
  • Fixed tuned shm configuration parameter issue
  • Offline packages now use the PGDG source directly, avoiding out-of-sync mirror sites
  • Fix ivorysql libxcrypt dependencies issues
  • Fix Replace the slow and broken epel mirror
  • Fix haproxy_enabled flag not working

Infra Package Updates

Added Victoria Metrics / Victoria Logs related packages

  • genai-toolbox 0.9.0 (new)
  • victoriametrics 1.120.0 -> 1.121.0 (refactor)
  • vmutils 1.121.0 (rename from victoria-metrics-utils)
  • grafana-victoriametrics-ds 0.15.1 -> 0.17.0
  • victorialogs 1.24.0 -> 1.25.1 (refactor)
  • vslogcli 1.24.0 -> 1.25.1
  • vlagent 1.25.1 (new)
  • grafana-victorialogs-ds 0.16.3 -> 0.18.1
  • prometheus 3.4.1 -> 3.5.0
  • grafana 12.0.0 -> 12.0.2
  • vector 0.47.0 -> 0.48.0
  • grafana-infinity-ds 3.2.1 -> 3.3.0
  • keepalived_exporter 1.7.0
  • blackbox_exporter 0.26.0 -> 0.27.0
  • redis_exporter 1.72.1 -> 1.77.0
  • rclone 1.69.3 -> 1.70.3

Database Package Updates

  • PostgreSQL 18 Beta2 update
  • pg_exporter 1.0.1, updated to latest dependencies and provides Docker image
  • pig 0.6.0, updated extension and repository list, with pig install subcommand
  • vip-manager 3.0.0 -> 4.0.0
  • ferretdb 2.2.0 -> 2.3.1
  • dblab 0.32.0 -> 0.33.0
  • duckdb 1.3.1 -> 1.3.2
  • etcd 3.6.1 -> 3.6.3
  • ferretdb 2.2.0 -> 2.4.0
  • juicefs 1.2.3 -> 1.3.0
  • tigerbeetle 0.16.41 -> 0.16.50
  • pev2 1.15.0 -> 1.16.0

Extension Package Updates

  • OrioleDB 1.5 beta12
  • OriolePG 17.11
  • plv8 3.2.3 -> 3.2.4
  • postgresql_anonymizer 2.1.1 -> 2.3.0
  • pgvectorscale 0.7.1 -> 0.8.0
  • wrappers 0.5.0 -> 0.5.3
  • supautils 2.9.1 -> 2.10.0
  • citus 13.0.3 -> 13.1.0
  • timescaledb 2.20.0 -> 2.21.1
  • vchord 0.3.0 -> 0.4.3
  • pgactive 2.1.5 (new)
  • documentdb 0.103.0 -> 0.105.0
  • pg_search 0.17.0

API Changes

  • pg_fs_backup: Renamed to pg_fs_backup, default value /data/backups.
  • pg_rm_bkup: Renamed to pg_rm_backup, default value true.
  • pg_fs_main: Default value adjusted to /data/postgres.
  • nginx_cert_validity: New parameter to control Nginx self-signed certificate validity, default 397d.
  • minio_buckets: Default value adjusted to create three buckets named pgsql, meta, data.
  • minio_users: Removed dba user, added s3user_meta and s3user_data users for meta and data buckets respectively.
  • minio_https: New parameter to allow MinIO to use HTTP mode.
  • minio_provision: New parameter to allow skipping MinIO provisioning stage (skip bucket and user creation)
  • minio_safeguard: New parameter, abort minio-rm.yml when enabled
  • minio_rm_data: New parameter, whether to remove minio data directory during minio-rm.yml
  • minio_rm_pkg: New parameter, whether to uninstall minio package during minio-rm.yml
  • etcd_learner: New parameter to control whether to init etcd instance as learner
  • etcd_rm_data: New parameter, whether to remove etcd data directory during etcd-rm.yml
  • etcd_rm_pkg: New parameter, whether to uninstall etcd package during etcd-rm.yml

Checksums

ab91bc05c54b88c455bf66533c1d8d43  pigsty-v3.6.0.tgz
cea861e2b4ec7ff5318e1b3c30b470cb  pigsty-pkg-v3.6.0.d12.aarch64.tgz
2f253af87e19550057c0e7fca876d37c  pigsty-pkg-v3.6.0.d12.x86_64.tgz
0158145b9bbf0e4a120b8bfa8b44f857  pigsty-pkg-v3.6.0.el8.aarch64.tgz
07330d687d04d26e7d569c8755426c5a  pigsty-pkg-v3.6.0.el8.x86_64.tgz
311df5a342b39e3288ebb8d14d81e0d1  pigsty-pkg-v3.6.0.el9.aarch64.tgz
92aad54cc1822b06d3e04a870ae14e29  pigsty-pkg-v3.6.0.el9.x86_64.tgz
c4fadf1645c8bbe3e83d5a01497fa9ca  pigsty-pkg-v3.6.0.u22.aarch64.tgz
5477ed6be96f156a43acd740df8a9b9b  pigsty-pkg-v3.6.0.u22.x86_64.tgz
196169afc1be02f93fcc599d42d005ca  pigsty-pkg-v3.6.0.u24.aarch64.tgz
dbe5c1e8a242a62fe6f6e1f6e6b6c281  pigsty-pkg-v3.6.0.u24.x86_64.tgz

v3.5.0

Highlights

  • New website: https://pgsty.com
  • PostgreSQL 18 (Beta) support: monitoring via pg_exporter 1.0.0, installer alias via pig 0.4.2, and a pg18 template
  • 421 bundled extensions, now including OrioleDB and OpenHalo kernels on all platforms
  • pig do CLI replaces legacy bin/ scripts
  • Hardening for self-hosted Supabase (replication lag, key distribution, etc.)
  • Code & architecture refactor — slimmer tasks, cleaner defaults for Postgres & PgBouncer
  • Monitoring stack refresh — Grafana 12, pg_exporter 1.0, new panels & plugins
  • Run vagrant on Apple Silicon
curl https://repo.pigsty.io/get | bash -s v3.5.0

Module Changes

  • Add PostgreSQL 18 support
  • PG18 metrics support with pg_exporter 1.0.0+
  • PG18 install support with pig 0.4.1+
  • New config template pg18.yml
  • Refactored pgsql module
  • Split monitoring into a new pg_monitor role; removed clean logic
  • Pruned duplicate tasks, dropped dir/utils block, renamed templates (no .j2)
  • All extensions install in extensions schema (Supabase best-practice)
  • Added SET search_path='' to every monitoring function
  • Tuned PgBouncer defaults (larger pool, cleanup query); new pgbouncer_ignore_param
  • New pg_key task to generate pgsodium master keys
  • Enabled sync_replication_slots by default on PG 17
  • Retagged subtasks for clearer structure
  • Refactored pg_remove module
  • New flags pg_rm_data, pg_rm_bkup, pg_rm_pkg control what gets wiped
  • Clearer role layout & tagging
  • Added new pg_monitor module
  • pgbouncer_exporter no longer shares configuration files with pg_exporter
  • Added monitoring metrics for TimescaleDB and Citus
  • Using pg_exporter 0.9.0 with updated replication slot metrics for PG16/17
  • Using more compact, newly designed collector configuration files
  • Supabase Enhancement (thanks @lawso017 for the contribution)
  • update supabase containers and schemas to the latest version
  • Support pgsodium server key loading
  • fix logflare lag issue with supa-kick crontab
  • add set search_path clause for monitor functions
  • Added new pig do command to CLI, allowing command-line tool to replace Shell scripts in bin/

Infra Package Updates

  • pig 0.4.2
  • duckdb 1.3.0
  • etcd 3.6.0
  • vector 0.47.0
  • minio 20250422221226
  • mcli 20250416181326
  • pev 1.5.0
  • rclone 1.69.3
  • mtail 3.0.8 (new)

Observability Package Updates

  • grafana 12.0.0
  • grafana-victorialogs-ds 0.16.3
  • grafana-victoriametrics-ds 0.15.1
  • grafana-infinity-ds 3.2.1
  • grafana_plugins 12.0.0
  • prometheus 3.4.0
  • pushgateway 1.11.1
  • nginx_exporter 1.4.2
  • pg_exporter 1.0.0
  • pgbackrest_exporter 0.20.0
  • redis_exporter 1.72.1
  • keepalived_exporter 1.6.2
  • victoriametrics 1.117.1
  • victoria_logs 1.22.2

Database Package Updates

  • PostgreSQL 17.5, 16.9, 15.13, 14.18, 13.21
  • PostgreSQL 18beta1 support
  • pgbouncer 1.24.1
  • pgbackrest 2.55
  • pgbadger 13.1

Extension Package Updates

  • spat 0.1.0a4 new extension
  • pgsentinel 1.1.0 new extension
  • pgdd 0.6.0 (pgrx 0.14.1) new extension add back
  • convert 0.0.4 (pgrx 0.14.1) new extension
  • pg_tokenizer.rs 0.1.0 (pgrx 0.13.1)
  • pg_render 0.1.2 (pgrx 0.12.8)
  • pgx_ulid 0.2.0 (pgrx 0.12.7)
  • pg_idkit 0.3.0 (pgrx 0.14.1)
  • pg_ivm 1.11.0
  • orioledb 1.4.0 beta11 rpm & add debian/ubuntu support
  • openhalo 14.10 add debian/ubuntu support
  • omnigres 20250507 (miss on d12/u22)
  • citus 12.0.3
  • timescaledb 2.20.0 (DROP PG14 support)
  • supautils 2.9.2
  • pg_envvar 1.0.1
  • pgcollection 1.0.0
  • aggs_for_vecs 1.4.0
  • pg_tracing 0.1.3
  • pgmq 1.5.1
  • tzf-pg 0.2.0 (pgrx 0.14.1)
  • pg_search 0.15.18 (pgrx 0.14.1)
  • anon 2.1.1 (pgrx 0.14.1)
  • pg_parquet 0.4.0 (0.14.1)
  • pg_cardano 1.0.5 (pgrx 0.12) -> 0.14.1
  • pglite_fusion 0.0.5 (pgrx 0.12.8) -> 14.1
  • vchord_bm25 0.2.1 (pgrx 0.13.1)
  • vchord 0.3.0 (pgrx 0.13.1)
  • pg_vectorize 0.22.1 (pgrx 0.13.1)
  • wrappers 0.4.6 (pgrx 0.12.9)
  • timescaledb-toolkit 1.21.0 (pgrx 0.12.9)
  • pgvectorscale 0.7.1 (pgrx 0.12.9)
  • pg_session_jwt 0.3.1 (pgrx 0.12.6) -> 0.12.9
  • pg_timetable 5.13.0
  • ferretdb 2.2.0
  • documentdb 0.103.0 (+aarch64 support)
  • pgml 2.10.0 (pgrx 0.12.9)
  • sqlite_fdw 2.5.0 (fix pg17 deb)
  • tzf 0.2.2 0.14.1 (rename src)
  • pg_vectorize 0.22.2 (pgrx 0.13.1)
  • wrappers 0.5.0 (pgrx 0.12.9)

Checksums

c7e5ce252ddf848e5f034173e0f29345  pigsty-v3.5.0.tgz
ba31f311a16d615c1ee1083dc5a53566  pigsty-pkg-v3.5.0.d12.aarch64.tgz
3aa5c56c8f0de53303c7100f2b3934f4  pigsty-pkg-v3.5.0.d12.x86_64.tgz
a098cb33822633357e6880eee51affd6  pigsty-pkg-v3.5.0.el8.x86_64.tgz
63723b0aeb4d6c02fff0da2c78e4de31  pigsty-pkg-v3.5.0.el9.aarch64.tgz
eb91c8921d7b8a135d8330c77468bfe7  pigsty-pkg-v3.5.0.el9.x86_64.tgz
87ff25e14dfb9001fe02f1dfbe70ae9e  pigsty-pkg-v3.5.0.u22.x86_64.tgz
18be503856f6b39a59efbd1d0a8556b6  pigsty-pkg-v3.5.0.u24.aarch64.tgz
2bbef6a18cfa99af9cd175ef0adf873c  pigsty-pkg-v3.5.0.u24.x86_64.tgz

v3.4.1

GitHub Release Page: v3.4.1

  • Added support for MySQL wire-compatible PostgreSQL kernel on EL systems: openHalo
  • Added support for OLTP-enhanced PostgreSQL kernel on EL systems: orioledb
  • Optimized pgAdmin 9.2 application template with automatic server list updates and pgpass password population
  • Increased PG default max connections to 250, 500, 1000
  • Removed the mysql_fdw extension with dependency errors from EL8

Infra Updates

  • pig 0.3.4
  • etcd 3.5.21
  • restic 0.18.0
  • ferretdb 2.1.0
  • tigerbeetle 0.16.34
  • pg_exporter 0.8.1
  • node_exporter 1.9.1
  • grafana 11.6.0
  • zfs_exporter 3.8.1
  • mongodb_exporter 0.44.0
  • victoriametrics 1.114.0
  • minio 20250403145628
  • mcli 20250403170756

Extension Update

  • Bump pg_search to 0.15.13
  • Bump citus to 13.0.3
  • Bump timescaledb to 2.19.1
  • Bump pgcollection RPM to 1.0.0
  • Bump pg_vectorize RPM to 0.22.1
  • Bump pglite_fusion RPM to 0.0.4
  • Bump aggs_for_vecs RPM to 1.4.0
  • Bump pg_tracing RPM to 0.1.3
  • Bump pgmq RPM to 1.5.1

Checksums

471c82e5f050510bd3cc04d61f098560  pigsty-v3.4.1.tgz
4ce17cc1b549cf8bd22686646b1c33d2  pigsty-pkg-v3.4.1.d12.aarch64.tgz
c80391c6f93c9f4cad8079698e910972  pigsty-pkg-v3.4.1.d12.x86_64.tgz
811bf89d1087512a4f8801242ca8bed5  pigsty-pkg-v3.4.1.el9.x86_64.tgz
9fe2e6482b14a3e60863eeae64a78945  pigsty-pkg-v3.4.1.u22.x86_64.tgz

v3.4.0

GitHub Release Page: v3.4.0

Introduction Blog: Pigsty v3.4 MySQL Compatibility and Overall Enhancements

New Features

  • Added new pgBackRest backup monitoring metrics and dashboards
  • Enhanced Nginx server configuration options, with support for automated Certbot issuance
  • Now prioritizing PostgreSQL’s built-in C/C.UTF-8 locale settings
  • IvorySQL 4.4 is now fully supported across all platforms (RPM/DEB on x86/ARM)
  • Added new software packages: Juicefs, Restic, TimescaleDB EventStreamer
  • The Apache AGE graph database extension now fully supports PostgreSQL 13–17 on EL
  • Improved the app.yml playbook: launch standard Docker app without extra config
  • Bump Supabase, Dify, and Odoo app templates, bump to their latest versions
  • Add electric app template, local-first PostgreSQL Sync Engine

Infra Packages

  • +restic 0.17.3
  • +juicefs 1.2.3
  • +timescaledb-event-streamer 0.12.0
  • Prometheus 3.2.1
  • AlertManager 0.28.1
  • blackbox_exporter 0.26.0
  • node_exporter 1.9.0
  • mysqld_exporter 0.17.2
  • kafka_exporter 1.9.0
  • redis_exporter 1.69.0
  • pgbackrest_exporter 0.19.0-2
  • DuckDB 1.2.1
  • etcd 3.5.20
  • FerretDB 2.0.0
  • tigerbeetle 0.16.31
  • vector 0.45.0
  • VictoriaMetrics 1.113.0
  • VictoriaLogs 1.17.0
  • rclone 1.69.1
  • pev2 1.14.0
  • grafana-victorialogs-ds 0.16.0
  • grafana-victoriametrics-ds 0.14.0
  • grafana-infinity-ds 3.0.0

PostgreSQL Related

  • Patroni 4.0.5
  • PolarDB 15.12.3.0-e1e6d85b
  • IvorySQL 4.4
  • pgbackrest 2.54.2
  • pev2 1.14
  • Babelfish 13.17

PostgreSQL Extensions

  • pgspider_ext 1.3.0 (new extension)
  • apache age 13–17 el rpm (1.5.0)
  • timescaledb 2.18.2 → 2.19.0
  • citus 13.0.1 → 13.0.2
  • documentdb 1.101-0 → 1.102-0
  • pg_analytics 0.3.4 → 0.3.7
  • pg_search 0.15.2 → 0.15.8
  • pg_ivm 1.9 → 1.10
  • emaj 4.4.0 → 4.6.0
  • pgsql_tweaks 0.10.0 → 0.11.0
  • pgvectorscale 0.4.0 → 0.6.0 (pgrx 0.12.5)
  • pg_session_jwt 0.1.2 → 0.2.0 (pgrx 0.12.6)
  • wrappers 0.4.4 → 0.4.5 (pgrx 0.12.9)
  • pg_parquet 0.2.0 → 0.3.1 (pgrx 0.13.1)
  • vchord 0.2.1 → 0.2.2 (pgrx 0.13.1)
  • pg_tle 1.2.0 → 1.5.0
  • supautils 2.5.0 → 2.6.0
  • sslutils 1.3 → 1.4
  • pg_profile 4.7 → 4.8
  • pg_snakeoil 1.3 → 1.4
  • pg_jsonschema 0.3.2 → 0.3.3
  • pg_incremental 1.1.1 → 1.2.0
  • pg_stat_monitor 2.1.0 → 2.1.1
  • ddl_historization 0.7 → 0.0.7 (bug fix)
  • pg_sqlog 3.1.7 → 1.6 (bug fix)
  • pg_random removed development suffix (bug fix)
  • asn1oid 1.5 → 1.6
  • table_log 0.6.1 → 0.6.4

Interface Changes

  • Added new Docker parameters: docker_data and docker_storage_driver (#521 by @waitingsong)
  • Added new Infra parameter: alertmanager_port, which lets you specify the AlertManager port
  • Added new Infra parameter: certbot_sign, apply for cert during nginx init? (false by default)
  • Added new Infra parameter: certbot_email, specifying the email used when requesting certificates via Certbot
  • Added new Infra parameter: certbot_options, specifying additional parameters for Certbot
  • Updated IvorySQL to place its default binary under /usr/ivory-4 starting in IvorySQL 4.4
  • Changed the default for pg_lc_ctype and other locale-related parameters from en_US.UTF-8 to C
  • For PostgreSQL 17, if using UTF8 encoding with C or C.UTF-8 locales, PostgreSQL’s built-in localization rules now take priority
  • configure automatically detects whether C.utf8 is supported by both the PG version and the environment, and adjusts locale-related options accordingly
  • Set the default IvorySQL binary path to /usr/ivory-4
  • Updated the default value of pg_packages to pgsql-main patroni pgbouncer pgbackrest pg_exporter pgbadger vip-manager
  • Updated the default value of repo_packages to [node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, extra-modules]
  • Removed LANG and LC_ALL environment variable settings from /etc/profile.d/node.sh
  • Now using bento/rockylinux-8 and bento/rockylinux-9 as the Vagrant box images for EL
  • Added a new alias, extra_modules, which includes additional optional modules
  • Updated PostgreSQL aliases: postgresql, pgsql-main, pgsql-core, pgsql-full
  • GitLab repositories are now included among available modules
  • The Docker module has been merged into the Infra module
  • The node.yml playbook now includes a node_pip task to configure a pip mirror on each node
  • The pgsql.yml playbook now includes a pgbackrest_exporter task for collecting backup metrics
  • The Makefile now allows the use of META/PKG environment variables
  • Added /pg/spool directory as temporary storage for pgBackRest
  • Disabled pgBackRest’s link-all option by default
  • Enabled block-level incremental backups for MinIO repositories by default

Bug Fixes

  • Fixed the exit status code in pg-backup (#532 by @waitingsong)
  • In pg-tune-hugepage, restricted PostgreSQL to use only large pages (#527 by @waitingsong)
  • Fixed logic errors in the pg-role task
  • Corrected type conversion for hugepage configuration parameters
  • Fixed default value issues for node_repo_modules in the slim template

Checksums

768bea3bfc5d492f4c033cb019a81d3a  pigsty-v3.4.0.tgz
7c3d47ef488a9c7961ca6579dc9543d6  pigsty-pkg-v3.4.0.d12.aarch64.tgz
b5d76aefb1e1caa7890b3a37f6a14ea5  pigsty-pkg-v3.4.0.d12.x86_64.tgz
42dacf2f544ca9a02148aeea91f3153a  pigsty-pkg-v3.4.0.el8.aarch64.tgz
d0a694f6cd6a7f2111b0971a60c49ad0  pigsty-pkg-v3.4.0.el8.x86_64.tgz
7caa82254c1b0750e89f78a54bf065f8  pigsty-pkg-v3.4.0.el9.aarch64.tgz
8f817e5fad708b20ee217eb2e12b99cb  pigsty-pkg-v3.4.0.el9.x86_64.tgz
8b2fcaa6ef6fd8d2726f6eafbb488aaf  pigsty-pkg-v3.4.0.u22.aarch64.tgz
83291db7871557566ab6524beb792636  pigsty-pkg-v3.4.0.u22.x86_64.tgz
c927238f0343cde82a4a9ab230ecd2ac  pigsty-pkg-v3.4.0.u24.aarch64.tgz
14cbcb90693ed5de8116648a1f2c3e34  pigsty-pkg-v3.4.0.u24.x86_64.tgz

v3.3.0

  • Total available extensions increased to 404!
  • PostgreSQL February Minor Updates: 17.4, 16.8, 15.12, 14.17, 13.20
  • New Feature: app.yml script for auto-installing apps like Odoo, Supabase, Dify.
  • New Feature: Further Nginx configuration customization in infra_portal.
  • New Feature: Added Certbot support for quick free HTTPS certificate requests.
  • New Feature: Pure-text extension list now supported in pg_default_extensions.
  • New Feature: Default repositories now include mongo, redis, groonga, haproxy, etc.
  • New Parameter: node_aliases to add command aliases for Nodes.
  • Fix: Resolved default EPEL repo address issue in Bootstrap script.
  • Improvement: Added Aliyun mirror for Debian Security repository.
  • Improvement: pgBackRest backup support for IvorySQL kernel.
  • Improvement: ARM64 and Debian/Ubuntu support for PolarDB.
  • pg_exporter 0.8.0 now supports new metrics in pgbouncer 1.24.
  • New Feature: Auto-completion for common commands like git, docker, systemctl #506 #524 by @waitingsong.
  • Improvement: Refined ignore_startup_parameters in pgbouncer config template #488 by @waitingsong.
  • New homepage design: Pigsty’s website now features a fresh new look.
  • Extension Directory: Detailed information and download links for RPM/DEB binary packages.
  • Extension Build: pig CLI now auto-sets PostgreSQL extension build environment.

New Extensions

12 new PostgreSQL extensions added, bringing the total to 404 available extensions.

Bump Extension

  • citus 13.0.0 -> 13.0.1
  • pg_duckdb 0.2.0 -> 0.3.1
  • pg_mooncake 0.1.0 -> 0.1.2
  • timescaledb 2.17.2 -> 2.18.2
  • supautils 2.5.0 -> 2.6.0
  • supabase_vault 0.3.1 (become C)
  • VectorChord 0.1.0 -> 0.2.1
  • pg_bulkload 3.1.22 (+pg17)
  • pg_store_plan 1.8 (+pg17)
  • pg_search 0.14 -> 0.15.2
  • pg_analytics 0.3.0 -> 0.3.4
  • pgroonga 3.2.5 -> 4.0.0
  • zhparser 2.2 -> 2.3
  • pg_vectorize 0.20.0 -> 0.21.1
  • pg_net 0.14.0
  • pg_curl 2.4.2
  • table_version 1.10.3 -> 1.11.0
  • pg_duration 1.0.2
  • pg_graphql 1.5.9 -> 1.5.11
  • vchord 0.1.1 -> 0.2.1 ((+13))
  • vchord_bm25 0.1.0 -> 0.1.1
  • pg_mooncake 0.1.1 -> 0.1.2
  • pgddl 0.29
  • pgsql_tweaks 0.11.0

Infra Updates

  • pig 0.1.3 -> 0.3.0
  • pushgateway 1.10.0 -> 1.11.0
  • alertmanager 0.27.0 -> 0.28.0
  • nginx_exporter 1.4.0 -> 1.4.1
  • pgbackrest_exporter 0.18.0 -> 0.19.0
  • redis_exporter 1.66.0 -> 1.67.0
  • mongodb_exporter 0.43.0 -> 0.43.1
  • VictoriaMetrics 1.107.0 -> 1.111.0
  • VictoriaLogs v1.3.2 -> 1.9.1
  • DuckDB 1.1.3 -> 1.2.0
  • Etcd 3.5.17 -> 3.5.18
  • pg_timetable 5.10.0 -> 5.11.0
  • FerretDB 1.24.0 -> 2.0.0-rc
  • tigerbeetle 0.16.13 -> 0.16.27
  • grafana 11.4.0 -> 11.5.2
  • vector 0.43.1 -> 0.44.0
  • minio 20241218131544 -> 20250218162555
  • mcli 20241121172154 -> 20250215103616
  • rclone 1.68.2 -> 1.69.0
  • vray 5.23 -> 5.28

v3.2.2

What’s Changed

  • Bump IvorySQL to 4.2 (PostgreSQL 17.2)
  • Add Arm64 and Debian support for PolarDB kernel
  • Add certbot and certbot-nginx to default infra_packages
  • Increase pgbouncer max_prepared_statements to 256
  • remove pgxxx-citus package alias
  • hide pgxxx-olap category in pg_extensions by default

v3.2.1

Highlights

  • 351 PostgreSQL Extensions, including the powerful postgresql-anonymizer 2.0
  • IvorySQL 4.0 support for EL 8/9
  • Now use the Pigsty compiled Citus, TimescaleDB and pgroonga on all distros
  • Add self-hosting Odoo template and support

Bump software versions

  • pig CLI 0.1.2 self-updating capability
  • prometheus 3.1.0

Add New Extension

  • add pg_anon 2.0.0
  • add omnisketch 1.0.2
  • add ddsketch 1.0.1
  • add pg_duration 1.0.1
  • add ddl_historization 0.0.7
  • add data_historization 1.1.0
  • add schedoc 0.0.1
  • add floatfile 1.3.1
  • add pg_upless 0.0.3
  • add pg_task 1.0.0
  • add pg_readme 0.7.0
  • add vasco 0.1.0
  • add pg_xxhash 0.0.1

Update Extension

  • lower_quantile 1.0.3
  • quantile 1.1.8
  • sequential_uuids 1.0.3
  • pgmq 1.5.0 (subdir)
  • floatvec 1.1.1
  • pg_parquet 0.2.0
  • wrappers 0.4.4
  • pg_later 0.3.0
  • topn fix for deb.arm64
  • add age 17 on debian
  • powa + pg17, 5.0.1
  • h3 + pg17
  • ogr_fdw + pg17
  • age + pg17 1.5 on debian
  • pgtap + pg17 1.3.3
  • repmgr
  • topn + pg17
  • pg_partman 5.2.4
  • credcheck 3.0
  • ogr_fdw 1.1.5
  • ddlx 0.29
  • postgis 3.5.1
  • tdigest 1.4.3
  • pg_repack 1.5.2

v3.2.0

Highlights

  • New CLI: Introducing the pig command-line tool for managing extension plugins.
  • ARM64 Support: 390 extensions are now available for ARM64 across five major distributions.
  • Supabase Update: Latest Supabase Release Week updates are now supported for self-hosting on all distributions.
  • Grafana v11.4: Upgraded Grafana to version 11.4, featuring a new Infinity datasource.

Package Changes

  • New Extensions
  • Added timescaledb, timescaledb-loader, timescaledb-toolkit, and timescaledb-tool to the PIGSTY repository.
  • Added a custom-compiled pg_timescaledb for EL.
  • Added pgroonga, custom-compiled for all EL variants.
  • Added vchord 0.1.0.
  • Added pg_bestmatch.rs 0.0.1.
  • Added pglite_fusion 0.0.3.
  • Added pgpdf 0.1.0.
  • Updated Extensions
  • pgvectorscale: 0.4.0 → 0.5.1
  • pg_parquet: 0.1.0 → 0.1.1
  • pg_polyline: 0.0.1
  • pg_cardano: 1.0.2 → 1.0.3
  • pg_vectorize: 0.20.0
  • pg_duckdb: 0.1.0 → 0.2.0
  • pg_search: 0.13.0 → 0.13.1
  • aggs_for_vecs: 1.3.1 → 1.3.2
  • Infrastructure
  • Added promscale 0.17.0
  • Added grafana-plugins 11.4
  • Added grafana-infinity-plugins
  • Added grafana-victoriametrics-ds
  • Added grafana-victorialogs-ds
  • vip-manager: 2.8.0 → 3.0.0
  • vector: 0.42.0 → 0.43.0
  • grafana: 11.3 → 11.4
  • prometheus: 3.0.0 → 3.0.1 (package name changed from prometheus2 to prometheus)
  • nginx_exporter: 1.3.0 → 1.4.0
  • mongodb_exporter: 0.41.2 → 0.43.0
  • VictoriaMetrics: 1.106.1 → 1.107.0
  • VictoriaLogs: 1.0.0 → 1.3.2
  • pg_timetable: 5.9.0 → 5.10.0
  • tigerbeetle: 0.16.13 → 0.16.17
  • pg_export: 0.7.0 → 0.7.1
  • New Docker App
  • Add mattermost the open-source Slack alternative self-hosting template
  • Bug Fixes
  • Added python3-cdiff for el8.aarch64 to fix missing Patroni dependency.
  • Added timescaledb-tools for el9.aarch64 to fix missing package in official repo.
  • Added pg_filedump for el9.aarch64 to fix missing package in official repo.
  • Removed Extensions
  • pg_mooncake: Removed due to conflicts with pg_duckdb.
  • pg_top: Removed because of repeated version issues and quality concerns.
  • hunspell_pt_pt: Removed because of conflict with official PG dictionary files.
  • pgml: Disabled by default (no longer downloaded or installed).

API Changes

  • repo_url_packages now defaults to an empty array; packages are installed via OS package managers.
  • grafana_plugin_cache is deprecated; Grafana plugins are now installed via OS package managers.
  • grafana_plugin_list is deprecated for the same reason.
  • The 36-node “production” template has been renamed to simu.
  • Auto-generated code under node_id/vars now includes aarch64 support.
  • infra_packages now includes the pig CLI tool.
  • The configure command now updates the version numbers of pgsql-xxx aliases in auto-generated config files.
  • Update terraform templates with Makefile shortcuts and better provision experience

Bug Fix

Checksums

c42da231067f25104b71a065b4a50e68  pigsty-pkg-v3.2.0.d12.aarch64.tgz
ebb818f98f058f932b57d093d310f5c2  pigsty-pkg-v3.2.0.d12.x86_64.tgz
d2b85676235c9b9f2f8a0ad96c5b15fd  pigsty-pkg-v3.2.0.el9.aarch64.tgz
649f79e1d94ec1845931c73f663ae545  pigsty-pkg-v3.2.0.el9.x86_64.tgz
24c0be1d8436f3c64627c12f82665a17  pigsty-pkg-v3.2.0.u22.aarch64.tgz
0b9be0e137661e440cd4f171226d321d  pigsty-pkg-v3.2.0.u22.x86_64.tgz
8fdc6a60820909b0a2464b0e2b90a3a6  pigsty-v3.2.0.tgz

v3.1.0

2024-11-24 : ARM64 & Ubuntu24, PG17 by Default, Better Supabase & MinIO

https://github.com/pgsty/pigsty/releases/tag/v3.1.0


v3.0.4

2024-10-28 : PostgreSQL 17 Extensions, Better self-hosting Supabase

https://github.com/pgsty/pigsty/releases/tag/v3.0.4


v3.0.3

2024-09-27 : PostgreSQL 17, Etcd Enhancement, IvorySQL 3.4, PostGIS 3.5

https://github.com/pgsty/pigsty/releases/tag/v3.0.3


v3.0.2

2024-09-07 : Mini Install, PolarDB 15, Bloat View Update

https://github.com/pgsty/pigsty/releases/tag/v3.0.2


v3.0.1

2024-08-31 : Oracle Compatibility, Patroni 4.0, Routine Bug Fix

https://github.com/pgsty/pigsty/releases/tag/v3.0.1


v3.0.0

2024-08-30 : Extension Exploding & Pluggable Kernels (MSSQL, Oracle)

https://github.com/pgsty/pigsty/releases/tag/v3.0.0


v2.7.0

2024-05-16 : Extension Overwhelming, new docker apps

https://github.com/pgsty/pigsty/releases/tag/v2.7.0


v2.6.0

2024-02-29 : PG 16 as default version, ParadeDB & DuckDB

https://github.com/pgsty/pigsty/releases/tag/v2.6.0


v2.5.1

2023-12-01 : Routine update, pg16 major extensions

https://github.com/pgsty/pigsty/releases/tag/v2.5.1


v2.5.0

2023-10-24 : Ubuntu/Debian Support: bullseye, bookworm, jammy, focal

https://github.com/pgsty/pigsty/releases/tag/v2.5.0


v2.4.1

2023-09-24 : Supabase/PostgresML support, graphql, jwt, pg_net, vault

https://github.com/pgsty/pigsty/releases/tag/v2.4.1


v2.4.0

2023-09-14 : PG16, RDS Monitor, New Extensions

https://github.com/pgsty/pigsty/releases/tag/v2.4.0


v2.3.1

2023-09-01 : PGVector with HNSW, PG16 RC1, Chinese Docs, Bug Fix

https://github.com/pgsty/pigsty/releases/tag/v2.3.1


v2.3.0

2023-08-20 : PGSQL/REDIS Update, NODE VIP, Mongo/FerretDB, MYSQL Stub

https://github.com/pgsty/pigsty/releases/tag/v2.3.0


v2.2.0

2023-08-04 : Dashboard & Provision overhaul, UOS compatibility

https://github.com/pgsty/pigsty/releases/tag/v2.2.0


v2.1.0

2023-06-10 : PostgreSQL 12 ~ 16beta support

https://github.com/pgsty/pigsty/releases/tag/v2.1.0


v2.0.2

2023-03-31 : Add pgvector support and fix MinIO CVE

https://github.com/pgsty/pigsty/releases/tag/v2.0.2


v2.0.1

2023-03-21 : v2 Bug Fix, security enhance and bump grafana version

https://github.com/pgsty/pigsty/releases/tag/v2.0.1


v2.0.0

2023-02-28 : Compatibility Security Maintainability Enhancement

https://github.com/pgsty/pigsty/releases/tag/v2.0.0


v1.5.1

2022-06-18 : Grafana Security Hotfix

https://github.com/pgsty/pigsty/releases/tag/v1.5.1


v1.5.0

2022-05-31 : Docker Applications

https://github.com/pgsty/pigsty/releases/tag/v1.5.0


v1.4.1

2022-04-20 : Bug fix & Full translation of English documents.

https://github.com/pgsty/pigsty/releases/tag/v1.4.1


v1.4.0

2022-03-31 : MatrixDB Support, Separated INFRA, NODES, PGSQL, REDIS

https://github.com/pgsty/pigsty/releases/tag/v1.4.0


v1.3.0

2021-11-30 : PGCAT Overhaul & PGSQL Enhancement & Redis Support Beta

https://github.com/pgsty/pigsty/releases/tag/v1.3.0


v1.2.0

2021-11-03 : Upgrade default Postgres to 14, monitoring existing pg

https://github.com/pgsty/pigsty/releases/tag/v1.2.0


v1.1.0

2021-10-12 : HomePage, JupyterLab, PGWEB, Pev2 & Pgbadger

https://github.com/pgsty/pigsty/releases/tag/v1.1.0


v1.0.0

2021-07-26 : v1 GA, Monitoring System Overhaul

https://github.com/pgsty/pigsty/releases/tag/v1.0.0


v0.9.0

2021-04-04 : Pigsty GUI, CLI, Logging Integration

https://github.com/pgsty/pigsty/releases/tag/v0.9.0


v0.8.0

2021-03-28 : Service Provision

https://github.com/pgsty/pigsty/releases/tag/v0.8.0


v0.7.0

2021-03-01 : Monitor only deployment

https://github.com/pgsty/pigsty/releases/tag/v0.7.0


v0.6.0

2021-02-19 : Architecture Enhancement

https://github.com/pgsty/pigsty/releases/tag/v0.6.0


v0.5.0

2021-01-07 : Database Customize Template

https://github.com/pgsty/pigsty/releases/tag/v0.5.0


v0.4.0

2020-12-14 : PostgreSQL 13 Support, Official Documentation

https://github.com/pgsty/pigsty/releases/tag/v0.4.0


v0.3.0

2020-10-22 : Provisioning Solution GA

https://github.com/pgsty/pigsty/releases/tag/v0.3.0


v0.2.0

2020-07-10 : PGSQL Monitoring v6 GA

https://github.com/pgsty/pigsty/commit/385e33a62a19817e8ba19997260e6b77d99fe2ba


v0.1.0

2020-06-20 : Validation on Testing Environment

https://github.com/pgsty/pigsty/commit/1cf2ea5ee91db071de00ec805032928ff582453b


v0.0.5

2020-08-19 : Offline Installation Mode

https://github.com/pgsty/pigsty/commit/0fe9e829b298fe5e56307de3f78c95071de28245


v0.0.4

2020-07-27 : Refactor playbooks into ansible roles

https://github.com/pgsty/pigsty/commit/90b44259818d2c71e37df5250fe8ed1078a883d0


v0.0.3

2020-06-22 : Interface enhancement

https://github.com/pgsty/pigsty/commit/4c5c68ccd57bc32a9e9c98aa3f264aa19f45c7ee


v0.0.2

2020-04-30 : First Commit

https://github.com/pgsty/pigsty/commit/dd646775624ddb33aef7884f4f030682bdc371f8


v0.0.1

2019-05-15 : POC

https://github.com/Vonng/pg/commit/fa2ade31f8e81093eeba9d966c20120054f0646b


4.13 - Comparison

This article compares Pigsty with similar products and projects, highlighting feature differences.

Comparison with RDS

Pigsty is a local-first RDS alternative released under Apache-2.0, deployable on your own physical/virtual machines or cloud servers.

We’ve chosen Amazon AWS RDS for PostgreSQL (the global market leader) and Alibaba Cloud RDS for PostgreSQL (China’s market leader) as benchmarks for comparison.

Both Aliyun RDS and AWS RDS are closed-source cloud database services, available only through rental models on public clouds. The following cloud-vendor information is a February 2024 archive based on PostgreSQL 16 at that time. The Pigsty column in the Feature Comparison table is maintained against the current release, while the later Key Extensions version table remains a period snapshot.


Feature Comparison

FeaturePigstyAliyun RDSAWS RDS
Major Version Support14 - 1813 - 1813 - 18
Read Replicas Supports unlimited read replicas Standby instances not exposed to users Standby instances not exposed to users
Read/Write Splitting Port-based traffic separation Separate paid component Separate paid component
Fast/Slow Separation Supports offline ETL instances Not available Not available
Cross-Region DR Supports standby clusters Multi-AZ deployment supported Multi-AZ deployment supported
Delayed Replicas Supports delayed instances Not available Not available
Load Balancing HAProxy / LVS Separate paid component Separate paid component
Connection Pool Pgbouncer Separate paid component: RDS Separate paid component: RDS Proxy
High Availability Patroni / etcd Requires HA edition Requires HA edition
Point-in-Time Recovery pgBackRest / Silo Backup supported Backup supported
Metrics Monitoring VictoriaMetrics / Exporter Free basic / Paid advanced Free basic / Paid advanced
Log Collection VictoriaLogs / Vector Basic support Basic support
Visualization Grafana / Echarts Basic monitoring Basic monitoring
Alert Aggregation AlertManager Basic support Basic support

Key Extensions

This is a historical PostgreSQL 16 extension-support snapshot based on information visible on 2024-02-28. Its versions and projects—including pg_analytics, which was later archived and removed from the catalog—are not the current Pigsty v4.5.0 or cloud-provider support matrix. Use the extension catalog for current Pigsty coverage and recheck each provider’s documentation for its current service capabilities.

ExtensionPigsty RDS / PGDG Official RepoAliyun RDSAWS RDS
Install Extensions Free to install Not allowed Not allowed
Geospatial PostGIS 3.4.2 PostGIS 3.3.4 / Ganos 6.1 PostGIS 3.4.1
Point Cloud PG PointCloud 1.2.5 Ganos PointCloud 6.1
Vector Embedding PGVector 0.6.1 / Svector 0.5.6 pase 0.0.1 PGVector 0.6
Machine Learning PostgresML 2.8.1
Time Series TimescaleDB 2.14.2
Horizontal Scaling Citus 12.1
Columnar Storage Hydra 1.1.1
Full Text Search pg_bm25 0.5.6
Graph Database Apache AGE 1.5.0
GraphQL PG GraphQL 1.5.0
OLAP pg_analytics 0.5.6
Message Queue pgq 3.5.0
DuckDB duckdb_fdw 1.1
Fuzzy Tokenization zhparser 1.1 / pg_bigm 1.2 zhparser 1.0 / pg_jieba pg_bigm 1.2
CDC Extraction wal2json 2.5.3 wal2json 2.5
Bloat Management pg_repack 1.5.0 pg_repack 1.4.8 pg_repack 1.5.0
AWS RDS PG Available Extensions

AWS RDS for PostgreSQL 16 available extensions (excluding PG built-in extensions)

namepg16pg15pg14pg13pg12pg11pg10
amcheck1.31.31.31.21.2yes1
auto_explainyesyesyesyesyesyesyes
autoinc1111nullnullnull
bloom1111111
bool_plperl1111nullnullnull
btree_gin1.31.31.31.31.31.31.2
btree_gist1.71.71.61.51.51.51.5
citext1.61.61.61.61.61.51.4
cube1.51.51.51.41.41.41.2
dblink1.21.21.21.21.21.21.2
dict_int1111111
dict_xsyn1111111
earthdistance1.11.11.11.11.11.11.1
fuzzystrmatch1.21.11.11.11.11.11.1
hstore1.81.81.81.71.61.51.4
hstore_plperl1111111
insert_username1111nullnullnull
intagg1.11.11.11.11.11.11.1
intarray1.51.51.51.31.21.21.2
isn1.21.21.21.21.21.21.1
jsonb_plperl11111nullnull
lo1.11.11.11.11.11.11.1
ltree1.21.21.21.21.11.11.1
moddatetime1111nullnullnull
old_snapshot111nullnullnullnull
pageinspect1.121.111.91.81.71.71.6
pg_buffercache1.41.31.31.31.31.31.3
pg_freespacemap1.21.21.21.21.21.21.2
pg_prewarm1.21.21.21.21.21.21.1
pg_stat_statements1.11.11.91.81.71.61.6
pg_trgm1.61.61.61.51.41.41.3
pg_visibility1.21.21.21.21.21.21.2
pg_walinspect1.11nullnullnullnullnull
pgcrypto1.31.31.31.31.31.31.3
pgrowlocks1.21.21.21.21.21.21.2
pgstattuple1.51.51.51.51.51.51.5
plperl1111111
plpgsql1111111
pltcl1111111
postgres_fdw1.11.11.11111
refint1111nullnullnull
seg1.41.41.41.31.31.31.1
sslinfo1.21.21.21.21.21.21.2
tablefunc1111111
tcn1111111
tsm_system_rows1111111.1
tsm_system_time1111111.1
unaccent1.11.11.11.11.11.11.1
uuid-ossp1.11.11.11.11.11.11.1
Aliyun RDS PG Available Extensions

Aliyun RDS for PostgreSQL 16 available extensions (excluding PG built-in extensions)

namepg16pg15pg14pg13pg12pg11pg10description
bloom1111111Provides a bloom filter-based index access method.
btree_gin1.31.31.31.31.31.31.2Provides GIN operator class examples that implement B-tree equivalent behavior for multiple data types and all enum types.
btree_gist1.71.71.61.51.51.51.5Provides GiST operator class examples that implement B-tree equivalent behavior for multiple data types and all enum types.
citext1.61.61.61.61.61.51.4Provides a case-insensitive string type.
cube1.51.51.51.41.41.41.2Provides a data type for representing multi-dimensional cubes.
dblink1.21.21.21.21.21.21.2Cross-database table operations.
dict_int1111111Additional full-text search dictionary template example.
earthdistance1.11.11.11.11.11.11.1Provides two different methods to calculate great circle distances on the Earth’s surface.
fuzzystrmatch1.21.11.11.11.11.11.1Determines similarities and distances between strings.
hstore1.81.81.81.71.61.51.4Stores key-value pairs in a single PostgreSQL value.
intagg1.11.11.11.11.11.11.1Provides an integer aggregator and an enumerator.
intarray1.51.51.51.31.21.21.2Provides some useful functions and operators for manipulating null-free integer arrays.
isn1.21.21.21.21.21.21.1Validates input according to a hard-coded prefix list, also used for concatenating numbers during output.
ltree1.21.21.21.21.11.11.1For representing labels of data stored in a hierarchical tree structure.
pg_buffercache1.41.31.31.31.31.31.3Provides a way to examine the shared buffer cache in real time.
pg_freespacemap1.21.21.21.21.21.21.2Examines the free space map (FSM).
pg_prewarm1.21.21.21.21.21.21.1Provides a convenient way to load data into the OS buffer or PostgreSQL buffer.
pg_stat_statements1.11.11.91.81.71.61.6Provides a means of tracking execution statistics of all SQL statements executed by a server.
pg_trgm1.61.61.61.51.41.41.3Provides functions and operators for alphanumeric text similarity, and index operator classes that support fast searching of similar strings.
pgcrypto1.31.31.31.31.31.31.3Provides cryptographic functions for PostgreSQL.
pgrowlocks1.21.21.21.21.21.21.2Provides a function to show row locking information for a specified table.
pgstattuple1.51.51.51.51.51.51.5Provides multiple functions to obtain tuple-level statistics.
plperl1111111Provides Perl procedural language.
plpgsql1111111Provides SQL procedural language.
pltcl1111111Provides Tcl procedural language.
postgres_fdw1.11.11.11111Cross-database table operations.
sslinfo1.21.21.21.21.21.21.2Provides information about the SSL certificate provided by the current client.
tablefunc1111111Contains multiple table-returning functions.
tsm_system_rows1111111Provides the table sampling method SYSTEM_ROWS.
tsm_system_time1111111Provides the table sampling method SYSTEM_TIME.
unaccent1.11.11.11.11.11.11.1A text search dictionary that can remove accents (diacritics) from lexemes.
uuid-ossp1.11.11.11.11.11.11.1Provides functions to generate universally unique identifiers (UUIDs) using several standard algorithms.
xml21.11.11.11.11.11.11.1Provides XPath queries and XSLT functionality.

Performance Comparison

MetricPigstyAliyun RDSAWS RDS
Peak PerformancePGTPC on NVME SSD Benchmark sysbench oltp_rwRDS PG Performance Whitepaper sysbench oltp scenario QPS 4000 ~ 8000 per core
Storage Spec: Max Capacity32TB / NVME SSD32 TB / ESSD PL364 TB / io2 EBS Block Express
Storage Spec: Max IOPS4K Random Read: Max 3M, Random Write 2000~350K4K Random Read: Max 1M16K Random IOPS: 256K
Storage Spec: Max Latency4K Random Read: 75µs, Random Write: 15µs4K Random Read: 200µs500µs / Inferred as 16K random IO
Storage Spec: Max ReliabilityUBER < 1e-18, equivalent to 18 nines MTBF: 2M hours 5DWPD, 3 years continuousReliability 9 nines, equivalent to UBER 1e-9 Storage and Data ReliabilityDurability: 99.999%, 5 nines (0.001% annual failure rate) io2 specification
Storage Spec: Max Cost¥31.5/TB·month (5-year warranty amortized / 3.2T / Enterprise-grade / MLC)¥3200/TB·month (original ¥6400, monthly ¥4000) 50% off with 3-year prepaid¥1900/TB·month using max spec 65536GB / 256K IOPS best discount

Observability

Pigsty provides nearly 3000 monitoring metrics and 50+ monitoring dashboards, covering database monitoring, host monitoring, connection pool monitoring, load balancer monitoring, and more, providing users with an unparalleled observability experience.

Pigsty monitoring dashboard

Pigsty provides 638 PostgreSQL-related monitoring metrics, while AWS RDS only has 99, and Aliyun RDS has only single-digit metrics:

Alibaba Cloud RDS for PostgreSQL metrics

Additionally, some projects provide PostgreSQL monitoring capabilities, but are relatively simple:


Maintainability

MetricPigstyAliyun RDSAWS RDS
System UsabilitySimpleSimpleSimple
Configuration ManagementConfig files / CMDB based on Ansible InventoryCan use TerraformCan use Terraform
Change MethodIdempotent Playbooks based on Ansible PlaybookConsole click operationsConsole click operations
Parameter TuningAuto-adapts to node specs, Four preset templates: OLTP, OLAP, TINY, CRIT
Infra as CodeNatively supportedCan use TerraformCan use Terraform
Customizable ParametersPigsty Parameters 283 parameters
Service & SupportCommercial subscription support availableAfter-sales ticket supportAfter-sales ticket support
Air-gapped DeploymentOffline installation supportedN/AN/A
Database MigrationPlaybooks for zero-downtime migration from existing v10+ PG instances to Pigsty managed instances via logical replicationCloud migration assistance Aliyun RDS Data Sync

Cost

Based on experience, RDS unit cost is 5-15 times that of self-hosted for software and hardware resources, with a rent-to-own ratio typically around one month. For details, see Cost Analysis.

FactorMetricPigstyAliyun RDSAWS RDS
CostSoftware License/Service FeeFree, hardware ~¥20-40/core·month¥200-400/core·month¥400-1300/core·month
Support Service FeeService ~¥100/core·monthIncluded in RDS cost

Other On-Premises Database Management Software

Some software and vendors providing PostgreSQL management capabilities:

  • Aiven: Closed-source commercial cloud-hosted solution
  • Percona: Commercial consulting, simple PG distribution
  • ClusterControl: Commercial database management software

Other Kubernetes Operators

Pigsty refuses to use Kubernetes for managing databases in production, so there are ecological differences with these solutions.

  • PGO
  • StackGres
  • CloudNativePG
  • TemboOperator
  • PostgresOperator
  • PerconaOperator
  • Kubegres
  • KubeDB
  • KubeBlocks

For more information, see:

4.13.1 - Cost Reference

This article provides cost data to help you evaluate self-hosted Pigsty, cloud RDS costs, and typical DBA salaries.

Overview

The cost data below is intended to illustrate order-of-magnitude differences. Cloud vendor pricing and discounts vary over time, region, instance size, and purchase model.

EC2Core·MonthRDSCore·Month
DHH Self-Hosted Core-Month Price (192C 384G)25.32Junior Open Source DB DBA Reference Salary¥15K/person·month
IDC Self-Hosted (Dedicated Physical: 64C384G)19.53Mid-Level Open Source DB DBA Reference Salary¥30K/person·month
IDC Self-Hosted (Container, 500% Oversold)7Senior Open Source DB DBA Reference Salary¥60K/person·month
UCloud Elastic VM (8C16G, Oversold)25ORACLE Database License10000
Aliyun ECS 2x Memory (Dedicated, No Oversold)107Aliyun RDS PG 2x Memory (Dedicated)260
Aliyun ECS 4x Memory (Dedicated, No Oversold)138Aliyun RDS PG 4x Memory (Dedicated)320
Aliyun ECS 8x Memory (Dedicated, No Oversold)180Aliyun RDS PG 8x Memory (Dedicated)410
AWS C5D.METAL 96C 200G (Monthly No Prepaid)100AWS RDS PostgreSQL db.T2 (2x)440
AWS C5D.METAL 96C 200G (3-Year Prepaid)80AWS RDS PostgreSQL db.M5 (4x)611
AWS C7A.METAL 192C 384G (3-Year Prepaid)104.8AWS RDS PostgreSQL db.R6G (8x)786

RDS Cost Reference

Payment ModelPriceAnnualized (¥10K)
IDC Self-Hosted (Single Physical Machine)¥75K / 5 years1.5
IDC Self-Hosted (2-3 Machines for HA)¥150K / 5 years3.0 ~ 4.5
Aliyun RDS On-Demand¥87.36/hour76.5
Aliyun RDS Monthly (Baseline)¥42K / month50
Aliyun RDS Annual (85% off)¥425,095 / year42.5
Aliyun RDS 3-Year Prepaid (50% off)¥750,168 / 3 years25
AWS On-Demand$25,817 / month217
AWS 1-Year No Prepaid$22,827 / month191.7
AWS 3-Year Full Prepaid$120K + $17.5K/month175
AWS China/Ningxia On-Demand¥197,489 / month237
AWS China/Ningxia 1-Year No Prepaid¥143,176 / month171
AWS China/Ningxia 3-Year Full Prepaid¥647K + ¥116K/month160.6

Here’s a comparison of self-hosted vs cloud database costs:

MethodAnnualized (¥10K)
IDC Hosted Server 64C / 384G / 3.2TB NVME SSD 660K IOPS (2-3 Machines)3.0 ~ 4.5
Aliyun RDS PG HA Edition pg.x4m.8xlarge.2c, 64C / 256GB / 3.2TB ESSD PL325 ~ 50
AWS RDS PG HA Edition db.m5.16xlarge, 64C / 256GB / 3.2TB io1 x 80k IOPS160 ~ 217

ECS Cost Reference

Pure Compute Price Comparison (Excluding NVMe SSD / ESSD PL3)

Using Aliyun as an example, the monthly pure compute price is 5-7x the self-hosted baseline, while 5-year prepaid is 2x self-hosted

Payment ModelUnit Price (¥/Core·Month)Relative to StandardSelf-Hosted Premium Multiple
On-Demand (1.5x)¥ 202160 %9.2 ~ 11.2
Monthly (Standard)¥ 126100 %5.7 ~ 7.0
1-Year Prepaid (65% off)¥ 83.766 %3.8 ~ 4.7
2-Year Prepaid (55% off)¥ 70.656 %3.2 ~ 3.9
3-Year Prepaid (44% off)¥ 55.144 %2.5 ~ 3.1
4-Year Prepaid (35% off)¥ 4535 %2.0 ~ 2.5
5-Year Prepaid (30% off)¥ 38.530 %1.8 ~ 2.1
DHH @ 2023¥ 22.0
Tantan IDC Self-Hosted¥ 18.0

Equivalent Price Comparison Including NVMe SSD / ESSD PL3

Including common NVMe SSD specs, the monthly pure compute price is 11-14x the self-hosted baseline, while 5-year prepaid is about 9x.

Payment ModelUnit Price (¥/Core·Month)+ 40GB ESSD PL3Self-Hosted Premium Multiple
On-Demand (1.5x)¥ 202¥ 36214.3 ~ 18.6
Monthly (Standard)¥ 126¥ 28611.3 ~ 14.7
1-Year Prepaid (65% off)¥ 83.7¥ 2449.6 ~ 12.5
2-Year Prepaid (55% off)¥ 70.6¥ 2309.1 ~ 11.8
3-Year Prepaid (44% off)¥ 55.1¥ 2158.5 ~ 11.0
4-Year Prepaid (35% off)¥ 45¥ 2058.1 ~ 10.5
5-Year Prepaid (30% off)¥ 38.5¥ 1997.9 ~ 10.2
DHH @ 2023¥ 25.3
Tantan IDC Self-Hosted¥ 19.5

DHH Case: 192 cores with 12.8TB Gen4 SSD (1c:66); Tantan Case: 64 cores with 3.2T Gen3 MLC SSD (1c:50).

Cloud prices calculated at 40GB ESSD PL3 per core (1 core:4x RAM:40x disk).


EBS Cost Reference

Evaluation FactorLocal PCI-E NVME SSDAliyun ESSD PL3AWS io2 Block Express
Capacity32TB32 TB64 TB
IOPS4K Random Read: 600K ~ 1.1M, 4K Random Write: 200K ~ 350K4K Random Read: Max 1M16K Random IOPS: 256K
Latency4K Random Read: 75µs, 4K Random Write: 15µs4K Random Read: 200µsRandom IO: ~500µs (contextually inferred as 16K)
ReliabilityUBER < 1e-18, equivalent to 18 nines, MTBF: 2M hours, 5DWPD for 3 yearsData Reliability 9 nines Storage and Data ReliabilityDurability: 99.999%, 5 nines (0.001% annual failure rate) io2 Specification
Cost¥16/TB·month (5-year amortized / 3.2T MLC), 5-year warranty, ¥3000 retail¥3200/TB·month (original ¥6400, monthly ¥4000), 50% off with 3-year full prepaid¥1900/TB·month using max spec 65536GB 256K IOPS best discount
SLA5-year warranty, replacement on failureAliyun RDS SLA Availability 99.99%: 15% monthly fee, 99%: 30% monthly fee, 95%: 100% monthly feeAmazon RDS SLA Availability 99.95%: 15% monthly fee, 99%: 25% monthly fee, 95%: 100% monthly fee

S3 Cost Reference

Date$/GB·Month¥/TB·5YearsHDD ¥/TBSSD ¥/TB
2006.030.150630002800
2010.110.140588001680
2012.120.0953990042015400
2014.040.030126003719051
2016.120.02396602453766
2023.120.0239660105280
Other ReferencesHigh-Perf StorageTop-Tier Discountedvs Purchased NVMe SSDPrice Ref
S3 Express0.16067200DHH 12T1400
EBS io20.125 + IOPS114000Shannon 3.2T900

Cloud Exit Collection

There was a time when “moving to the cloud” was almost politically correct in tech circles, and an entire generation of app developers had their vision obscured by the cloud. Let’s use real data analysis and firsthand experience to explain the value and pitfalls of the public cloud rental model — for your reference in this era of cost reduction and efficiency improvement — please see “Cloud Computing Mudslide: Collection

Cloud Infrastructure Basics


Cloud Business Model


Cloud Exit Odyssey


Cloud Failure Post-Mortems


RDS Failures


Cloud Vendor Profiles

4.13.2 - Open-Source Impact

Impact comparison of PostgreSQL ecosystem projects, mainly measured by GitHub star counts.

China PostgreSQL Ecosystem Projects

Sorted by GitHub stars in descending order. Last updated: 2026-08-13 (Beijing time).

ProjectStarAuthorTypeSummary
pgsty/pigsty5521Ruohang Feng @ PGSTYDistributionOut-of-the-box PostgreSQL distribution
polardb/PolarDB-for-PostgreSQL3191Alibaba CloudKernelOpen-source PolarDB for PostgreSQL kernel
tensorchord/pgvecto.rs2181TensorChordExtensionVector search extension written in Rust
tensorchord/VectorChord1770TensorChordExtensionNext-generation vector search extension
Tencent/TBase1439Tencent CloudKernelTencent distributed HTAP database kernel
apache/cloudberry1315HashDataKernelOpen-source MPP data warehouse kernel
IvorySQL/IvorySQL1051HighGoKernelOracle-compatible PostgreSQL fork
pgplex/pgschema995Chen TianzhouToolDeclarative Postgres schema migration CLI
amutu/zhparser869JovExtensionChinese full-text parser based on SCWS
opengauss-mirror/openGauss-server784HuaweiKernelEarly PostgreSQL 9.2 kernel fork
HaloTech-Co-Ltd/openHalo437HaloTechKernelPostgreSQL kernel compatible with MySQL wire protocol
jaiminpan/pg_jieba417Pan JiaminExtensionChinese full-text search extension based on Jieba
alitrack/duckdb_fdw409Li HongyanExtensionDuckDB foreign data wrapper
tensorchord/VectorChord-bm25375TensorChordExtensionNative BM25 ranking index for PostgreSQL
pgsty/pg_exporter359Ruohang Feng @ PGSTYToolMetrics exporter for PostgreSQL and Pgbouncer
ChenHuajun/pg_roaringbitmap286Chen Huajun @ SuningExtensionPostgreSQL RoaringBitmap bitmap extension
pgsty/pig199Ruohang Feng @ PGSTYToolPostgreSQL extension package manager
tensorchord/pg_bestmatch.rs101TensorChordExtensionBM25 sparse-vector generation in PostgreSQL
wublabdubdub/PDU-PostgreSQLDataUnloader101Zhang ChenToolPostgreSQL database rescue and unloading tool
tensorchord/pg_tokenizer.rs45TensorChordExtensionFull-text search tokenizer extension
jaiminpan/pg_scws41Pan JiaminExtensionChinese tokenizer extension based on SCWS
pgsty/pgext31Ruohang Feng @ PGSTYToolPostgreSQL extension catalog and metadata tool
tooltip:
  trigger: axis
  axisPointer: { type: shadow }
  formatter: $fn:tipfmt
grid: { left: 320, right: 72, top: 20, bottom: 26 }
xAxis:
  type: value
  max: 5600
  name: GitHub Stars
  nameLocation: middle
  nameGap: 24
  axisLabel: { formatter: $fn:fnum }
  splitLine: { show: true, lineStyle: { type: dashed, opacity: 0.45 } }
yAxis:
  type: category
  inverse: true
  axisLabel:
    align: right
    margin: 8
    width: 300
    overflow: truncate
    fontSize: 11
    fontFamily: monospace
  data:
    - 'pgsty/pigsty'
    - 'polardb/PolarDB-for-PostgreSQL'
    - 'tensorchord/pgvecto.rs'
    - 'tensorchord/VectorChord'
    - 'Tencent/TBase'
    - 'apache/cloudberry'
    - 'IvorySQL/IvorySQL'
    - 'pgplex/pgschema'
    - 'amutu/zhparser'
    - 'opengauss-mirror/openGauss-server'
    - 'HaloTech-Co-Ltd/openHalo'
    - 'jaiminpan/pg_jieba'
    - 'alitrack/duckdb_fdw'
    - 'tensorchord/VectorChord-bm25'
    - 'pgsty/pg_exporter'
    - 'ChenHuajun/pg_roaringbitmap'
    - 'pgsty/pig'
    - 'tensorchord/pg_bestmatch.rs'
    - 'wublabdubdub/PDU-PostgreSQLDataUnloader'
    - 'tensorchord/pg_tokenizer.rs'
    - 'jaiminpan/pg_scws'
    - 'pgsty/pgext'
series:
  - name: Star
    type: bar
    barWidth: 20
    showBackground: true
    backgroundStyle: { color: "rgba(148, 163, 184, 0.16)" }
    itemStyle:
      color: $fn:barclr
      borderRadius: [0, 5, 5, 0]
    label:
      show: true
      position: right
      formatter: $fn:labfmt
      color: '#334155'
      fontWeight: 600
    data: [5521, 3191, 2181, 1770, 1439, 1315, 1051, 995, 869, 784, 437, 417, 409, 375, 359, 286, 199, 101, 101, 45, 41, 31]

PostgreSQL Distribution Impact Metrics

Sorted by GitHub stars in descending order, with commercial products that do not publish stars listed last. Last updated: 2026-08-13 (Beijing time).

ProjectStarVendorTypeLicenseSummary
CloudNativePG9133EDBK8S NativeApache-2.0Mainstream PG Operator without Patroni dependency
Pigsty5521PGSTYLinux NativeApache-2.0Ansible-driven integrated PostgreSQL distribution
Zalando Postgres Operator5222ZalandoK8S NativeMITLong-standing Patroni/Spilo architecture operator
PGO4436Crunchy DataK8S NativeApache-2.0Production-grade operator with backup and monitoring
Autobase4332vitabaksLinux NativeMITAutomated deployment for Patroni/etcd/Consul
KubeBlocks3102ApeCloudK8S NativeAGPL-3.0Unified multi-database operator platform
StackGres1426OnGresK8S NativeAGPL-3.0Integrated PG operator with CRD/CLI/Web UI
Kubegres1350Reactive TechK8S NativeApache-2.0Minimal operator built on native streaming replication
Tembo Operator1263TemboK8S NativeUnspecifiedScenario-based stacks for PostgreSQL
pgEdge744pgEdgeLinux NativePostgreSQLDistributed PG distribution focused on Spock multi-master replication
KubeDB733AppsCodeK8S NativeACL-1.0Multi-database operator with kubectl plugin
Percona Operator for PostgreSQL381PerconaK8S NativeApache-2.0PostgreSQL operator in Percona ecosystem
EDB TPA86EDBLinux NativeGPL-3.0EDB official Ansible delivery toolkit
Percona Distribution for PostgreSQL-PerconaLinux NativeMultiIntegrated PostgreSQL distribution bundle
ClusterControl-ServerNinesLinux NativeCommercialMulti-database deploy, monitoring, backup, and failover platform
CYBERTEC PGEE-CYBERTECLinux NativeCommercialEnterprise PostgreSQL distribution focused on security and performance
Crunchy Postgres for Ansible-Crunchy DataLinux NativeCommercialCrunchy bare-metal/VM automation solution
EDB Postgres Advanced Server (EPAS)-EDBLinux NativeCommercialEDB flagship distribution with Oracle-compatibility features

Star History Chart

Other Resources

5 - References

Detailed reference information and lists, supported Linux distros, available modules, metrics, extensions, and more.

5.1 - Supported Linux

Pigsty compatible Linux OS distribution major versions and CPU architectures

Pigsty runs on Linux, supporting amd64/x86_64 and arm64/aarch64 arch, plus 3 major distros: EL, Debian, Ubuntu.

Pigsty runs bare-metal without containers. Supports actively maintained mainstream releases across the 3 major distro families and both archs.

Overview

Recommended OS versions: Rocky Linux 9.8 / 10.2, Debian 12.15 / 13.6, Ubuntu 22.04.5 / 24.04.4 / 26.04.0.

DistroArchOS CodePG18PG17PG16PG15PG14
RHEL / Rocky / Alma 10x86_64el10.x86_64
RHEL / Rocky / Alma 10aarch64el10.aarch64
RHEL / Rocky / Alma 9x86_64el9.x86_64
RHEL / Rocky / Alma 9aarch64el9.aarch64
Ubuntu 26.04 (resolute)x86_64u26.x86_64
Ubuntu 26.04 (resolute)aarch64u26.aarch64
Ubuntu 24.04 (noble)x86_64u24.x86_64
Ubuntu 24.04 (noble)aarch64u24.aarch64
Ubuntu 22.04 (jammy)x86_64u22.x86_64
Ubuntu 22.04 (jammy)aarch64u22.aarch64
Debian 13 (trixie)x86_64d13.x86_64
Debian 13 (trixie)aarch64d13.aarch64
Debian 12 (bookworm)x86_64d12.x86_64
Debian 12 (bookworm)aarch64d12.aarch64

These seven minor releases are the current validation baselines. The extension repository retains dual-architecture EL8 compatibility, so the complete package matrix covers 16 Linux platforms. EL8 is in its retirement transition and is no longer a recommended deployment baseline.


EL

Pigsty supports RHEL / Rocky / Alma / Anolis / CentOS 8, 9, 10.

EL DistroArchOS CodePG18PG17PG16PG15PG14
RHEL10 / Rocky10 / Alma10x86_64el10.x86_64
RHEL10 / Rocky10 / Alma10aarch64el10.aarch64
RHEL9 / Rocky9 / Alma9x86_64el9.x86_64
RHEL9 / Rocky9 / Alma9aarch64el9.aarch64
RHEL8 / Rocky8 / Alma8x86_64el8.x86_64
RHEL8 / Rocky8 / Alma8aarch64el8.aarch64
RHEL7 / CentOS7x86_64el7.x86_64
RHEL7 / CentOS7aarch64-
Rocky Linux 9.8 / 10.2 Recommended

Rocky Linux 9.8 / 10.2 balances stability and fresh software. Recommended for EL users.

EL8 EOL Soon

EL8 goes EOL in 2029. Plan upgrade ASAP. EL10 support is ready, EL8 will be dropped in next release.

EL 7 EOL @ 2024-06

RHEL 7 EOL since Jun 2024. PGDG stopped providing binary packages for PG 16/17/18 on EL7.

For extended support on legacy OS, consider Enterprise Subscription.


Ubuntu

Pigsty supports Ubuntu 26.04 / 24.04 / 22.04:

Ubuntu DistroArchOS CodePG18PG17PG16PG15PG14
Ubuntu 26.04 (resolute)x86_64u26.x86_64
Ubuntu 26.04 (resolute)aarch64u26.aarch64
Ubuntu 24.04 (noble)x86_64u24.x86_64
Ubuntu 24.04 (noble)aarch64u24.aarch64
Ubuntu 22.04 (jammy)x86_64u22.x86_64
Ubuntu 22.04 (jammy)aarch64u22.aarch64
Ubuntu 22.04.5 / 24.04.4 / 26.04.0 LTS Recommended

Ubuntu 26.04 provides the newest LTS baseline, while Ubuntu 24.04 remains the conservative default for Ubuntu users.


Debian

Pigsty supports Debian 12 / 13, latest Debian 13.6 recommended:

Debian DistroArchOS CodePG18PG17PG16PG15PG14
Debian 13 (trixie)x86_64d13.x86_64
Debian 13 (trixie)aarch64d13.aarch64
Debian 12 (bookworm)x86_64d12.x86_64
Debian 12 (bookworm)aarch64d12.aarch64
Debian 11 (bullseye)x86_64d11.x86_64 (historical)
Debian 11 (bullseye)aarch64-
Debian 12.15 / 13.6 Recommended
Debian 11 EOL @ 2024-07

Debian 11 EOL since Jul 2024. For extended support on legacy OS, consider Enterprise Subscription.


Vagrant

For local VM deployment, use these Vagrant base images (same as used in Pigsty dev):


Terraform

For cloud deployment, use these Terraform base image prefixes (Aliyun example):

x86_64Aliyun Image Prefix
Rocky 8.10rockylinux_8_10_x64
Rocky 9.8rockylinux_9_8_x64
Rocky 10.2rockylinux_10_2_x64
Ubuntu 22.04.5ubuntu_22_04_x64_20G
Ubuntu 24.04.4ubuntu_24_04_x64_20G
Ubuntu 26.04.0ubuntu_26_04_x64_20G
Debian 12.15debian_12_15_x64
Debian 13.6debian_13_6_x64
aarch64Aliyun Image Prefix
Rocky 8.10rockylinux_8_10_arm64
Rocky 9.8rockylinux_9_8_arm64
Rocky 10.2rockylinux_10_2_arm64
Ubuntu 22.04.5ubuntu_22_04_arm64_20G
Ubuntu 24.04.4ubuntu_24_04_arm64_20G
Ubuntu 26.04.0ubuntu_26_04_arm64_20G
Debian 12.15debian_12_15_arm64
Debian 13.6debian_13_6_arm64

5.2 - Modules

This article lists available Pigsty modules and the current module planning.

Official Modules

ModuleCategoryStatusDocs PathSummary
PGSQLCoreGA/docs/pgsqlHigh-availability PostgreSQL clusters with built-in backup, monitoring, SOP, and extension ecosystem.
INFRACoreGA/docs/infraLocal software repository + VictoriaMetrics/Logs/Traces + Grafana infrastructure stack.
NODECoreGA/docs/nodeNode initialization and convergence: system tuning, admin, HAProxy, Vector, Keepalived, etc.
ETCDCoreGA/docs/etcdDCS for PostgreSQL HA (service discovery, config, leader-election metadata).
MINIOExtensionGA/docs/minioDeploys Silo S3-compatible object storage, suitable for PostgreSQL backups.
REDISExtensionGA/docs/redisRedis by default, or Valkey, in standalone, Sentinel, or native-cluster mode with monitoring.
DOCKERExtensionGA/docs/dockerDocker daemon and the runtime capability for containerized apps.
JUICEExtensionBETA/docs/juiceJuiceFS distributed file system using PostgreSQL as metadata engine.
VIBEExtensionBETA/docs/vibeBrowser-based dev environment with Code-Server, JupyterLab, Node.js, Claude Code, and Codex CLI.
KAFKAExtensionBETA/docs/kafkaApache Kafka 4.x dynamic KRaft cluster deployment, security baseline, and monitoring.

Core Modules

Pigsty provides four core modules that are important for delivering complete highly available PostgreSQL services:

  • PGSQL: Self-healing PostgreSQL clusters with HA, PITR, IaC, SOP, monitoring, and 576 extensions.
  • INFRA: Local software repository, VictoriaMetrics, VictoriaLogs, VictoriaTraces, Grafana, Alertmanager, Blackbox Exporter…
  • NODE: Node convergence for hostname, timezone, NTP, SSH, sudo, HAProxy, Vector, and Keepalived.
  • ETCD: Distributed key-value store used as DCS for HA PostgreSQL clusters: consensus leader election/config management/service discovery.

Although these four modules are usually installed together, separate use is still feasible. In practice, only the NODE module is usually mandatory.


Extension Modules

Pigsty provides six extension modules. They are not mandatory for core functionality, but can enhance PostgreSQL capabilities:

  • MINIO: An S3-compatible object-storage module that deploys Silo and provides PostgreSQL backup integration and monitoring.
  • REDIS: Redis server with standalone/sentinel/cluster production deployment and full monitoring support.
  • DOCKER: Docker daemon service for one-click deployment of stateless software templates on Pigsty.
  • JUICE: JuiceFS distributed filesystem module using PostgreSQL as metadata engine, providing shared POSIX storage.
  • VIBE: Browser-based development environment with Code-Server, JupyterLab, Node.js, Claude Code, and Codex CLI.
  • KAFKA: Apache Kafka 4.x dynamic KRaft clusters with TLS/SCRAM/ACL security baseline, declarative topics/users, and full monitoring.

Ecosystem Modules

The modules below are closely related to the PostgreSQL ecosystem. They are optional ecosystem capabilities and are not counted in the 10 official modules above:

  • SUPABASE, DUCKDB: peripheral ecosystem integration.
  • MSSQL, IVORY, POLAR, CITUS, CLOUDBERRY, PGEDGE: kernel replacement, distributed, and MPP forms.
  • MYSQL-compatible kernel (OpenHalo), ORIOLE, PGTDE, AGENS: protocol compatibility, storage engine, transparent encryption, and graph database kernels. Here, MYSQL means the pg_mode=mysql PostgreSQL-compatible kernel, not a native MySQL service.
  • GREENPLUM, NEON: historical docs retained, no longer default public capabilities.
  • Native MYSQL pilot: the current mysql.yml, mysql-rm.yml, and roles/mysql* manage a fixed native MySQL 8.4 platform with either one node or a three-node single-primary InnoDB Cluster. It remains a PILOT and is not counted among the 10 official modules above.
  • KUBE, VICTORIA, JUPYTER: other pilot modules, currently not open for public use.

5.3 - File Hierarchy

How Pigsty’s file system structure is designed and organized, and directory structures used by each module.

Pigsty FHS

Pigsty’s home directory is located at ~/pigsty by default. The file structure within this directory is as follows:

~/pigsty Source Tree

  • app/
    • Application template resources
  • bin/
    • Management and operations scripts
  • files/
    • victoria/
      • Rules and operations scripts
    • grafana/
      • Grafana dashboards
    • postgres/
      • PostgreSQL management scripts
    • migration/
      • Data-migration task definitions
    • pki/
      • Self-signed CA and certificates
  • roles/
    • Ansible role implementations
  • templates/
    • Ansible templates
  • vagrant/
    • Vagrant sandbox definitions
  • terraform/
    • Terraform cloud-resource templates
  • configure
  • ansible.cfg
  • pigsty.yml
  • *.yml

/infra is a runtime symlink to /data/infra, which keeps observability data and generated configuration together:

/data/infra
metrics/           # VictoriaMetrics TSDB data
logs/              # VictoriaLogs data
traces/             # VictoriaTraces data
alertmgr/           # AlertManager data
rules/              # Rule definitions, including agent.yml
targets/            # FileSD monitoring targets
dashboards/         # Grafana dashboard definitions
datasources/        # Grafana datasource definitions
prometheus.yml      # Victoria Prometheus-compatible configuration

CA FHS

Pigsty’s self-signed CA is located in files/pki/ under the Pigsty home directory.

You must keep the CA key file secure: files/pki/ca/ca.key. This key is generated by the ca role during deploy.yml or infra.yml execution.

# pigsty/files/pki                           # (local_user) 0755
#  ^-----@ca                                 # (local_user) 0700
#         ^[email protected]                      # 0600, CRITICAL: keep secret
#         ^[email protected]                      # 0644, CRITICAL: trust anchor
#  ^-----@csr                                # (local_user) 0755, CSRs
#  ^-----@misc                               # (local_user) 0755, misc/issued certs
#  ^-----@etcd                               # (local_user) 0755, ETCD certs
#  ^-----@minio                              # (local_user) 0755, MinIO certs
#  ^-----@nginx                              # (local_user) 0755, Nginx SSL certs
#  ^-----@infra                              # (local_user) 0755, infra client certs
#  ^-----@pgsql                              # (local_user) 0755, PostgreSQL certs
#  ^-----@kafka                              # (local_user) 0755, Kafka server certs
#  ^-----@mysql                              # (local_user) 0755, MySQL server certs

Nodes managed by Pigsty will have the following certificate files installed:

/etc/pki/ca.crt                             # root:root 0644, root cert on all nodes
/etc/pki/ca-trust/source/anchors/ca.crt     # EL system trust anchor
/usr/local/share/ca-certificates/ca.crt     # Debian/Ubuntu system trust anchor

All infra nodes will have the following certificates:

/etc/pki/infra.crt                          # root:infra 0644, infra node cert
/etc/pki/infra.key                          # root:infra 0640, infra node key

When your admin node fails, the files/pki directory and pigsty.yml file should be available on the backup admin node. You can use rsync to achieve this:

# run on meta-1, rsync to meta2
cd ~/pigsty;
rsync -avz ./ meta-2:~/pigsty

INFRA FHS

The infra role creates infra_data (default: /data/infra) and creates a symlink /infra -> /data/infra. /data/infra permissions are root:infra 0771; subdirectories default to *:infra 0750 unless overridden:

# /infra -> /data/infra
# /data/infra                              # root:infra 0771
#  ^-----@pgadmin                          # 5050:5050 0700
#  ^-----@alertmgr                         # prometheus:infra 0700
#  ^-----@conf                             # root:infra 0750
#            ^-----patronictl.yml          # root:admin 0640
#  ^-----@tmp                              # root:infra 0750
#  ^-----@hosts                            # dnsmasq:dnsmasq 0755 (DNS records)
#            ^-----default                 # root:root 0644
#  ^-----@datasources                      # root:infra 0750
#            ^-----*.json                  # 0600 (generated by register)
#  ^-----@dashboards                       # grafana:infra 0750
#  ^-----@metrics                          # victoria:infra 0750
#  ^-----@logs                             # victoria:infra 0750
#  ^-----@traces                           # victoria:infra 0750
#  ^-----@bin                              # victoria:infra 0750
#            ^-----check|new|reload|status # root:infra 0755
#  ^-----@rules                            # victoria:infra 0750
#            ^-----agent.yml               # victoria:infra 0644
#            ^-----infra.yml               # victoria:infra 0644
#            ^-----node.yml                # victoria:infra 0644
#            ^-----pgsql.yml               # victoria:infra 0644
#            ^-----redis.yml               # victoria:infra 0644
#            ^-----etcd.yml                # victoria:infra 0644
#            ^-----minio.yml               # victoria:infra 0644
#            ^-----kafka.yml               # victoria:infra 0644
#            ^-----mysql.yml               # victoria:infra 0644
#  ^-----@targets                          # victoria:infra 0750
#            ^-----@infra                  # infra targets (files 0640)
#            ^-----@node                   # node targets (files 0640)
#            ^-----@ping                   # ping targets (files 0640)
#            ^-----@etcd                   # etcd targets (files 0640)
#            ^-----@pgsql                  # pgsql targets (files 0640)
#            ^-----@pgrds                  # pgrds targets (files 0640)
#            ^-----@redis                  # redis targets (files 0640)
#            ^-----@minio                  # minio targets (files 0640)
#            ^-----@juice                  # juicefs targets (files 0640)
#            ^-----@mysql                  # mysql targets (files 0640)
#            ^-----@kafka                  # kafka targets (files 0640)
#            ^-----@docker                 # docker targets (files 0640)
#            ^-----@patroni                # patroni SSL targets (files 0640)
#  ^-----prometheus.yml                    # victoria:infra 0644

This structure is created by: roles/infra/tasks/dir.yml, roles/infra/tasks/victoria.yml, roles/infra/tasks/register.yml, roles/infra/tasks/dns.yml, and roles/infra/tasks/env.yml.


NODE FHS

The node data directory is specified by node_data, defaulting to /data, owned by root:root with mode 0755.

Most core components place their default data directories here. Some pilot modules use fixed paths of their own; native MySQL 8.4 currently uses /var/lib/mysql.

/data                                 # root:root 0755
#  ^-----@postgres                    # postgres:postgres 0700 (default pg_fs_main)
#  ^-----@backups                     # postgres:postgres 0700 (default pg_fs_backup)
#  ^-----@redis                       # redis:redis 0700 (shared by multiple instances)
#  ^-----@minio                       # minio:minio 0750 (single-node single-disk mode)
#  ^-----@etcd                        # etcd:etcd 0700 (etcd_data)
#  ^-----@infra                       # root:infra 0771 (infra module data directory)
#  ^-----@docker                      # root:root 0755 (Docker data directory)
#  ^-----@kafka                       # kafka:kafka 0700 (kafka_data)
#  ^-----@...                         # Other component data directories

HAProxy

Pigsty starts HAProxy with its own systemd unit and manages the main configuration separately from service fragments:

/etc/systemd/system/haproxy.service   # systemd unit rendered by Pigsty
/etc/haproxy/haproxy.cfg              # HAProxy main configuration
/etc/haproxy/conf.d/*.cfg             # node and PostgreSQL service fragments
/etc/default/haproxy                  # optional user environment file; Pigsty does not create it

To append startup arguments in /etc/default/haproxy, use EXTRAOPTS and retain the default -S /run/haproxy-master.sock. The systemd unit already loads configuration with explicit -f arguments, so do not add another -f to EXTRAOPTS.


Victoria FHS

Monitoring config has moved from the legacy /etc/prometheus layout to the /infra runtime layout. The main template is roles/infra/templates/victoria/prometheus.yml, rendered to /infra/prometheus.yml.

files/victoria/bin/* and files/victoria/rules/* are synced to /infra/bin/ and /infra/rules/, while each module registers FileSD targets under /infra/targets/*.

# /infra
#  ^-----prometheus.yml              # Victoria main config (Prometheus-compatible) 0644
#  ^-----@bin                        # Utility scripts (check/new/reload/status) 0755
#  ^-----@rules                      # Recording and alerting rules (*.yml 0644)
#            ^-----agent.yml         # Agent pre-aggregation rules
#            ^-----infra.yml         # infra rules and alerts
#            ^-----etcd.yml          # etcd rules and alerts
#            ^-----node.yml          # node rules and alerts
#            ^-----pgsql.yml         # pgsql rules and alerts
#            ^-----redis.yml         # redis rules and alerts
#            ^-----minio.yml         # minio rules and alerts
#            ^-----kafka.yml         # kafka rules and alerts
#            ^-----mysql.yml         # mysql rules and alerts
#  ^-----@targets                    # FileSD targets (*.yml 0640)
#            ^-----@infra            # infra static targets
#            ^-----@node             # node static targets
#            ^-----@pgsql            # pgsql static targets
#            ^-----@pgrds            # pgsql remote RDS targets
#            ^-----@redis            # redis static targets
#            ^-----@minio            # minio static targets
#            ^-----@mysql            # mysql static targets
#            ^-----@etcd             # etcd static targets
#            ^-----@ping             # ping static targets
#            ^-----@kafka            # kafka static targets
#            ^-----@juice            # juicefs static targets
#            ^-----@docker           # docker static targets
#            ^-----@patroni          # patroni static targets (when SSL enabled)
# /etc/default/vmetrics              # vmetrics startup args (victoria:infra 0644)
# /etc/default/vlogs                 # vlogs startup args (victoria:infra 0644)
# /etc/default/vtraces               # vtraces startup args (victoria:infra 0644)
# /etc/default/vmalert               # vmalert startup args (victoria:infra 0644)
# /etc/alertmanager.yml              # alertmanager main config (prometheus:infra 0644)
# /etc/default/alertmanager          # alertmanager env (prometheus:infra 0640)
# /etc/blackbox.yml                  # blackbox main config (prometheus:infra 0644)
# /etc/default/blackbox_exporter     # blackbox env (prometheus:infra 0644)

Pigsty-rendered INFRA units are consistently stored in /etc/systemd/system/, including vmetrics, vlogs, vtraces, vmalert, alertmanager, blackbox_exporter, nginx_exporter, and dnsmasq. Distribution package unit directories are not write targets for these roles.


PostgreSQL FHS

The following parameters and internal variables are related to PostgreSQL directory layout:

  • pg_dbsu_home: Postgres default user home directory, default: /var/lib/pgsql
  • pg_bin_dir: Postgres binary directory, default: /usr/pgsql/bin/
  • pg_fs_main: Postgres primary data directory, default: /data/postgres
  • pg_fs_backup: Postgres backup disk mount point, default: /data/backups (optional; can also be a subdirectory on primary disk)
  • pg_data: Internal variable, fixed to the Postgres data-directory symlink /pg/data
  • pg_cluster_dir: Derived variable, {{ pg_fs_main }}/{{ pg_cluster }}-{{ pg_version }}
  • pg_backup_dir: Derived variable, {{ pg_fs_backup }}/{{ pg_cluster }}-{{ pg_version }}
#--------------------------------------------------------------#
# Working assumptions:
#   {{ pg_fs_main   }} primary data directory, default: `/data/postgres` [SSD]
#   {{ pg_fs_backup }} backup data disk, default: `/data/backups`        [HDD]
#--------------------------------------------------------------#
# Default config (pg_cluster=pg-test, pg_version=18):
#     pg_fs_main = /data/postgres      High-speed SSD
#     pg_fs_backup = /data/backups     Cheap HDD (optional)
#
#     /pg        -> /data/postgres/pg-test-18
#     /pg/data   -> /data/postgres/pg-test-18/data
#     /pg/backup -> /data/backups/pg-test-18/backup
#--------------------------------------------------------------#
- name: create pgsql directories
  tags: pg_dir
  become: true
  block:

    - name: create pgsql directories
      file: path={{ item.path }} state=directory owner={{ item.owner|default(pg_dbsu) }} group={{ item.group|default('postgres') }} mode={{ item.mode }}
      with_items:
        - { path: "{{ pg_fs_main }}"            ,mode: "0700" }
        - { path: "{{ pg_fs_backup }}"          ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}"        ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}/bin"    ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}/log"    ,mode: "0750" }
        - { path: "{{ pg_cluster_dir }}/tmp"    ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}/cert"   ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}/conf"   ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}/data"   ,mode: "0700" }
        - { path: "{{ pg_cluster_dir }}/spool"  ,mode: "0700" }
        - { path: "{{ pg_backup_dir }}/backup"  ,mode: "0700" }
        - { path: "/var/run/postgresql"         ,owner: root, group: root, mode: "0755" }

    - name: link pgsql directories
      file: src={{ item.src }} dest={{ item.dest }} state=link
      with_items:
        - { src: "{{ pg_backup_dir }}/backup" ,dest: "{{ pg_cluster_dir }}/backup" }
        - { src: "{{ pg_cluster_dir }}"       ,dest: "/pg" }

Data File Structure

# Physical directories
{{ pg_fs_main }}     /data/postgres                    # postgres:postgres 0700, primary data directory
{{ pg_cluster_dir }} /data/postgres/pg-test-18         # postgres:postgres 0700, cluster directory
                     /data/postgres/pg-test-18/bin     # postgres:postgres 0700 (scripts root:postgres 0755)
                     /data/postgres/pg-test-18/log     # postgres:postgres 0750, logs
                     /data/postgres/pg-test-18/tmp     # postgres:postgres 0700, temp files
                     /data/postgres/pg-test-18/cert    # postgres:postgres 0700, certs
                     /data/postgres/pg-test-18/conf    # postgres:postgres 0700, config index
                     /data/postgres/pg-test-18/data    # postgres:postgres 0700, main data
                     /data/postgres/pg-test-18/spool   # postgres:postgres 0700, pgBackRest spool
                     /data/postgres/pg-test-18/backup  # -> /data/backups/pg-test-18/backup

{{ pg_fs_backup  }}  /data/backups                     # postgres:postgres 0700, optional backup mount
{{ pg_backup_dir }}  /data/backups/pg-test-18          # postgres:postgres 0700, cluster backup directory
                     /data/backups/pg-test-18/backup   # postgres:postgres 0700, actual backup location

# Symlinks
/pg             ->   /data/postgres/pg-test-18         # pg root symlink
/pg/data        ->   /data/postgres/pg-test-18/data    # pg data directory
/pg/backup      ->   /data/backups/pg-test-18/backup   # pg backup directory

Binary File Structure

On EL-compatible distributions (using yum), PostgreSQL default installation location is:

/usr/pgsql-${pg_version}/

Pigsty creates a symlink named /usr/pgsql pointing to the actual version specified by the pg_version parameter, for example:

/usr/pgsql -> /usr/pgsql-18

Therefore, the default pg_bin_dir is /usr/pgsql/bin/, and this path is added to the system PATH environment variable, defined in: /etc/profile.d/pgsql.sh.

export PATH="/usr/pgsql/bin:/pg/bin:$PATH"
export PGHOME=/usr/pgsql
export PGDATA=/pg/data

On Ubuntu/Debian, the default PostgreSQL Deb package installation location is:

/usr/lib/postgresql/${pg_version}/bin

Pigsty-rendered PostgreSQL runtime units are likewise stored in /etc/systemd/system/. They primarily include patroni.service, postgres.service, pgbouncer.service, pg_exporter.service, pgbackrest_exporter.service, pgbouncer_exporter.service, and vip-manager.service when VIP is enabled.


Pgbouncer FHS

Pgbouncer runs under the same user as {{ pg_dbsu }} (default postgres), with configs in /etc/pgbouncer.

  • pgbouncer.ini: main pool configuration (postgres:postgres 0640)
  • database.txt: pooled database definitions (postgres:postgres 0600)
  • useropts.txt: per-user connection options (postgres:postgres 0600)
  • userlist.txt: password file maintained by /pg/bin/pgb-user
  • pgb_hba.conf: access control file (postgres:postgres 0600)
/etc/pgbouncer/                # postgres:postgres 0750
/etc/pgbouncer/pgbouncer.ini   # postgres:postgres 0640
/etc/pgbouncer/database.txt    # postgres:postgres 0600
/etc/pgbouncer/useropts.txt    # postgres:postgres 0600
/etc/pgbouncer/userlist.txt    # postgres:postgres (managed by pgb-user)
/etc/pgbouncer/pgb_hba.conf    # postgres:postgres 0600
/pg/log/pgbouncer              # postgres:postgres 0750
/var/run/postgresql            # {{ pg_dbsu }}:postgres 0755 (managed by tmpfiles)

Object Storage FHS

The MINIO module currently deploys only Silo, while retaining minio_* parameter and directory names for compatibility:

/etc/default/silo                             # root:minio 0640, service environment
/etc/systemd/system/silo.service              # root:root 0644, rendered by Pigsty
/data/minio/                                  # minio:minio 0750, default data directory
/infra/targets/minio/<cluster>-<seq>.yml      # victoria:infra 0640, FileSD target
/home/minio/.mcli/config.json                 # mcli alias; also written for the execution user

Silo certificates are stored in /home/minio/.minio/certs/. The module name, role parameters, data directory, and FileSD path retain the compatible MINIO / minio_* naming.


Redis FHS

Pigsty manages Redis or Valkey with the same directory layout and instance naming.

Service units call binaries according to redis_type (/bin/* is compatible with /usr/bin/* on most distributions):

/bin/redis-server  /bin/redis-cli    # redis_type: redis
/bin/valkey-server /bin/valkey-cli   # redis_type: valkey

For a Redis instance named redis-test-1-6379, the related resources are as follows:

/etc/systemd/system/redis-test-1-6379.service         # root:root 0644, rendered by Pigsty
/etc/systemd/system/redis_exporter.service            # root:root 0644, rendered by Pigsty
/etc/redis/                                           # redis:redis 0700
/etc/redis/redis-test-1-6379.conf                     # redis:redis 0600
/data/redis/                                          # redis:redis 0700
/data/redis/redis-test-1-6379                         # redis:redis 0700
/data/redis/redis-test-1-6379/redis-test-1-6379.rdb   # RDB file
/data/redis/redis-test-1-6379/redis-test-1-6379.aof   # AOF file
/var/log/redis/                                       # redis:redis 0700
/var/log/redis/redis-test-1-6379.log                  # logs
/var/run/redis/                                       # redis:redis 0700 (tmpfiles creates 0755 at boot)
/var/run/redis/redis-test-1-6379.pid                  # PID

Pigsty-rendered Redis/Valkey instance and exporter units are consistently stored in /etc/systemd/system/, and instance units use Type=notify. Package-provided units may still live in distribution directories, but those are not role write targets.

5.4 - Parameters

Pigsty v4.x configuration overview and module parameter navigation

This is the parameter navigation page for Pigsty v4.x, without repeating full explanations for each parameter. For parameter details, please read each module’s param page.

Cross-checked against the current source and parameter reference pages, the 10 official modules expose 373 public parameters. Native MySQL 8.4 remains a pilot module; its 13 public parameters are listed separately and are not included in the official-module total.


Module Parameter Navigation

ModuleGroupsCountDescription
PGSQL9124PostgreSQL HA cluster configuration
INFRA1073Software repository and Victoria-based observability infra
NODE1173Node initialization, system tuning, and ops baseline
ETCD213ETCD cluster and removal safeguard parameters
MINIO222Silo deployment, observability, and removal parameters
REDIS222Redis/Valkey deployment and removal parameters
DOCKER18Docker engine parameters
JUICE12JuiceFS instance and cache parameters
VIBE118Code/Jupyter/Node.js/Claude/Codex configuration
KAFKA218Kafka deployment and removal safeguard parameters

Pilot module: native MYSQL 8.4 currently exposes 13 public parameters: 11 for deployment and 2 for protected removal. Fixed ports, paths, software versions, and timers are not public parameters.


Parameter Group Quick View


Recommendations

  • Read in this order for first deployment: NODE, INFRA, PGSQL
  • In production, always review: *_safeguard, password credentials, ports, and network exposure
  • Validate changes on one cluster first, then roll out globally in batches

5.5 - Playbooks

Pigsty v4.x preset Ansible playbook navigation and execution notes

This page summarizes Pigsty v4.x playbook entries and usage guidance by module. For detailed task tags, open each module’s playbook page.

Module Playbook Navigation

ModuleCountPlaybooks
INFRA3deploy.yml infra.yml infra-rm.yml
NODE2node.yml node-rm.yml
ETCD2etcd.yml etcd-rm.yml
PGSQL7pgsql.yml pgsql-rm.yml
pgsql-user.yml pgsql-db.yml
pgsql-monitor.yml pgsql-migration.yml pgsql-pitr.yml
REDIS2redis.yml redis-rm.yml
MINIO2minio.yml minio-rm.yml
DOCKER1docker.yml
JUICE1juice.yml
VIBE1vibe.yml
KAFKA2kafka.yml kafka-rm.yml
MYSQL (pilot)2mysql.yml mysql-rm.yml

Playbook Matrix

PlaybookModulePurpose
deploy.ymlINFRAOne-pass deployment for the core chain (Infra/Node/Etcd/PGSQL, enabling MINIO by config)
infra.ymlINFRAInitialize infrastructure nodes
infra-rm.ymlINFRARemove infrastructure components
node.ymlNODENode onboarding and baseline convergence
node-rm.ymlNODENode offboarding
etcd.ymlETCDETCD install/scale-out
etcd-rm.ymlETCDETCD remove/scale-in
pgsql.ymlPGSQLInitialize PostgreSQL cluster or add instance
pgsql-rm.ymlPGSQLRemove PostgreSQL cluster/instance
pgsql-user.ymlPGSQLAdd business users
pgsql-db.ymlPGSQLAdd business databases
pgsql-monitor.ymlPGSQLRegister remote PostgreSQL for monitoring
pgsql-migration.ymlPGSQLGenerate migration runbook and scripts
pgsql-pitr.ymlPGSQLPoint-in-time recovery (PITR)
redis.ymlREDISDeploy Redis
redis-rm.ymlREDISRemove Redis
minio.ymlMINIODeploy Silo
minio-rm.ymlMINIORemove Silo, its configuration, and optional data
docker.ymlDOCKERDeploy Docker engine
juice.ymlJUICEDeploy/remove JuiceFS instances
vibe.ymlVIBEDeploy VIBE dev environment
kafka.ymlKAFKACreate or converge a complete dynamic KRaft cluster
kafka-rm.ymlKAFKARemove a Kafka cluster, or safely retire a single member
mysql.ymlMYSQLConverge a native MySQL 8.4 single node or three-node InnoDB Cluster (pilot)
mysql-rm.ymlMYSQLStop or retire a native MySQL instance or cluster while preserving local state (pilot)

Auxiliary Playbooks

The following playbooks are cross-module helpers.

PlaybookDescription
cache.ymlBuild offline installation package cache
cert.ymlIssue certificates using Pigsty CA
app.ymlInstall Docker Compose app templates
slim.ymlMinimal component installation scenario

Playbook Usage Notes

Protection Mechanism

Several modules provide deletion safeguards through *_safeguard parameters:

The PGSQL, ETCD, MINIO, REDIS, and KAFKA role defaults are explicitly false; set them to true for initialized production clusters. Native MySQL is the exception: mysql_safeguard defaults to true, and even after disabling it you must provide a mysql_rm_confirm value that exactly matches the target instance or cluster.

When safeguard is true, corresponding *-rm.yml playbooks abort immediately. You can force override via CLI:

./pgsql-rm.yml -l pg-test -e pg_safeguard=false
./etcd-rm.yml  -l etcd -e etcd_safeguard=false
./minio-rm.yml -l minio -e minio_type=silo -e minio_safeguard=false
./redis-rm.yml -l redis-test -e redis_safeguard=false
./kafka-rm.yml -l kf-main -e kafka_safeguard=false
./mysql-rm.yml -l my-test -e mysql_safeguard=false -e mysql_rm_confirm=my-test

Limiting Execution Scope

Use -l to limit execution targets:

./pgsql.yml -l pg-meta            # run only on pg-meta cluster
./node.yml -l 10.10.10.10         # run only on one node
./redis.yml -l redis-test         # run only on redis-test cluster

For large-scale rollout, validate on one cluster first, then deploy in batches.

Idempotency

Most playbooks are idempotent and safe to rerun, with caveats:

  • infra.yml does not clean data by default; all clean parameters (vmetrics_clean, vlogs_clean, vtraces_clean, grafana_clean, nginx_clean) default to false
  • To rebuild from a clean state, explicitly set relevant clean parameters to true
  • Re-running *-rm.yml deletion playbooks requires extra caution

Task Tags

Use -t to run only selected task subsets:

./pgsql.yml -l pg-test -t pg_service    # refresh services only on pg-test
./node.yml -t haproxy                   # configure haproxy only
./etcd.yml -t etcd_launch               # restart etcd only

Quick Command Reference

INFRA Module

./deploy.yml                     # deploy the core chain in one pass
./infra.yml                      # initialize infrastructure
./infra-rm.yml                   # remove infrastructure components
./cache.yml -l <infra-host>      # build an offline package from an existing repo on an Infra node
./cert.yml -e cn=<name>          # issue client certificate

NODE Module

./node.yml -l <cls|ip>           # add node
./node-rm.yml -l <cls|ip>        # remove node
bin/node-add <cls|ip>            # add node (wrapper)
bin/node-rm <cls|ip>             # remove node (wrapper)

ETCD Module

./etcd.yml                       # initialize etcd cluster
./etcd-rm.yml -l etcd            # remove etcd cluster; deletes local data and configuration by default
bin/etcd-add <ip>                # add etcd member (wrapper)
bin/etcd-rm <ip>                 # remove etcd member (wrapper)

PGSQL Module

./pgsql.yml -l <cls>                             # initialize PostgreSQL cluster
./pgsql-rm.yml -l <cls>                          # remove PostgreSQL cluster
./pgsql-user.yml -l <cls> -e username=<user>     # create business user
./pgsql-db.yml -l <cls> -e dbname=<db>           # create business database
./pgsql-monitor.yml -e clsname=<cls>             # monitor remote cluster
./pgsql-migration.yml -e@files/migration/<cls>.yml  # generate migration runbook
./pgsql-pitr.yml -l <cls> -e '{"pg_pitr": {}}'  # perform PITR recovery

bin/pgsql-add <cls>              # initialize cluster (wrapper)
bin/pgsql-rm <cls>               # remove cluster (wrapper)
bin/pgsql-user <cls> <user>      # create user (wrapper)
bin/pgsql-db <cls> <db>          # create database (wrapper)
bin/pgsql-svc <cls>              # refresh services (wrapper)
bin/pgsql-hba <cls>              # reload HBA (wrapper)
bin/pgmon-add <cls>              # monitor remote cluster (wrapper)

REDIS Module

./redis.yml -l <cls>             # initialize Redis cluster
./redis-rm.yml -l <cls>          # remove Redis cluster

MINIO Module

./minio.yml -l <cls>                       # initialize the MINIO module's Silo cluster
./minio-rm.yml -l <cls> -e minio_type=silo # remove Silo; this value must be confirmed explicitly

DOCKER Module

./docker.yml -l <host>           # install Docker
./app.yml -e app=<name>          # deploy Docker Compose app

KAFKA Module

./kafka.yml -l <cls>             # create / converge a complete Kafka cluster
./kafka.yml -l <cls> --check     # read-only precheck
./kafka-rm.yml -l <cls>          # remove the whole cluster
./kafka-rm.yml -l <ip>           # retire a single member from the cluster

For ordinary convergence, -l must cover every declared member of the selected Kafka cluster; only kafka-rm.yml accepts a single member, for retirement.

MYSQL Pilot Module

./mysql.yml -l <cls> --check
./mysql.yml -l <cls>             # accepts only a complete 1- or 3-member cluster scope
./mysql-rm.yml -l <instance> --check \
  -e mysql_safeguard=false -e mysql_rm_confirm=<instance>
./mysql-rm.yml -l <cls> \
  -e mysql_safeguard=false -e mysql_rm_confirm=<cls>

mysql-rm.yml stops the service, writes a retirement marker, and deregisters monitoring, but does not delete data directories, backups, configuration, certificates, packages, or InnoDB Cluster metadata.

5.6 - Port List

Default ports used by Pigsty components, with related parameters and status.

This page lists default ports used by Pigsty module components. Adjust as needed or use as a reference for fine-grained firewall configuration.

ModuleComponentPortParameterStatus
NODEnode_exporter9100node_exporter_portEnabled
NODEhaproxy9101haproxy_exporter_portEnabled
NODEvector9598vector_portEnabled
NODEkeepalived_exporter9650vip_exporter_portOptional
NODEchronyd123-Enabled
DOCKERdocker9323docker_exporter_portOptional
INFRAnginx80nginx_portEnabled
INFRAnginx443nginx_ssl_portEnabled
INFRAnginx_exporter9113nginx_exporter_portEnabled
INFRAgrafana3000grafana_portEnabled
INFRAvictoriaMetrics8428vmetrics_portEnabled
INFRAvictoriaLogs9428vlogs_portEnabled
INFRAvictoriaTraces10428vtraces_portEnabled
INFRAvmalert8880vmalert_portEnabled
INFRAalertmanager9059alertmanager_portEnabled
INFRAblackbox_exporter9115blackbox_portEnabled
INFRAdnsmasq53dns_portEnabled
ETCDetcd2379etcd_portEnabled
ETCDetcd2380etcd_peer_portEnabled
MINIOSilo S3 API9000minio_portOptional
MINIOSilo admin port9001minio_admin_portOptional
REDISRedis / Valkey6379redis_instancesOptional
REDISredis_exporter9121redis_exporter_portOptional
VIBEcode-server8443code_portOptional
VIBEjupyterlab8888jupyter_portOptional
KAFKAbroker9092kafka_port🧪 BETA
KAFKAKRaft controller9093kafka_controller_port🧪 BETA
KAFKAkafka_exporter9308kafka_exporter_port🧪 BETA
KAFKAJMX exporter9404kafka_jmx_exporter_port🧪 BETA
MYSQLmysqld3306Fixed value (the current pilot exposes no port parameter)🧪 PILOT
MYSQLMySQL X Protocol33060Fixed value; loopback-only on a single node, member-facing in a 3-node topology🧪 PILOT
MYSQLGroup Replication33061Fixed value; three-node InnoDB Cluster only🧪 PILOT
MYSQLMySQL Router RW6446Fixed value; three-node InnoDB Cluster only🧪 PILOT
MYSQLMySQL Router RO6447Fixed value; three-node InnoDB Cluster only🧪 PILOT
MYSQLmysqld_exporter9104Fixed value; controlled by mysql_exporter_enabled🧪 PILOT
PGSQLpostgres5432pg_portEnabled
PGSQLpgbouncer6432pgbouncer_portEnabled
PGSQLpatroni8008patroni_portEnabled
PGSQLpg_exporter9630pg_exporter_portEnabled
PGSQLpgbouncer_exporter9631pgbouncer_exporter_portEnabled
PGSQLpgbackrest_exporter9854pgbackrest_exporter_portEnabled
PGSQL{{ pg_cluster }}-primary5433pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-replica5434pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-default5436pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-offline5438pg_default_servicesEnabled
PGSQL{{ pg_cluster }}-<service>543xpg_servicesOptional

The native MySQL pilot reuses port 3306 for MySQL Shell AdminAPI. XtraBackup is invoked by a local systemd timer and has no listening port, while the role explicitly disables the MySQL Router REST management interface. The table lists only network endpoints currently managed by the role.

Public Port Recommendations

If you use firewall zone mode, expose only minimum required ports via node_firewall_public_port:

  • Minimal management surface: 22, 80, 443 (recommended)
  • If public direct DB access is required: additionally expose 5432

Avoid exposing internal component ports directly to the public internet: etcd (2379/2380), patroni (8008), exporters (9xxx), object-storage S3/admin endpoints (9000/9001), redis (6379), ferretdb (27017/27018), Kafka (9092/9093), MySQL Group Replication (33061), etc.

node_firewall_mode: zone
node_firewall_public_port: [22, 80, 443]
# node_firewall_public_port: [22, 80, 443, 5432]  # only if public DB access is required

6 - Applications

Pigsty application templates and data applets: run stateless apps with Docker Compose and host state in external PostgreSQL and S3-compatible storage.

Pigsty “applications” fall into two categories:

  • Software Templates: Docker Compose templates under ~/pigsty/app/<name> for stateless business components.
  • Data Applets: PostgreSQL + Grafana analytics demos, mainly for learning and showcase use.

Application Model

The recommended application deployment workflow is:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c <template>     # e.g. app/dify, app/immich, app/jumpserver, app/maybe, supabase
vi pigsty.yml                 # edit passwords, domains, IPs, and secrets
./deploy.yml                  # deploy infrastructure and databases
./docker.yml                  # install Docker
./app.yml                     # launch applications

app.yml copies app/<name> templates to /opt/<name>, overwrites .env with apps.<name>.conf, then runs docker compose up -d.

Maintained Config Templates

The following app config templates are actively maintained (conf/app/*.yml, conf/supabase.yml, and the conf/app/supa.yml symlink):

  • app/dify
  • app/odoo
  • app/teable
  • app/mattermost
  • app/electric
  • app/maybe
  • app/immich
  • app/jumpserver
  • app/registry
  • app/insforge
  • app/hindsight
  • supabase

These templates work out of the box and align with the ./configure -c ... + ./app.yml workflow.

Lightweight Compose Apps

For apps like bytebase, gitea, jupyter, kong, metabase, minio, nocodb, pgadmin, pgweb, postgrest, pg_exporter, and wiki, you can also use the per-app Compose templates directly.

FerretDB is provided as the Docker APP layer of PostgreSQL Mongo mode. Deploy it from the mongo configuration template with docker.yml and app.yml.

cd ~/pigsty/app/<name>
make up

If you want to manage them uniformly via Pigsty IaC:

./app.yml -e app=<name>

Legacy Applets

Data applets like pglog, covid, db-engine, sf-survey, cloud, and isd are kept as reference examples for data modeling and visualization ideas.

They are no longer the primary application delivery path. Prefer the software template workflow above.

6.1 - Enterprise Self-Hosted Supabase

Self-host enterprise-grade Supabase with Pigsty, featuring monitoring, high availability, PITR, IaC, and 575 PostgreSQL extensions.

Supabase is great, but having your own Supabase is even better. Pigsty can help you deploy enterprise-grade Supabase on your own servers (physical, virtual, or cloud) with a single command — more extensions, better performance, deeper control, and more cost-effective.

As of August 2026, the official Supabase self-hosting guide recommends Docker and classifies other implementations as community projects. Pigsty is an independent community integration and is not currently listed on that page.

This tutorial requires basic Linux knowledge. Otherwise, consider using Supabase cloud or plain Docker Compose self-hosting.


TL;DR

Prepare a Linux server, follow the Pigsty standard single-node installation process with the supabase config template:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./configure -c supabase    # Use supabase config (change credentials in pigsty.yml)
vi pigsty.yml              # Edit domain, passwords, keys...
./deploy.yml               # Standard single-node Pigsty deployment
./docker.yml -l supabase   # Install Docker on the supabase group
./app.yml -l supabase      # Start stateless containers on the supabase group (may be slow)

After installation, access Supa Studio on port 8000 with username supabase and password pigsty.

Supabase
demo/supabase.cast

Checklist


Table of Contents


What is Supabase?

Supabase is a BaaS (Backend as a Service), an open-source Firebase alternative, and the most popular database + backend solution in the AI Agent era. Supabase wraps PostgreSQL and provides authentication, messaging, edge functions, object storage, and automatically generates REST APIs based on your database schema. After enabling pg_graphql on demand, it can also provide GraphQL APIs.

Supabase aims to provide developers with a one-stop backend solution, reducing the complexity of developing and maintaining backend infrastructure. It allows developers to skip most backend development work — you only need to understand database design and frontend to ship quickly! Developers can use vibe coding to create a frontend and database schema to rapidly build complete applications.

Supabase is one of the most popular open-source projects in the PostgreSQL ecosystem. As of August 2026, its GitHub repository has more than 100,000 stars. Supabase also offers a free hosted tier. The current Free plan includes shared CPU, 500 MB of RAM, a 500 MB database quota, and 1 GB of file storage; consult the official page for later changes.


Why Self-Host?

If Supabase cloud is so attractive, why self-host?

The most obvious reason is what we discussed in “Is Cloud Database an IQ Tax?”: costs can rise quickly once data, compute, or availability requirements outgrow a managed-service tier. And nowadays, reliable local enterprise NVMe SSDs have three to four orders of magnitude cost advantage over cloud storage, and self-hosting can better leverage this.

Another important reason is functionality — Supabase cloud features are limited. Many powerful PostgreSQL extensions aren’t available in cloud services due to multi-tenant security challenges and licensing. Despite extensions being a core PostgreSQL feature, Supabase currently promises only more than 50 preconfigured extensions; the exact list changes with platform releases. Self-hosted Supabase with Pigsty provides up to 576 ready-to-use PostgreSQL extensions.

Additionally, self-control and vendor lock-in avoidance are important reasons for self-hosting. Although Supabase aims to provide a vendor-lock-free open-source Google Firebase alternative, self-hosting enterprise-grade Supabase is not trivial. Supabase includes PostgreSQL extensions that it develops and maintains. It acquired the Oriole team in 2024 and offers OrioleDB as an optional Public Alpha; OrioleDB is not the production default and should not be described as a confirmed replacement for native PostgreSQL. Some Supabase extensions and patched kernels are not distributed by the official PGDG repository.

This is implicit vendor lock-in, preventing users from self-hosting in ways other than the supabase/postgres Docker image. Pigsty provides an open, transparent, and universal solution. We package the 10 missing Supabase extensions as ready-to-use RPM/DEB packages for the current supabase template matrix: EL 8/9, Debian 12, and Ubuntu 22.04/24.04/26.04 on x86_64 and aarch64. See supported Linux distributions.

ExtensionDescription
pg_graphqlGraphQL support in PostgreSQL (Rust), provided by PIGSTY, enabled on demand
pg_jsonschemaJSON Schema validation (Rust), provided by PIGSTY
wrappersSupabase foreign data wrapper bundle (Rust), provided by PIGSTY
index_advisorQuery index advisor (SQL), provided by PIGSTY
pg_netAsync non-blocking HTTP/HTTPS requests (C), provided by PIGSTY
vaultStore encrypted credentials in Vault (C), provided by PIGSTY
pgjwtJSON Web Token API implementation (SQL), provided by PIGSTY
pgsodiumTable data encryption TDE, provided by PIGSTY
supautilsSecurity utilities for cloud environments (C), provided by PIGSTY
pg_plan_filterFilter queries by execution plan cost (C), provided by PIGSTY

We also install most extensions by default in Supabase deployments. You can enable them as needed. Newer templates install the pg_graphql package but no longer create the pg_graphql extension object by default. If you need GraphQL APIs, run CREATE EXTENSION IF NOT EXISTS pg_graphql; in the target database; the event trigger in the template will rebuild the graphql_public.graphql entry point and permissions.

Pigsty also handles the underlying highly available PostgreSQL cluster, highly available Silo object storage cluster, and even Docker deployment, Nginx reverse proxy, domain configuration, and HTTPS certificate issuance. You can spin up any number of stateless Supabase container clusters using Docker Compose and store state in external Pigsty-managed database services.

With this self-hosted architecture, you can choose among the PostgreSQL majors supported by the current template (15-18, default 18), install 576 extensions, and scale Supabase, PostgreSQL, and Silo independently. Compared with a managed service, you also assume responsibility for operating and securing that infrastructure.


Single-Node Quick Start

Let’s start with single-node Supabase deployment. We’ll cover multi-node high availability later.

Prepare a fresh Linux server, use the Pigsty supabase configuration template for standard installation, then run docker.yml and app.yml to start stateless Supabase containers (default ports 8000/8443).

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./configure -c supabase    # Use supabase config (change credentials in pigsty.yml)
vi pigsty.yml              # Edit domain, passwords, keys...
./deploy.yml               # Install Pigsty
./docker.yml -l supabase   # Install Docker on the supabase group
./app.yml -l supabase      # Start stateless containers on the supabase group

Before deploying Supabase, modify the auto-generated pigsty.yml configuration file (domain and passwords) according to your needs. For local development/testing, you can skip this and customize later.

If configured correctly, after about ten minutes, you can access the Supabase Studio GUI at http://<your_ip_address>:8000 on your local network. Default username and password are supabase and pigsty.

Supabase

Notes:

  • In mainland China, Pigsty uses 1Panel and 1ms DockerHub mirrors by default, which may be slow.
  • You can configure your own proxy and registry mirror, then manually pull images with cd /opt/supabase; docker compose pull. We also offer expert consulting services including complete offline installation packages.
  • If you need object storage functionality, you must access Supabase via domain and HTTPS, otherwise errors will occur.
  • For serious production deployments, always change all default passwords!

Key Technical Decisions

Here are some key technical decisions for self-hosting Supabase:

Single-node deployment doesn’t provide PostgreSQL/Silo high availability. However, single-node deployment still has significant advantages over the official pure Docker Compose approach: out-of-the-box monitoring, freedom to install extensions, component scaling capabilities, and point-in-time recovery as a safety net.

Pigsty’s Supabase template does not start the upstream Compose db or supavisor containers, and does not use Supabase’s bundled connection pooler. Stateless containers connect directly to the PostgreSQL service managed by Pigsty; the single-node template uses service port 5436 by default, which always routes to the current primary.

Logflare / Analytics in the template no longer writes to postgres._analytics in the application database. Instead, it uses the separate _supabase database and its _analytics schema. This prevents internal scheduling tables such as oban_jobs and oban_peers from being created in the project database’s public schema and triggering Supabase Advisor RLS warnings. LOGFLARE_DB and LOGFLARE_SCHEMA control these locations.

The Query Performance page in Supabase Studio accesses pg_stat_statements with a public, extensions search path. Pigsty keeps the pg_stat_statements extension objects in the monitor schema for compatibility with pg_exporter and existing monitoring dashboards. The template creates a compatibility view and functions in the extensions schema for Studio.

If you only have one server or choose to self-host on cloud servers, Pigsty recommends using external S3 instead of local Silo for object storage to hold PostgreSQL backups and Supabase Storage. This provides an hour-scale recovery path after a single-node failure. Actual RPO depends on the newest recoverable backup, WAL archiving state, and object-storage availability; the topology alone does not guarantee a fixed value.

For serious production deployments, Pigsty recommends at least 3-4 nodes, ensuring both Silo and PostgreSQL use enterprise-grade multi-node high availability deployments. You’ll need more nodes and disks, adjusting cluster configuration in pigsty.yml and Supabase cluster configuration to use high availability endpoints.

Some Supabase features require sending emails, so SMTP service is needed. Unless purely for internal use, production deployments should use SMTP cloud services. Self-hosted mail servers’ emails are often marked as spam.

If your service is directly exposed to the public internet, we strongly recommend using real domain names and HTTPS certificates via Nginx Portal.

Next, we’ll discuss advanced topics for improving Supabase security, availability, and performance beyond single-node deployment.


Advanced: Security Hardening

Pigsty Components

For serious production deployments, we strongly recommend changing Pigsty component passwords. These defaults are public and well-known — going to production without changing passwords is like running naked:

These are Pigsty component passwords. Strongly recommended to set before installation.

Supabase Keys

Besides Pigsty component passwords, you need to change Supabase keys, including:

Please follow the Supabase tutorial: Securing your services:

  • Generate a JWT_SECRET with at least 40 characters, then use the tutorial tools to issue ANON_KEY and SERVICE_ROLE_KEY JWTs.
  • Use the tutorial tools to generate an ANON_KEY JWT based on JWT_SECRET and expiration time — this is the anonymous user credential.
  • Use the tutorial tools to generate a SERVICE_ROLE_KEY — this is the higher-privilege service role credential.
  • If you use newer opaque API keys or asymmetric JWTs, also generate and fill SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY, JWT_KEYS, JWT_JWKS, and the corresponding asymmetric ANON_KEY / SERVICE_ROLE_KEY.
  • Specify a random string of at least 32 characters for PG_META_CRYPTO_KEY to encrypt Studio UI and meta service interactions.
  • SECRET_KEY_BASE must be at least 64 characters; REALTIME_DB_ENC_KEY must be exactly 16 characters.
  • Generate separate random credentials for S3_PROTOCOL_ACCESS_KEY_ID and S3_PROTOCOL_ACCESS_KEY_SECRET; do not reuse an object-storage administrator password.
  • If using different PostgreSQL business user passwords, modify POSTGRES_PASSWORD accordingly.
  • If your object storage uses different passwords, modify S3_ACCESS_KEY and S3_SECRET_KEY accordingly.
  • If Edge Functions are exposed to untrusted clients, set FUNCTIONS_VERIFY_JWT to true as needed.
  • API_EXTERNAL_URL should now be the external Auth service URL, retaining the /auth/v1 suffix, for example https://supa.pigsty.io/auth/v1; keep SITE_URL and SUPABASE_PUBLIC_URL at the site root URL.
  • The current template defaults PGRST_DB_SCHEMAS to public,graphql_public; the storage schema is used by the Storage API and is no longer exposed through PostgREST by default.

After modifying Supabase credentials, restart Docker Compose to apply:

./app.yml -l supabase -t app_config,app_launch   # Using playbook
cd /opt/supabase; make up            # Manual execution

Advanced: Domain Configuration

If using Supabase locally or on LAN, you can directly connect to Kong’s HTTP port 8000 via IP:Port.

You can use an internal static-resolved domain, but for serious production deployments, we recommend using a real domain + HTTPS to access Supabase. In this case, your server should have a public IP, you should own a domain, use cloud/DNS/CDN provider’s DNS resolution to point to the node’s public IP (optional fallback: local /etc/hosts static resolution).

The simple approach is to batch-replace the placeholder domain (supa.pigsty) with your actual domain, e.g., supa.pigsty.io:

sed -ie 's/supa.pigsty/supa.pigsty.io/g' ~/pigsty/pigsty.yml

If not configured beforehand, reload Nginx and Supabase configuration:

make cert       # Request certbot free HTTPS certificate
./app.yml -l supabase -t app_config,app_launch  # Reload Supabase configuration

The modified configuration should look like:

all:
  vars:
    certbot_sign: true                # Use certbot to sign real certificates
    infra_portal:
      home: { domain: i.pigsty.io }   # Replace with your domain!
      supa:
        domain: supa.pigsty.io        # Replace with your domain!
        endpoint: "10.10.10.10:8000"
        websocket: true
        certbot: supa.pigsty.io       # Certificate name, usually same as domain

  children:
    supabase:
      vars:
        apps:
          supabase:                                         # Supabase app definition
            conf:                                           # Override /opt/supabase/.env
              SITE_URL: https://supa.pigsty.io              # <------- Change to your external domain name
              API_EXTERNAL_URL: https://supa.pigsty.io/auth/v1 # <--- Auth external URL; keep /auth/v1
              SUPABASE_PUBLIC_URL: https://supa.pigsty.io   # <------- Don't forget to set this in infra_portal!

For complete domain/HTTPS configuration, see Certificate Management. You can also use Pigsty’s built-in local static resolution and self-signed HTTPS certificates as fallback.


Advanced: External Object Storage

You can use S3 or S3-compatible services for PostgreSQL backups and Supabase object storage. Here we use Alibaba Cloud OSS as an example.

Pigsty provides a terraform/spec/aliyun-s3.tf template for provisioning a server and OSS bucket on Alibaba Cloud.

First, modify the S3 configuration in all.children.supabase.vars.apps.supabase.conf to point to Alibaba Cloud OSS:

# if using s3/minio as file storage
S3_BUCKET: pigsty-supa                     # Legacy compatibility; keep aligned with GLOBAL_S3_BUCKET
GLOBAL_S3_BUCKET: pigsty-supa              # Bucket actually used by Supabase Storage
S3_ENDPOINT: https://oss-cn-beijing.aliyuncs.com
S3_ACCESS_KEY: <your_access_key>
S3_SECRET_KEY: <your_secret_key>
S3_FORCE_PATH_STYLE: false                 # Alibaba Cloud OSS uses host-style URIs
S3_PROTOCOL: https
S3_REGION: oss-cn-beijing                  # Legacy compatibility; keep aligned with REGION
REGION: oss-cn-beijing                     # Region actually used by Supabase Storage
STORAGE_TENANT_ID: pigsty                  # Supabase Storage tenant id
S3_PROTOCOL_ACCESS_KEY_ID: <independent_access_key>
S3_PROTOCOL_ACCESS_KEY_SECRET: <independent_secret_key>

Reload Supabase configuration:

./app.yml -l supabase -t app_config,app_launch

You can also use S3 as PostgreSQL backup repository. Add an aliyun backup repository definition in all.vars.pgbackrest_repo:

all:
  vars:
    pgbackrest_method: aliyun          # pgbackrest backup method: local,minio,[user-defined repos...]
    pgbackrest_repo:                   # pgbackrest backup repo: https://pgbackrest.org/configuration.html#section-repository
      aliyun:                          # Define new backup repo 'aliyun'
        type: s3                       # Alibaba Cloud OSS is S3-compatible
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: pigsty-oss
        s3_key: xxxxxxxxxxxxxx
        s3_key_secret: xxxxxxxx
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest.MyPass    # Set encryption password for pgBackRest backup repo
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days

Then select aliyun with all.vars.pgbackrest_method. Check the current backup first, run check mode, and only after explicit authorization re-render pgBackRest configuration on the named cluster, initialize the stanza, and establish a new full recovery point:

pig pb info
./pgsql.yml -t pg_backup -l pg-meta
pg-backup full

Backups in the old repository are not migrated automatically, and a recovery-window gap remains until the first full backup in the new repository succeeds. See Switching Repositories for the complete procedure.


Advanced: Using SMTP

You can use SMTP for sending emails. Modify the supabase app configuration with SMTP information:

all:
  children:
    supabase:        # supa group
      vars:          # supa group vars
        apps:        # supa group app list
          supabase:  # the supabase app
            conf:    # the supabase app conf entries
              SMTP_HOST: smtpdm.aliyun.com
              SMTP_PORT: 80
              SMTP_USER: [email protected]
              SMTP_PASS: your_email_user_password
              SMTP_SENDER_NAME: MySupabase
              SMTP_ADMIN_EMAIL: [email protected]
              ENABLE_ANONYMOUS_USERS: false

Reload the configuration with ./app.yml -l supabase -t app_config,app_launch.


Advanced: True High Availability

After these configurations, you have enterprise-grade Supabase with public domain, HTTPS certificate, SMTP, PITR backup, monitoring, IaC, and access to 576 PostgreSQL extensions (basic single-node version). For high availability configuration, see other Pigsty documentation. We offer expert consulting services for hands-on Supabase self-hosting — $400 USD to save you the hassle.

Single-node RTO/RPO relies on external object storage as a safety net. If your node fails, backups in external S3 storage let you redeploy Supabase on a new node and restore from backup. This provides an hour-scale recovery fallback, but RPO depends on the actual backup and WAL-archive state and must be proven through restore drills. “MB-level” is not a fixed guarantee.

For a target RTO below 30 seconds while preserving acknowledged transactions, use multi-node, explicitly select the fast RTO preset and the crit.yml strict-synchronous policy, and validate them with failure drills. The default norm preset targets RTO below 45 seconds, while asynchronous replication does not promise RPO=0:

  • ETCD: DCS needs three or more nodes to tolerate one node failure.
  • PGSQL: PostgreSQL synchronous commit (no data loss) mode recommends at least three nodes.
  • INFRA: Monitoring infrastructure failure has less impact; production recommends dual replicas.
  • Supabase stateless containers can also be multi-node replicas for high availability.

In this case, you also need to modify PostgreSQL and Silo endpoints to use DNS / L2 VIP / HAProxy high availability endpoints. For these parts, follow the documentation for each Pigsty module. Reference conf/ha/trio.yml and conf/ha/safe.yml for upgrading to three or more nodes.

6.2 - Odoo: Self-Hosted Open Source ERP

How to spin up an out-of-the-box enterprise application suite Odoo and use Pigsty to manage its backend PostgreSQL database.

Odoo is an open-source enterprise resource planning (ERP) software that provides a full suite of business applications, including CRM, sales, purchasing, inventory, production, accounting, and other management functions. Odoo is a typical web application that uses PostgreSQL as its underlying database.

All your business on one platform — Simple, efficient, yet affordable

Public Demo (may not always be available): http://odoo.pigsty.io, username: [email protected], password: pigsty


Quick Start

On a fresh Linux x86/ARM server running a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap                # Install Ansible
./configure -c app/odoo    # Use Odoo configuration (change credentials in pigsty.yml)
./deploy.yml               # Install Pigsty
./docker.yml               # Install Docker Compose
./app.yml                  # Start Odoo stateless components with Docker

Odoo listens on port 8069 by default. Access http://<ip>:8069 in your browser. The default username and password are both admin.

You can add a DNS resolution record odoo.pigsty pointing to your server in the browser host’s /etc/hosts file, allowing you to access the Odoo web interface via http://odoo.pigsty.

If you want to access Odoo via SSL/HTTPS, you need to use a real SSL certificate or trust the self-signed CA certificate automatically generated by Pigsty. (In Chrome, you can also type thisisunsafe to bypass certificate verification)


Configuration Template

conf/app/odoo.yml defines a template configuration file containing the resources required for a single Odoo instance.

all:
  children:

    # Odoo application (default username and password: admin/admin)
    odoo:
      hosts: { 10.10.10.10: {} }
      vars:
        app: odoo   # Specify app name to install (in apps)
        apps:       # Define all applications
          odoo:     # App name, should have corresponding ~/pigsty/app/odoo folder
            file:   # Optional directories to create
              - { path: /data/odoo         ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/webdata ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/addons  ,state: directory, owner: 100, group: 101 }
            conf:   # Override /opt/<app>/.env config file
              PG_HOST: 10.10.10.10            # PostgreSQL host
              PG_PORT: 5432                   # PostgreSQL port
              PG_USERNAME: odoo               # PostgreSQL user
              PG_PASSWORD: DBUser.Odoo        # PostgreSQL password
              ODOO_PORT: 8069                 # Odoo app port
              ODOO_DATA: /data/odoo/webdata   # Odoo webdata
              ODOO_ADDONS: /data/odoo/addons  # Odoo plugins
              ODOO_DBNAME: odoo               # Odoo database name
              ODOO_VERSION: 19.0              # Odoo image version

    # Odoo database
    pg-odoo:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-odoo
        pg_users:
          - { name: odoo    ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_admin ] ,createdb: true ,comment: admin user for odoo service }
          - { name: odoo_ro ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readonly ]  ,comment: read only user for odoo service  }
          - { name: odoo_rw ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readwrite ] ,comment: read write user for odoo service }
        pg_databases:
          - { name: odoo ,owner: odoo ,revokeconn: true ,comment: odoo main database  }
        pg_hba_rules:
          - { user: all ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow access from local docker network' }
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # Full backup daily at 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # Global variables
    admin_ip: 10.10.10.10             # Admin node IP address
    region: default                   # Upstream mirror region: default|china|europe
    node_tune: oltp                   # Node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # PGSQL tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # Enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # Global proxy env for downloading packages & pulling docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345   # Add proxy env here for downloading packages or pulling images
      #https_proxy: 127.0.0.1:12345   # Usually format is http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                      # Domain names and upstream servers
      home  : { domain: i.pigsty }
      minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      odoo:                            # Nginx server config for odoo
        domain: odoo.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8069"   # Odoo service endpoint: IP:PORT
        websocket: true                # Add websocket support
        certbot: odoo.pigsty           # Certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------#
    # Credentials: MUST CHANGE THESE!
    #----------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

Basics

Check the configurable environment variables in the .env file:

# https://hub.docker.com/_/odoo#
PG_HOST=10.10.10.10
PG_PORT=5432
PG_USER=dbuser_odoo
PG_PASS=DBUser.Odoo
ODOO_PORT=8069

Then start Odoo with:

make up  # docker compose up

Access http://odoo.pigsty or http://10.10.10.10:8069

Makefile

make up         # Start Odoo with docker compose in minimal mode
make run        # Start Odoo with docker, local data directory and external PostgreSQL
make view       # Print Odoo access endpoints
make log        # tail -f Odoo logs
make info       # Inspect Odoo with jq
make stop       # Stop Odoo container
make clean      # Remove Odoo container
make pull       # Pull latest Odoo image
make rmi        # Remove Odoo image
make save       # Save Odoo image to /tmp/docker/odoo.tgz
make load       # Load Odoo image from /tmp/docker/odoo.tgz

Using External PostgreSQL

You can use external PostgreSQL for Odoo. Odoo will create its own database during setup, so you don’t need to do that.

pg_users: [ { name: dbuser_odoo ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: admin user for odoo database } ]
pg_databases: [ { name: odoo ,owner: dbuser_odoo ,revokeconn: true ,comment: odoo primary database } ]

Create the business user and database with:

bin/pgsql-user  pg-meta  dbuser_odoo
#bin/pgsql-db    pg-meta  odoo     # Odoo will create the database during setup

Check connectivity:

psql postgres://dbuser_odoo:[email protected]:5432/odoo

Expose Odoo Service

Expose the Odoo web service via Nginx portal:

    infra_portal:                     # Domain names and upstream servers
      home         : { domain: i.pigsty }
      odoo         : { domain: odoo.pigsty, endpoint: "127.0.0.1:8069", websocket: true }  # <------ Add this line
./infra.yml -t nginx   # Setup nginx infra portal

Odoo Addons

There are many Odoo modules available in the community. You can install them by downloading and placing them in the addons folder.

volumes:
  - ./addons:/mnt/extra-addons

You can mount the ./addons directory to /mnt/extra-addons in the container, then download and extract addons to the addons folder.

To enable addon modules, first enter Developer mode:

Settings -> General Settings -> Developer Tools -> Activate the developer mode

Then go to Apps -> Update Apps List, and you’ll find the extra addons available to install from the panel.

Frequently used free addons: Accounting Kit


Demo

Check the public demo: http://odoo.pigsty.io, username: [email protected], password: pigsty

If you want to access Odoo via SSL, you must trust files/pki/ca/ca.crt in your browser (or use the dirty hack thisisunsafe in Chrome).

6.3 - Dify: AI Workflow Platform

How to self-host the AI Workflow LLMOps platform — Dify, using external PostgreSQL, PGVector, and Redis for storage with Pigsty?

Dify is a Generative AI Application Innovation Engine and open-source LLM application development platform. It provides capabilities from Agent building to AI workflow orchestration, RAG retrieval, and model management, helping users easily build and operate generative AI native applications.

Pigsty provides support for self-hosted Dify, allowing you to deploy Dify with a single command while storing critical state in externally managed PostgreSQL. You can use pgvector as a vector database in the same PostgreSQL instance, further simplifying deployment.

app/dify template latest verified Dify version: v1.15.0 (2026-07-09). The template includes a Dify migration compatibility patch for PostgreSQL 18’s built-in uuidv7().


Quick Start

On a fresh Linux x86/ARM server running a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap                # Install Pigsty dependencies
./configure -c app/dify    # Use Dify configuration template
vi pigsty.yml              # Edit passwords, domains, keys, etc.

./deploy.yml               # Install Pigsty
./docker.yml               # Install Docker and Compose
./app.yml                  # Install Dify

Dify listens on port 5001 by default. Access http://<ip>:5001 in your browser and set up your initial user credentials to log in.

Once Dify starts, you can install various extensions, configure system models, and start using it!


Why Self-Host

There are many reasons to self-host Dify, but the primary motivation is data security. The Docker Compose template provided by Dify uses basic default database images, lacking enterprise features like high availability, disaster recovery, monitoring, IaC, and PITR capabilities.

Pigsty provides declarative Dify deployment and can use mirrors to address image access in China. The template puts PostgreSQL and pgvector under Pigsty management and deploys Compose Redis, VictoriaMetrics/Grafana monitoring, and an Nginx reverse proxy. It can request a Let’s Encrypt certificate after public DNS, ports, and Certbot are configured. Files are stored in DIFY_DATA (/data/dify) by default, with optional Silo/S3 object storage.

The current template places PostgreSQL/pgvector in an externally managed Pigsty database and directs API files and plugin data to DIFY_DATA (/data/dify by default). However, the built-in Compose Redis data remains under /opt/dify/volumes/redis/data, while Sandbox dependencies and Certbot data are also stored under /opt/dify/volumes/. The complete application stack is therefore not fully stateless, and a backup cannot retain only the database.


Installation

Let’s start with single-node Dify deployment. We’ll cover production high-availability deployment methods later.

First, use Pigsty’s standard installation process to install the PostgreSQL instance required by Dify:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap               # Prepare Pigsty dependencies
./configure -c app/dify   # Use Dify application template
vi pigsty.yml             # Edit configuration file, modify domains and passwords
./deploy.yml              # Install Pigsty and various databases

When you use the ./configure -c app/dify command, Pigsty automatically generates a configuration file based on the conf/app/dify.yml template and your current environment. You should modify passwords, domains, and other relevant parameters in the generated pigsty.yml configuration file according to your needs, then run ./deploy.yml to execute the standard installation process.

Next, run docker.yml to install Docker and Docker Compose, then use app.yml to complete Dify deployment:

./docker.yml -l dify      # Install Docker and Docker Compose on Dify nodes
./app.yml -l dify         # Deploy Dify application components with Docker

You can access the Dify Web admin interface at http://<your_ip_address>:5001 on your local network.

The first login will prompt you to set up default username, email, and password.

You can also use the locally resolved placeholder domain dify.pigsty, or follow the configuration below to use a real domain with an HTTPS certificate.


Configuration

When you run ./configure -c app/dify, Pigsty generates a configuration file from the conf/app/dify.yml template and the current environment. The snapshot below matches the v4.5.0 source template:

---
#==============================================================#
# File      :   dify.yml
# Desc      :   pigsty config for running 1-node dify app
# Ctime     :   2025-02-24
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/dify
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Last Verified Dify Version: v1.15.0 on 2026-07-09
# tutorial: https://pigsty.io/docs/app/dify
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/dify   # use this dify config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install dify with docker-compose
#
# To replace domain name:
#   sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml


all:
  children:

    # the dify application
    dify:
      hosts: { 10.10.10.10: {} }
      vars:
        app: dify   # specify app name to be installed (in the apps)
        apps:       # define all applications
          dify:     # app name, should have corresponding ~/pigsty/app/dify folder
            file:   # data directory to be created
              - { path: /data/dify ,state: directory ,mode: 0755 }
            conf:   # override /opt/dify/.env config file

              # change domain, mirror, proxy, secret key
              NGINX_SERVER_NAME: dify.pigsty
              # A secret key for signing and encryption, gen with `openssl rand -base64 42` (CHANGE PASSWORD!)
              SECRET_KEY: sk-somerandomkey
              # expose DIFY nginx service with port 5001 by default
              DIFY_PORT: 5001
              # where to store dify files? the default is ./volume, we'll use another volume created above
              DIFY_DATA: /data/dify
              # enable the upstream websocket sidecar, while keeping PostgreSQL/pgvector external
              COMPOSE_PROFILES: collaboration
              NEXT_PUBLIC_SOCKET_URL: ws://dify.pigsty
              TRIGGER_URL: http://dify.pigsty
              ENDPOINT_URL_TEMPLATE: http://dify.pigsty/e/{hook_id}

              # proxy and mirror settings
              #PIP_MIRROR_URL: https://pypi.tuna.tsinghua.edu.cn/simple
              #SANDBOX_HTTP_PROXY: http://10.10.10.10:12345
              #SANDBOX_HTTPS_PROXY: http://10.10.10.10:12345

              # database credentials
              DB_TYPE: postgresql
              DB_USERNAME: dify
              DB_PASSWORD: difyai123456
              DB_HOST: 10.10.10.10
              DB_PORT: 5432
              DB_DATABASE: dify
              DB_SSL_MODE: disable
              VECTOR_STORE: pgvector
              PGVECTOR_HOST: 10.10.10.10
              PGVECTOR_PORT: 5432
              PGVECTOR_USER: dify
              PGVECTOR_PASSWORD: difyai123456
              PGVECTOR_DATABASE: dify
              PGVECTOR_MIN_CONNECTION: 2
              PGVECTOR_MAX_CONNECTION: 10

              # optional MinIO/S3 storage, disabled by default to avoid touching backup MinIO
              #STORAGE_TYPE: s3
              #S3_ENDPOINT: http://10.10.10.10:9000
              #S3_BUCKET_NAME: dify
              #S3_ACCESS_KEY: dify
              #S3_SECRET_KEY: S3User.Dify
              #S3_REGION: us-east-1
              #S3_ADDRESS_STYLE: path

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_extensions: [ pgvector ]
        pg_users:
          - { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
        pg_databases:
          - { name: dify        ,owner: dify ,extensions: [ { name: vector } ] ,comment: dify main database  }
          - { name: dify_plugin ,owner: dify ,comment: dify plugin daemon database }
        pg_hba_rules:
          - { user: dify ,db: all ,addr: 172.16.0.0/12  ,auth: pwd ,title: 'allow dify access from local docker networks' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home   :  { domain: i.pigsty }
      #minio :  { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      dify:                            # nginx server config for dify
        domain: dify.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5001"   # dify service endpoint: IP:PORT
        websocket: true                # add websocket support
        certbot: dify.pigsty           # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    # Dify v1.15.0 is patched in app/dify/patches for PostgreSQL 18's built-in uuidv7().
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Checklist

Here’s a checklist of configuration items you need to pay attention to:

  • Hardware/Software: Prepare required machine resources: Linux x86_64/arm64 server, fresh installation of a mainstream Linux OS
  • Network/Permissions: SSH passwordless login access, user with sudo privileges without password
  • Ensure the machine has a static IPv4 network address on the internal network and can access the internet
  • If accessing via public network, ensure you have a domain pointing to the node’s public IP address
  • Ensure you use the app/dify configuration template and modify parameters as needed
    • configure -c app/dify, enter the node’s internal primary IP address, or specify via -i <primary_ip> command line parameter
  • In production, have you changed every example password, application secret, and database credential? [Required]
  • Have you changed the PostgreSQL cluster business user password and application configurations using these passwords?
    • Default username dify and password difyai123456 are generated by Pigsty for Dify; modify according to your needs
    • In the Dify configuration block, modify DB_USERNAME, DB_PASSWORD, PGVECTOR_USER, PGVECTOR_PASSWORD accordingly
  • Have you changed Dify’s default encryption key?
    • You can randomly generate a password string with openssl rand -base64 42 and fill in the SECRET_KEY parameter
  • Have you changed the domain used by Dify?
    • Replace placeholder domain dify.pigsty with your actual domain, e.g., dify.pigsty.io
    • You can use sed -ie 's/dify.pigsty/dify.pigsty.io/g' pigsty.yml to modify Dify’s domain

Domain and SSL

If you want to use a real domain with an HTTPS certificate, you need to modify the pigsty.yml configuration file:

  • The dify domain in the infra_portal parameter
  • It’s best to specify an email address certbot_email for certificate expiration notifications
  • Configure Dify’s NGINX_SERVER_NAME parameter to specify your actual domain
all:
  children:                            # Cluster definitions
    dify:                              # Dify group
      vars:                            # Dify group variables
        apps:                          # Application configuration
          dify:                        # Dify application definition
            conf:                      # Dify application configuration
              NGINX_SERVER_NAME: dify.pigsty

  vars:                                # Global parameters
    #certbot_sign: true                # Use Certbot for free HTTPS certificate
    certbot_email: [email protected]      # Email for certificate requests, for expiration notifications, optional
    infra_portal:                      # Configure Nginx servers
      dify:                            # Dify server definition
        domain: dify.pigsty            # Replace with your own domain here!
        endpoint: "10.10.10.10:5001"   # Specify Dify's IP and port here (auto-configured by default)
        websocket: true                # Dify requires websocket enabled
        certbot: dify.pigsty           # Specify Certbot certificate name

Use the following commands to request Nginx certificates:

# Request and load the certificate on the explicitly limited infra group
./infra.yml -l infra -t nginx_certbot,nginx_reload -e certbot_sign=true

Run the app.yml playbook to redeploy Dify service for the NGINX_SERVER_NAME configuration to take effect:

./app.yml -l dify -t app_config,app_launch

File Backup

You can use restic to back up Dify’s file state. The current template requires at least /data/dify, /opt/dify/.env, and /opt/dify/volumes/; the latter contains Compose Redis, Sandbox dependencies, and any Certbot data. Dify data in PostgreSQL should still be backed up separately with Pigsty/pgBackRest.

export RESTIC_REPOSITORY=/data/backups/dify   # Specify dify backup directory
export RESTIC_PASSWORD=some-strong-password   # Specify backup encryption password
mkdir -p ${RESTIC_REPOSITORY}                 # Create dify backup directory
restic init

After creating the Restic backup repository, you can backup Dify with:

export RESTIC_REPOSITORY=/data/backups/dify   # Specify dify backup directory
export RESTIC_PASSWORD=some-strong-password   # Specify backup encryption password

restic backup /data/dify /opt/dify/.env /opt/dify/volumes
restic snapshots                              # View backup snapshot list
restic restore 0b11f778 --target /tmp/dify-restore  # Restore to a temporary directory first, verify, then copy back
restic check                                  # Periodically check repository integrity

Another option is to place /data/dify on a shared filesystem managed by the JUICE module. File data can live in Silo/S3 or in a PostgreSQL jfs_blob table; the latter is not PostgreSQL large-object storage.

To use PostgreSQL for both JuiceFS metadata and file data, first declare a dedicated database and least-privilege user in pg_databases, then declare the instance on the Dify node. Passwords below are placeholders and must not be used in production:

pg_databases:
  - { name: dify_fs, owner: dify, comment: JuiceFS metadata and data for Dify }

juice_instances:
  dify:
    path: /data/dify
    meta: postgres://dify:<password>@10.10.10.10:5432/dify_fs
    data: --storage postgres --bucket 10.10.10.10:5432/dify_fs --access-key dify --secret-key <password>
    owner: 1001
    group: 1001
    port: 9567

Handle database creation and JUICE deployment separately. After confirming the exact targets, run the playbooks:

./pgsql-db.yml -l pg-meta -e dbname=dify_fs
./juice.yml -l dify -e fsname=dify

Database creation, initial filesystem formatting, and mounting all change the target environment. Confirm the backup, database name, and host group before executing them. Start Dify only after the mount is ready; see JUICE configuration and its PITR consistency boundary. Before mounting over a nonempty /data/dify, stop Dify and plan migration of the existing files.


Reference

Dify Self-Hosting FAQ

6.4 - InsForge: AI Backend-as-a-Service

Self-host InsForge OSS with Pigsty and let Pigsty manage PostgreSQL, backups, monitoring, and ingress.

InsForge is an open-source Backend-as-a-Service platform for AI coding agents. Built around PostgreSQL, it provides authentication, database APIs, file storage, a model gateway, edge functions, site deployment, payment integrations, and more, allowing applications to skip most backend boilerplate.

Pigsty provides the app/insforge configuration template, which runs InsForge OSS stateless services in Docker Compose while placing the most critical state in PostgreSQL managed by Pigsty. This lets you continue using Pigsty’s high availability, backup and recovery, monitoring, ingress domains, and infrastructure capabilities instead of hiding the database in an ephemeral container volume.

The current template targets InsForge OSS v2.2.6, uses external PostgreSQL, and exposes three services by default: the InsForge Dashboard/API, PostgREST, and Deno Runtime.


Quick Start

Run the following on a fresh Linux x86 / ARM server with a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap                  # Install Pigsty dependencies
./configure -c app/insforge  # Use the InsForge configuration template
vi pigsty.yml                # Required: keys, admin account, database password, domain

./deploy.yml                 # Install Pigsty, Infra, Etcd, and PostgreSQL
./docker.yml                 # Install Docker and Compose
./app.yml                    # Install InsForge

After installation, the default access URLs are:

  • http://<your_ip_address>:7130
  • http://isf.pigsty

The default administrator account is [email protected] / pigsty. In production, you must change the administrator account, administrator password, JWT secret, encryption key, and database password.

To access InsForge through isf.pigsty, add the following entry to /etc/hosts on the machine running your browser:

10.10.10.10 isf.pigsty

To expose the service to the public internet, use a real domain and HTTPS certificate, and modify infra_portal as described below.


Checklist

  • Prepare a fresh Linux server with at least 2C4G; use an SSD/NVMe disk.
  • Confirm that the server has a static private IPv4 address and can access GHCR / Docker Hub, or that a registry mirror is configured.
  • After running ./configure -c app/insforge, change the default passwords, domains, and keys in pigsty.yml.
  • Generate new JWT_SECRET and ENCRYPTION_KEY values separately with openssl rand -base64 32.
  • Keep POSTGRES_PASSWORD consistent with the password of dbuser_insforge in pg_users.
  • For public access, configure a real domain, an HTTPS certificate, and firewall access rules.
  • Confirm that PostgreSQL extension packages are installed correctly, and run pig pb info after deployment.

Architecture

The InsForge template separates the database from the application containers by default:

                    ┌──────────────────────────────────────────────┐
                    │                 InsForge Stack               │
┌──────────┐       │  ┌──────────┐  ┌──────────┐  ┌───────────┐  │
│  Nginx   │──────▶│  │ InsForge │  │PostgREST │  │   Deno    │  │
│ (Pigsty) │  :7130│  │ App+Web  │  │ REST API │  │  Runtime  │  │
└──────────┘       │  │  :7130   │  │  :5430   │  │   :7133   │  │
                    │  └────┬─────┘  └────┬─────┘  └─────┬─────┘  │
                    │       │             │              │         │
                    └───────┼─────────────┼──────────────┼─────────┘
                            │             │              │
                            ▼             ▼              ▼
                    ┌──────────────────────────────────────────────┐
                    │  PostgreSQL (Pigsty Managed HA Cluster)      │
                    │  Patroni + pgBackRest + pgBouncer + HAProxy  │
                    └──────────────────────────────────────────────┘

Components:

  • InsForge App: ghcr.io/insforge/insforge-oss:v2.2.6, providing the Dashboard and main API on port 7130.
  • PostgREST: postgrest/postgrest:v12.2.12, generating REST APIs from PostgreSQL schemas; exposed on host port 5430.
  • Deno Runtime: ghcr.io/insforge/deno-runtime:latest, the edge function runtime, listening on port 7133.
  • PostgreSQL: Managed by Pigsty for persistent state, backup, monitoring, and high availability.

Configuration Template

conf/app/insforge.yml defines a single-node, self-hosted InsForge template. The default topology includes:

  • insforge: The node running the InsForge, PostgREST, and Deno Runtime containers.
  • pg-meta: The PostgreSQL database cluster managed by Pigsty, including the roles, database, and extensions required by InsForge.
  • infra: Infrastructure services such as Nginx ingress, Grafana, and VictoriaMetrics.
  • etcd: The distributed configuration store required by Patroni.

Key configuration excerpts:

insforge:
  hosts: { 10.10.10.10: {} }
  vars:
    app: insforge
    apps:
      insforge:
        conf:
          JWT_SECRET: your-secret-key-here-must-be-32-char-or-above
          ENCRYPTION_KEY: your-encryption-key-here-must-be-32-char-or-above
          ROOT_ADMIN_USERNAME: [email protected]
          ROOT_ADMIN_PASSWORD: pigsty
          POSTGRES_HOST: 10.10.10.10
          POSTGRES_PORT: 5432
          POSTGRES_DB: insforge
          POSTGRES_USER: dbuser_insforge
          POSTGRES_PASSWORD: DBUser.Insforge

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - { name: dbuser_insforge ,password: DBUser.Insforge ,pgbouncer: true ,roles: [dbrole_admin] ,superuser: true ,comment: 'insforge superuser' }
      - { name: anon            ,login: false ,comment: 'insforge anonymous role for PostgREST' }
      - { name: authenticated   ,login: false ,comment: 'insforge authenticated role' }
      - { name: project_admin   ,login: false ,bypassrls: true ,comment: 'insforge project admin with RLS bypass' }
    pg_databases:
      - name: insforge
        owner: dbuser_insforge
        baseline: insforge.sql
        extensions: [pgcrypto, http, pg_cron]
    pg_libs: 'pg_cron, pg_stat_statements, auto_explain'
    pg_parameters:
      cron.database_name: insforge
      app.encryption_key: your-encryption-key-here-must-be-32-char-or-above
      insforge.policy_grant_role: project_admin
      insforge.internal_schemas: 'ai,auth,compute,deployments,email,functions,memory,payments,realtime,schedules,storage,system'
    pg_extensions: [ pg_cron, pg_http ]
    pg_hba_rules:
      - { user: dbuser_insforge ,db: all ,addr: 172.16.0.0/12 ,auth: pwd ,title: 'allow insforge access from local docker networks' }

Important Parameters

app.yml copies the app/insforge directory to /opt/insforge and uses apps.insforge.conf to override /opt/insforge/.env. Common parameters include:

ParameterDefaultDescription
JWT_SECRETSample secretJWT signing secret; must be replaced in production, preferably with a random value of at least 32 characters
ENCRYPTION_KEYSample secretEncrypts runtime credentials; must be replaced in production and managed separately from JWT_SECRET
ROOT_ADMIN_USERNAME[email protected]Root administrator account
ROOT_ADMIN_PASSWORDpigstyRoot administrator password; must be replaced in production
POSTGRES_HOST / POSTGRES_PORT10.10.10.10 / 5432Pigsty PostgreSQL endpoint
POSTGRES_DBinsforgeInsForge database
POSTGRES_USERdbuser_insforgeApplication user that connects InsForge to PostgreSQL
POSTGRES_PASSWORDDBUser.InsforgeApplication user password; must be replaced in production
INSFORGE_VERSIONv2.2.6InsForge OSS image tag
DENO_RUNTIME_VERSIONlatestDeno Runtime image tag
APP_PORT7130External InsForge App port
POSTGREST_PORT5430External PostgREST port
DENO_PORT7133External Deno Runtime port
ACCESS_API_KEYEmptyOptional MCP / API access key; generated by InsForge when empty
ACCESS_ANON_KEYEmptyOptional anonymous frontend access key; should begin with anon_ when set
OPENROUTER_API_KEYEmptyOptional OpenRouter model gateway key
AWS_S3_BUCKET / S3_*EmptyOptional object storage configuration
DENO_DEPLOY_TOKENEmptyOptional Deno Deploy integration
VERCEL_TOKEN / FLY_API_TOKENEmptyOptional site deployment and compute platform integrations
STRIPE_* / RAZORPAY_*EmptyOptional payment integrations

Generate production secrets with:

openssl rand -base64 32

When changing the database password, keep the application and database definitions synchronized. For example:

apps:
  insforge:
    conf:
      POSTGRES_PASSWORD: <new-password>

pg_users:
  - { name: dbuser_insforge ,password: <new-password> ,pgbouncer: true ,roles: [dbrole_admin] ,superuser: true }

Once ENCRYPTION_KEY has been used for production data, keep it stable. Changing it may make stored runtime credentials such as API keys, OAuth tokens, and function secrets impossible to decrypt.


Database and Permissions

The default InsForge database is named insforge and owned by dbuser_insforge. The template creates the following roles:

RoleLoginPurpose
dbuser_insforgeYesApplication user that connects InsForge to PostgreSQL; granted superuser in the template
anonNoPostgREST anonymous role
authenticatedNoPostgREST authenticated-user role
project_adminNoAdministrative role with service-key semantics and BYPASSRLS

files/insforge.sql configures PostgREST role privileges, default privileges, ACLs for project_admin, and the helper function public.reload_postgrest_schema(). The function executes:

NOTIFY pgrst, 'reload schema';

This notifies PostgREST to reload its schema.

The upstream InsForge PostgreSQL image preinstalls insforge_pg_utils. The current Pigsty template does not depend on this extension package. Instead, it uses pgcrypto, http, and pg_cron already provided by Pigsty, while application migrations by InsForge manage runtime schemas.


Service Ports and Persistence

The default Docker Compose services are:

ServiceContainerHost PortDescription
InsForge Appinsforge7130Dashboard and main API
PostgRESTinsforge-postgrest5430Automatically generated REST API
Deno Runtimeinsforge-deno7133Edge function runtime

The default Docker volumes are:

VolumeMount PointDescription
storage-data/insforge-storageLocal file storage
insforge-logs/insforge-logsApplication logs
deno_cache/deno-dirDeno module cache

By default, Docker containers connect to the Pigsty node at 10.10.10.10:5432. The template HBA rule permits 172.16.0.0/12, covering Docker’s default bridge and common custom bridge networks.


Domain and Ingress

The template adds an InsForge entry to infra_portal by default:

infra_portal:
  home    : { domain: i.pigsty }
  insforge:
    domain: isf.pigsty
    endpoint: "10.10.10.10:7130"
    websocket: true
    certbot: isf.pigsty

To use a real domain such as insforge.example.com, replace the placeholder in bulk:

sed -ie 's/isf.pigsty/insforge.example.com/g' pigsty.yml

Then apply the Nginx ingress configuration:

./infra.yml -t nginx

To request an HTTPS certificate, first ensure that the domain resolves to the current node, then add or modify certbot under infra_portal.insforge:

insforge:
  domain: insforge.example.com
  endpoint: "10.10.10.10:7130"
  websocket: true
  certbot: insforge.example.com

Then run:

make cert
./infra.yml -t nginx

Operations

InsForge is installed in /opt/insforge. Common commands include:

cd /opt/insforge

make up       # Start services
make view     # Print access URLs
make info     # Show container status
make log      # Follow logs
make restart  # Restart containers
make down     # Stop containers
make clean    # Remove stopped containers
make edit     # Edit .env

For offline environments, save the images in advance:

cd /opt/insforge
make pull
make save
make tarball

Default artifact locations:

  • /tmp/docker/insforge/postgrest.tgz
  • /tmp/docker/insforge/insforge.tgz
  • /tmp/docker/insforge/deno.tgz
  • /tmp/insforge.tgz

Load the images on the target machine:

cd /opt/insforge
make load
make up

Data and Backup

InsForge state is divided into two categories:

  • Business data, users, project metadata, permissions, and related state are stored in the Pigsty PostgreSQL database insforge.
  • Local files and logs are stored in the Docker volumes storage-data and insforge-logs.

By default, the template schedules a full PostgreSQL backup every day at 1:00 AM:

pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]

After deployment, check the backup status:

pig pb info

If file storage is configured to use S3 / MinIO, file objects are managed by that object storage system. If you keep local volumes, include them separately in your host-level backup strategy.


Troubleshooting

Check container status:

cd /opt/insforge
make info

View logs:

sudo docker logs insforge
sudo docker logs insforge-postgrest
sudo docker logs insforge-deno

Check whether PostgreSQL is reachable from the container:

sudo docker exec insforge-postgrest bash -c '</dev/tcp/10.10.10.10/5432'

Check whether the HBA rules include the Docker network:

sudo -iu postgres psql -d insforge -c "TABLE pg_hba_file_rules;"

Check whether the roles exist:

sudo -iu postgres psql -d insforge -c "SELECT rolname, rolcanlogin, rolbypassrls FROM pg_roles WHERE rolname IN ('anon','authenticated','project_admin');"

Check for port conflicts:

ss -tlnp | grep -E '7130|7133|5430'

Common issues:

  • Cannot log in: Confirm that ROOT_ADMIN_USERNAME / ROOT_ADMIN_PASSWORD were written to /opt/insforge/.env by the template, and check the insforge container logs.
  • PostgREST fails to start: Confirm that the anon, authenticated, and project_admin roles exist, and that JWT_SECRET matches the InsForge App setting.
  • Database connection fails: Confirm that POSTGRES_HOST, POSTGRES_PORT, and POSTGRES_PASSWORD match the pg_users configuration, and check that HBA permits the Docker network.
  • File upload or download errors: When using S3 / MinIO, check AWS_S3_BUCKET, S3_ENDPOINT_URL, S3_FORCE_PATH_STYLE, and the access-key configuration.

References

6.5 - Hindsight: AI Long-Term Memory

Self-host Hindsight with Pigsty and store long-term memory in external PostgreSQL.

Hindsight is a PostgreSQL-native long-term memory service for AI agents.

Pigsty provides the app/hindsight configuration template (conf/app/hindsight.yml), using Pigsty-managed PostgreSQL by default instead of Hindsight’s built-in development database.

Quick Start

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/hindsight
vi pigsty.yml                 # edit domain, database password, and LLM settings
./deploy.yml
./docker.yml
./app.yml

Default access URLs:

  • UI: http://hs.pigsty or http://<IP>:9999
  • API: http://hs-api.pigsty or http://<IP>:8888

Key Settings

conf/app/hindsight.yml overrides /opt/hindsight/.env through apps.hindsight.conf. Key parameters:

  • HINDSIGHT_API_PUBLISH_PORT: public API port, default 8888
  • HINDSIGHT_UI_PUBLISH_PORT: public UI port, default 9999
  • HINDSIGHT_DB_HOST / HINDSIGHT_DB_PORT / HINDSIGHT_DB_NAME / HINDSIGHT_DB_USER / HINDSIGHT_DB_PASSWORD
  • HINDSIGHT_API_VECTOR_EXTENSION: default pgvector
  • HINDSIGHT_API_TEXT_SEARCH_EXTENSION: default native
  • HINDSIGHT_API_LLM_PROVIDER: default none

The default none LLM provider only ensures the service can start. Fact extraction, reflection, and consolidation require configuring Ollama or an OpenAI-compatible API.

Operations

cd /opt/hindsight
make up
make log
make info
make down
make pull

References

6.6 - FerretDB: MongoDB Protocol

Deploy a stateless FerretDB proxy on PostgreSQL and DocumentDB managed by Pigsty.

FerretDB provides a MongoDB-compatible protocol over PostgreSQL and the DocumentDB extension. Pigsty’s app/ferretdb runs only the stateless protocol proxy; PostgreSQL, the postgres database, the DocumentDB extensions, and the backend PostgreSQL login role must already exist. The mongo configuration template prepares these dependencies together.

Quick Start

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c mongo
./deploy.yml
./docker.yml -l pg-meta
./app.yml -l pg-meta

After installing mongosh or another MongoDB-compatible client separately, connect with the dedicated login declared by the template:

mongosh 'mongodb://mongod:[email protected]:27017/'

Key Configuration

Override template variables through apps.ferretdb.conf in the inventory. Do not edit the deployed /opt/ferretdb/.env directly:

app: ferretdb
apps:
  ferretdb:
    conf:
      FERRETDB_IMAGE: ghcr.io/ferretdb/ferretdb:2.7.0
      FERRETDB_POSTGRESQL_URL: 'postgres://mongod:[email protected]:5436/postgres?pool_min_conns=1&pool_max_conns=20'
      FERRETDB_BIND_ADDR: 127.0.0.1
      FERRETDB_PORT: 27017
      FERRETDB_AUTH: true
      FERRETDB_TELEMETRY: disabled

Port 5436 is Pigsty’s direct-to-current-primary PostgreSQL service. Linux host-gateway mapping lets the container connect through the local host while preserving Pigsty’s primary routing. The MongoDB port listens on loopback by default; change FERRETDB_BIND_ADDR explicitly only when remote clients require access.

FerretDB authenticates users through PostgreSQL, but it does not currently implement MongoDB authorization semantics, so MongoDB roles cannot provide access isolation. The template also does not enable MongoDB client TLS. Before exposing the service to an untrusted network, configure certificates and the FERRETDB_LISTEN_TLS* variables.

FerretDB releases specify a preferred DocumentDB version, while Pigsty may ship a newer compatible package. After upgrading either component, rerun an authenticated CRUD smoke test.

Optional Three-Node Topology

The mongo template includes a commented three-node PostgreSQL / DocumentDB cluster. Each node runs a FerretDB container, and HAProxy exposes standard port 27017 at the floating endpoint 10.10.10.4:27017 (mongo.pigsty). After enabling the complete pg-mongo cluster and the additional etcd members, run:

./configure -c mongo
./deploy.yml
./docker.yml -l pg-mongo
./app.yml -l pg-mongo
mongosh 'mongodb://mongod:[email protected]:27017/'

HAProxy uses TCP health checks to exclude stopped or unreachable FerretDB processes; the image’s built-in health check continues to verify the backend connection. Production deployments should also use a shared Silo or external S3-compatible pgBackRest repository so the same backup history remains available after a PostgreSQL primary failover.

References

6.7 - Teable: AI No-Code Database

Self-host Teable with Pigsty, external PostgreSQL, and Silo.

Teable is a no-code database platform for team collaboration.

Pigsty provides the app/teable template (conf/app/teable.yml) and depends on PostgreSQL + Silo + Docker by default (no Redis dependency).

Quick Start

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/teable
vi pigsty.yml                 # update passwords, domain, and mail settings
./deploy.yml                  # deploy infra, PostgreSQL, and Silo
./docker.yml
./app.yml

Default endpoints:

  • http://<IP>:8890
  • http://tea.pigsty

Key Settings

The template writes the following into /opt/teable/.env:

  • POSTGRES_HOST/POSTGRES_PORT/POSTGRES_DB/POSTGRES_USER/POSTGRES_PASSWORD
  • PRISMA_DATABASE_URL
  • PUBLIC_ORIGIN (public URL)
  • PUBLIC_DATABASE_PROXY
  • TEABLE_PORT (default 8890)

Operations

cd /opt/teable
make up
make log
make down

References

6.8 - Gitea: Self-Hosted Git Service

Deploy Gitea with Pigsty’s Compose template and connect it to external PostgreSQL.

Gitea is a lightweight open-source Git hosting platform.

Pigsty’s app/gitea template uses external PostgreSQL mode by default, configured via GITEA_DB_* values in .env.

Quick Start

cd ~/pigsty/app/gitea
vi .env         # check domain, ports, database settings
make up

Default endpoints:

  • Web: http://git.pigsty or http://<IP>:8889
  • SSH: <IP>:2222

Database Preparation

bin/pgsql-user pg-meta dbuser_gitea
bin/pgsql-db   pg-meta gitea

Connection string example:

postgres://dbuser_gitea:[email protected]:5432/gitea

Common Commands

make up
make log
make stop
make clean

References

6.9 - NocoDB: Open-Source Airtable

Use NocoDB to transform PostgreSQL databases into smart spreadsheets, a no-code database application platform.

NocoDB is an open-source Airtable alternative that turns any database into a smart spreadsheet.

It provides a rich user interface that allows you to create powerful database applications without writing code. NocoDB supports PostgreSQL, MySQL, SQL Server, and more, making it ideal for building internal tools and data management systems.

Quick Start

Pigsty provides a Docker Compose configuration file for NocoDB in the software template directory:

cd ~/pigsty/app/nocodb

Review and modify the .env configuration file (adjust database connections as needed).

Start the service:

make up     # Start NocoDB with Docker Compose

Access NocoDB:

  • Default URL: http://nocodb.pigsty
  • Alternate URL: http://10.10.10.10:8080
  • First-time access requires creating an administrator account

Management Commands

Pigsty provides convenient Makefile commands to manage NocoDB:

make up      # Start NocoDB service
make run     # Start with Docker (connect to external PostgreSQL)
make view    # Display NocoDB access URL
make log     # View container logs
make info    # View service details
make stop    # Stop the service
make clean   # Stop and remove containers
make pull    # Pull the latest image
make rmi     # Remove NocoDB image
make save    # Save image to /tmp/nocodb.tgz
make load    # Load image from /tmp/nocodb.tgz

Connect to PostgreSQL

NocoDB can connect to PostgreSQL databases managed by Pigsty.

When adding a new project in the NocoDB interface, select “External Database” and enter the PostgreSQL connection information:

Host: 10.10.10.10
Port: 5432
Database Name: your_database
Username: your_username
Password: your_password
SSL: Disabled (or enable as needed)

After successful connection, NocoDB will automatically read the database table structure, and you can manage data through the visual interface.

Features

  • Smart Spreadsheet Interface: Excel/Airtable-like user experience
  • Multiple Views: Grid, form, kanban, calendar, gallery views
  • Collaboration Features: Team collaboration, permission management, comments
  • API Support: Auto-generated REST API
  • Integration Capabilities: Webhooks, Zapier integrations
  • Import/Export: CSV, Excel format support
  • Formulas and Validation: Complex data calculations and validation rules

Configuration

NocoDB configuration is in the .env file:

# Database connection (NocoDB metadata storage)
NC_DB=pg://postgres:[email protected]:5432/nocodb

# JWT secret (recommended to change)
NC_AUTH_JWT_SECRET=your-secret-key

# Other settings
NC_PUBLIC_URL=http://nocodb.pigsty
NC_DISABLE_TELE=true

Data Persistence

NocoDB metadata is stored by default in an external PostgreSQL database, and application data can also be stored in PostgreSQL.

If using local storage, data is saved in the /data/nocodb directory.

Security Recommendations

  1. Change Default Secret: Modify NC_AUTH_JWT_SECRET in the .env file
  2. Use Strong Passwords: Set strong passwords for administrator accounts
  3. Configure HTTPS: Enable HTTPS for production environments
  4. Restrict Access: Limit access through firewall or Nginx
  5. Regular Backups: Regularly back up the NocoDB metadata database

6.10 - Mattermost: Open-Source Team Collaboration

Deploy Mattermost with Pigsty and store state in external PostgreSQL.

Mattermost is an open-source team collaboration platform and a private alternative to Slack.

Pigsty provides app/mattermost (conf/app/mattermost.yml), which stores app state in external PostgreSQL and persists file directories on host paths.

Quick Start

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/mattermost
vi pigsty.yml                 # update passwords and domain
./deploy.yml
./docker.yml
./app.yml

Default endpoints:

  • http://<IP>:8065
  • http://mm.pigsty

On first access, initialize the admin account in the web UI.

Default Storage and Connections

Default template settings include:

  • PostgreSQL URL: POSTGRES_URL=postgres://dbuser_mattermost:DBUser.Mattermost@<IP>:5432/mattermost?...
  • Persistent directories: /data/mattermost/{config,data,logs,plugins,client/plugins,bleve-indexes}

Operations

cd /opt/mattermost
make up
make restart
make log
make stop

References

6.11 - Wiki.js: OSS Wiki Software

How to self-hosting your own wikipedia with Wiki.js and use Pigsty managed PostgreSQL as the backend database

Public Demo: http://wiki.pigsty.cc

Wiki.js

TL; DR

cd ~/pigsty/app/wiki && docker compose up -d

Postgres Preparation

# postgres://dbuser_wiki:[email protected]:5432/wiki
- { name: wiki, owner: dbuser_wiki, revokeconn: true , comment: wiki the api gateway database }
- { name: dbuser_wiki, password: DBUser.Wiki , pgbouncer: true , roles: [ dbrole_admin ] }
bin/pgsql-user pg-meta dbuser_wiki
bin/pgsql-db   pg-meta wiki

Configuration

version: "3"
services:
  wiki:
    container_name: wiki
    image: requarks/wiki:2
    environment:
      DB_TYPE: postgres
      DB_HOST: 10.10.10.10
      DB_PORT: 5432
      DB_USER: dbuser_wiki
      DB_PASS: DBUser.Wiki
      DB_NAME: wiki
    restart: unless-stopped
    ports:
      - "9002:3000"

Access

  • Default Port for wiki: 9002
# add to nginx_upstream
- { name: wiki  , domain: wiki.pigsty.cc , endpoint: "127.0.0.1:9002"   }
./infra.yml -t nginx_config,nginx_reload -l infra

6.12 - Maybe: Self-Hosted Personal Finance

Self-host the Maybe personal finance application with Pigsty and let Pigsty manage PostgreSQL, backups, monitoring, and ingress.

Maybe is an open-source personal finance application for managing accounts, transactions, budgets, investments, and household financial views. Maybe is a typical Rails web application: it stores business data in PostgreSQL in production and uses Redis for background job queues.

Pigsty provides the app/maybe template, which connects the stateless Maybe Web / Worker containers to PostgreSQL managed by Pigsty and uses local Redis for the Sidekiq queue. This keeps your most important financial data in a PostgreSQL cluster that can be backed up, monitored, and recovered, rather than in an ephemeral Docker data volume.

The upstream Maybe repository has been archived, and its latest release is v0.6.0. GHCR currently publishes stable and latest image tags. Pigsty uses stable by default, which tracks the latest release image.


Quick Start

Run the following on a fresh Linux x86 / ARM server with a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap                # Install Pigsty dependencies
./configure -c app/maybe   # Use the Maybe configuration template
vi pigsty.yml              # Required: SECRET_KEY_BASE, database password, domain

./deploy.yml               # Install Pigsty, Infra, Etcd, and PostgreSQL
./docker.yml               # Install Docker and Compose
./app.yml                  # Install Maybe

Maybe listens on port 5002 by default. After installation, you can access it at:

  • http://<your_ip_address>:5002
  • http://maybe.pigsty

On your first visit, select the option to create an account on the login page, then register your first household account to get started.

To access Maybe through maybe.pigsty, add the following entry to /etc/hosts on the machine running your browser:

10.10.10.10 maybe.pigsty

To expose the service to the public internet, use a real domain and HTTPS certificate, and modify infra_portal as described below.


Checklist

  • Prepare a fresh Linux server with at least 2C4G; use an SSD/NVMe disk.
  • Confirm that the server has a static private IPv4 address and can access GHCR / Docker Hub, or that a registry mirror is configured.
  • After running ./configure -c app/maybe, change the default passwords, domain, and secrets in pigsty.yml.
  • Generate a new SECRET_KEY_BASE with openssl rand -hex 64.
  • Keep POSTGRES_PASSWORD consistent with the password of the maybe user in pg_users.
  • For public access, configure a real domain, an HTTPS certificate, and firewall access rules.
  • Confirm that PostgreSQL backup jobs run correctly, and check pig pb info after deployment.

Configuration Template

conf/app/maybe.yml defines a single-node, self-hosted Maybe template. The default topology includes:

  • maybe: The node running the Maybe Web / Worker / Redis containers.
  • pg-maybe: The PostgreSQL database cluster managed by Pigsty.
  • infra: Infrastructure services such as Nginx ingress, Grafana, and VictoriaMetrics.
  • etcd: The distributed configuration store required by Patroni.

Key configuration excerpts:

maybe:
  hosts: { 10.10.10.10: {} }
  vars:
    app: maybe
    apps:
      maybe:
        file:
          - { path: /data/maybe             ,state: directory ,mode: 0755 }
          - { path: /data/maybe/storage     ,state: directory ,owner: 1000 ,group: 1000 ,mode: 0755 }
          - { path: /data/maybe/redis       ,state: directory ,mode: 0755 }
        conf:
          MAYBE_IMAGE: ghcr.io/maybe-finance/maybe
          MAYBE_VERSION: stable
          MAYBE_PORT: 5002
          MAYBE_DATA: /data/maybe
          APP_DOMAIN: maybe.pigsty
          SECRET_KEY_BASE: 2f1e4c3d5b6a79808796a5b4c3d2e1f00123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567
          DB_HOST: 10.10.10.10
          DB_PORT: 5432
          POSTGRES_USER: maybe
          POSTGRES_PASSWORD: MaybeFinance2026
          POSTGRES_DB: maybe_production
          REDIS_VERSION: 7-alpine

pg-maybe:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-maybe
    pg_users:
      - { name: maybe ,password: MaybeFinance2026 ,pgbouncer: true ,roles: [ dbrole_admin ] ,comment: admin user for maybe service }
    pg_databases:
      - { name: maybe_production ,owner: maybe ,revokeconn: true ,comment: maybe main database }
    pg_hba_rules:
      - { user: maybe ,db: maybe_production ,addr: 172.16.0.0/12 ,auth: pwd ,title: 'allow maybe access from local docker network' }
    pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]

Here, maybe_production is the default production database name used upstream by Maybe / Rails. You can rename it to maybe, but you must update POSTGRES_DB, pg_databases.name, pg_hba_rules.db, and every reference in documentation and operational scripts at the same time.


Important Parameters

app.yml copies the app/maybe directory to /opt/maybe and uses apps.maybe.conf to override /opt/maybe/.env. Common parameters include:

ParameterDefaultDescription
MAYBE_IMAGEghcr.io/maybe-finance/maybeMaybe image repository
MAYBE_VERSIONstableImage tag; keep stable for production
MAYBE_PORT5002Host port exposed by Maybe
MAYBE_DATA/data/maybePersistent directory on the host
APP_DOMAINmaybe.pigstyPlaceholder for the default Maybe ingress domain
SECRET_KEY_BASESample random stringRails encryption and signing secret; must be replaced in production
DB_HOST / DB_PORT10.10.10.10 / 5432Pigsty PostgreSQL endpoint
POSTGRES_USERmaybeApplication user that connects Maybe to PostgreSQL
POSTGRES_PASSWORDMaybeFinance2026Application user password; must be replaced in production
POSTGRES_DBmaybe_productionMaybe production database
REDIS_VERSION7-alpineLocal Redis image tag

Generate a production secret with:

openssl rand -hex 64

When changing the password, keep the application and database definitions synchronized. For example:

apps:
  maybe:
    conf:
      POSTGRES_PASSWORD: <new-password>

pg_users:
  - { name: maybe ,password: <new-password> ,pgbouncer: true ,roles: [ dbrole_admin ] }

Domain and Ingress

The template adds a Maybe entry to infra_portal by default:

infra_portal:
  home  : { domain: i.pigsty }
  maybe:
    domain: maybe.pigsty
    endpoint: "10.10.10.10:5002"
    websocket: true

To use a real domain such as finance.example.com, replace the placeholder in bulk:

sed -ie 's/maybe.pigsty/finance.example.com/g' pigsty.yml

Then apply the Nginx ingress configuration:

./infra.yml -t nginx

To request an HTTPS certificate, first ensure that the domain resolves to the current node, then add certbot under infra_portal.maybe:

maybe:
  domain: finance.example.com
  endpoint: "10.10.10.10:5002"
  websocket: true
  certbot: finance.example.com

Then run:

make cert
./infra.yml -t nginx

Operations

Maybe is installed in /opt/maybe. Common commands include:

cd /opt/maybe

make up        # Start Maybe
make run       # Start in the foreground and show logs
make restart   # Restart containers
make down      # Stop containers
make status    # Show container status
make log       # Follow logs
make health    # Check the Rails /up health endpoint
make migrate   # Run Rails db:prepare manually
make console   # Enter the Rails console
make exec      # Enter a shell in the maybe-web container

The web container automatically runs db:prepare at startup, so manual migration is not usually required. If the startup logs report a database migration problem after an image upgrade, inspect the logs, then run:

cd /opt/maybe
make pull
make up
make log

Data and Backup

Maybe state is divided into two categories:

  • Business data is stored in the Pigsty PostgreSQL database maybe_production.
  • Attachments and cache are stored in the host directories /data/maybe/storage and /data/maybe/redis.

By default, the template schedules a full PostgreSQL backup every day at 1:00 AM:

pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]

After deployment, check the backup status:

pig pb info

If you use Maybe to store real financial data in production, at minimum:

  • Regularly verify that PostgreSQL backups succeed.
  • Place the pgBackRest repository on reliable storage or object storage.
  • Include /data/maybe/storage in file-level backups; for example, use restic to back it up to S3.
  • Do not expose SECRET_KEY_BASE, database passwords, or API keys in a public repository.

Security Recommendations

Maybe manages highly sensitive personal and household financial data. For production use:

  • Change all Pigsty default passwords, especially pg_admin_password, pg_monitor_password, patroni_password, and haproxy_admin_password.
  • Change the Maybe database user password in POSTGRES_PASSWORD.
  • Use a new SECRET_KEY_BASE; do not retain the sample value from the template.
  • Enable HTTPS for public access and restrict access to administration ports.
  • If you enable OPENAI_ACCESS_TOKEN or SYNTH_API_KEY, assess both external API costs and the boundary of data exposure.

The upstream Maybe repository has been archived. It is suitable for users who are satisfied with the existing feature set and prefer long-term local ownership. If you need continuously evolving features or automatic bank synchronization, evaluate the upstream maintenance status before adopting it.


References

6.13 - Immich: Self-Hosted Photo and Video Library

Self-host Immich, the open-source Google Photos alternative, with Pigsty managing its metadata, vector search, backups, and ingress.

Immich is a high-performance, self-hosted photo and video management application and one of the most popular open-source alternatives to Google Photos. It provides web and mobile uploads, album sharing, timelines, maps, EXIF and RAW support, LivePhoto, semantic search, facial recognition, and automatic backups under the AGPL-3.0 license.

Pigsty’s app/immich template runs the Immich application layer with Docker Compose and stores metadata in Pigsty-managed PostgreSQL. The current template follows the Immich v3 layout and uses VectorChord by default for similar-image search, smart search, and face-search vectors.

Unlike Immich’s official single-node Compose template, PostgreSQL does not run in an application container. Pigsty manages it instead, providing monitoring, backups, PITR, extension management, and high-availability access.


Quick Start

Immich recommends at least 2 CPU cores and 6 GB of RAM, or 4 CPU cores and 8 GB of RAM for smooth operation. The v3 amd64 machine-learning image requires the x86-64-v2 instruction set. Linux with local SSD storage is recommended for production.

On a fresh x86 or ARM Linux server running a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/immich
vi pigsty.yml              # Required: change passwords, domains, and media paths

./deploy.yml               # Install Pigsty and PostgreSQL
./docker.yml               # Install Docker and Compose
./app.yml                  # Install Immich

Default endpoints:

http://photo.pigsty
http://10.10.10.10:2283

If you use photo.pigsty, add a hosts entry on the browser host or replace the template domain with a real domain.


Template Structure

conf/app/immich.yml defines a single-node self-hosted Immich template. The default topology includes:

  • immich: the node running Immich Server, Machine Learning, and local Valkey/Redis containers.
  • pg-immich: the Pigsty-managed PostgreSQL cluster.
  • infra: Nginx ingress, Grafana, VictoriaMetrics, and other infrastructure.
  • etcd: the distributed configuration store required by Patroni.

Application containers include:

  • immich-server: API, Web UI, and background jobs, exposed on host port 2283 by default.
  • immich-machine-learning: CLIP and facial-recognition model inference.
  • redis: local Valkey queues and cache.

The template does not start the PostgreSQL container from Immich’s upstream Compose file. Pigsty provides the database through DB_URL.


Data Storage Strategy

Immich state is divided into three layers that must be managed separately:

  • Media files: original photos and videos, thumbnails, transcoded videos, avatars, and the upload queue, stored in the host directory specified by UPLOAD_LOCATION.
  • PostgreSQL: metadata for users, albums, assets, EXIF, file paths, job state, people, faces, and smart-search vectors.
  • Valkey/Redis: queues, cache, and runtime state; it must not be treated as an authoritative data source.

Photo and video files are not stored in PostgreSQL. Conversely, Immich cannot reconstruct its complete application state simply by rescanning the media directory; the paths and metadata in the database are equally important.

A recoverable Immich backup must therefore include both PostgreSQL and the media directory. Backing up only the database loses the photos, while backing up only the files cannot reliably restore albums, users, shares, faces, and search state.


PostgreSQL

Default database connection and vector extension:

DB_URL=postgresql://dbuser_immich:[email protected]:5432/immich
DB_VECTOR_EXTENSION=vectorchord

The template installs the extension packages on the pg-immich cluster and creates the database extensions:

CREATE EXTENSION vchord CASCADE;
CREATE EXTENSION earthdistance CASCADE;

vchord must be added to shared_preload_libraries through pg_libs; the template already configures it:

pg_extensions: [ pgvector, vchord ]
pg_libs: 'vchord.so, pg_stat_statements, auto_explain'

The default connection goes directly to PostgreSQL on port 5432. Do not point Immich at PgBouncer transaction pooling. Direct PostgreSQL connections or session pooling are more reliable for migrations, indexes, and prepared statements.

Immich still treats pre-existing PostgreSQL as an advanced deployment option, but explicitly notes that it enables WAL-based backup tools such as pgBackRest and Barman. The Pigsty template uses a non-superuser path: Pigsty creates the database, user, and extensions in advance, so the Immich application user does not need PostgreSQL superuser privileges.


Media Files

Uploaded photos, videos, thumbnails, transcoded files, and avatars are stored in the host directory specified by UPLOAD_LOCATION:

/data/immich/library

PostgreSQL stores only metadata and file paths. Media files are not stored in PostgreSQL and are not automatically protected by pgBackRest.

A production deployment must back up at least two data layers:

  • PostgreSQL: use Pigsty pgBackRest / PITR.
  • Media files: perform a complete file-level backup of /data/immich/library, including originals, the upload queue, thumbnails, transcoded files, avatars, and other generated assets.

For a more consistent combined backup, stop immich-server before backing up the database and media directory together. If the service cannot be stopped, back up the database first, followed by the filesystem.


Images and Networking

The default images come from GHCR and Docker Hub:

docker pull ghcr.io/immich-app/immich-server:v3
docker pull ghcr.io/immich-app/immich-machine-learning:v3
docker pull docker.io/valkey/valkey:9

If image pulls are slow or restricted, configure proxy_env or docker_registry_mirrors in pigsty.yml.


Operations

After installation, enter /opt/immich:

cd /opt/immich

make up       # Start Immich
make logs     # Follow logs
make info     # Show container status
make pull     # Pull images
make restart  # Restart containers
make down     # Stop and remove containers

To pin a specific Immich version, set the following in pigsty.yml:

IMMICH_VERSION: v3.0.1

Read the upstream release notes before upgrading Immich or VectorChord. After upgrading the VectorChord package, you will usually also need to update the extension and rebuild the related indexes in the immich database:

ALTER EXTENSION vchord UPDATE;
REINDEX INDEX face_index;
REINDEX INDEX clip_index;

Rebuilding indexes for a large library can take a long time. Confirm that you have a backup and a maintenance window before proceeding.


References

6.14 - Kong: API Gateway

Deploy Kong with Pigsty Compose templates and PostgreSQL backend storage.

Kong is an open-source API gateway.

Pigsty’s app/kong template stores configuration in PostgreSQL and runs a one-time migration job (kong-migration) automatically.

Quick Start

cd ~/pigsty/app/kong
vi .env         # check KONG_PG_* and port settings
make

Default ports:

  • Proxy HTTP: 8000
  • Proxy HTTPS: 8443
  • Admin API: 8001

Database Preparation

bin/pgsql-user pg-meta dbuser_kong
bin/pgsql-db   pg-meta kong

Connection string example:

postgres://dbuser_kong:[email protected]:5432/kong

Common Commands

make log
make stop
make clean
make pull

References

6.15 - Metabase: BI Analytics Tool

Use Metabase for rapid business intelligence analysis with a user-friendly interface for team self-service data exploration.

Metabase is a fast, easy-to-use open-source business intelligence tool that lets your team explore and visualize data without SQL knowledge.

Metabase provides a friendly user interface with rich chart types and supports connecting to various databases, making it an ideal choice for enterprise data analysis.

Quick Start

Pigsty provides a Docker Compose configuration file for Metabase in the software template directory:

cd ~/pigsty/app/metabase

Review and modify the .env configuration file:

vim .env    # Check configuration, recommend changing default credentials

Start the service:

make up     # Start Metabase with Docker Compose

Access Metabase:

  • Default URL: http://metabase.pigsty
  • Alternate URL: http://10.10.10.10:3001
  • First-time access requires initial setup

Management Commands

Pigsty provides convenient Makefile commands to manage Metabase:

make up      # Start Metabase service
make run     # Start with Docker (connect to external PostgreSQL)
make view    # Display Metabase access URL
make log     # View container logs
make info    # View service details
make stop    # Stop the service
make clean   # Stop and remove containers
make pull    # Pull the latest image
make rmi     # Remove Metabase image
make save    # Save image to file
make load    # Load image from file

Connect to PostgreSQL

Metabase can connect to PostgreSQL databases managed by Pigsty.

During Metabase initialization or when adding a database, select “PostgreSQL” and enter the connection information:

Database Type: PostgreSQL
Name: Custom name (e.g., "Production Database")
Host: 10.10.10.10
Port: 5432
Database Name: your_database
Username: dbuser_meta
Password: DBUser.Meta

After successful connection, Metabase will automatically scan the database schema, and you can start creating questions and dashboards.

Features

  • No SQL Required: Build queries through visual interface
  • Rich Chart Types: Line, bar, pie, map charts, and more
  • Interactive Dashboards: Create beautiful data dashboards
  • Auto Refresh: Schedule data and dashboard updates
  • Permission Management: Fine-grained user and data access control
  • SQL Mode: Advanced users can write SQL directly
  • Embedding: Embed charts into other applications
  • Alerting: Automatic notifications on data changes

Configuration

Metabase configuration is in the .env file:

# Metabase metadata database (PostgreSQL recommended)
MB_DB_TYPE=postgres
MB_DB_DBNAME=metabase
MB_DB_PORT=5432
MB_DB_USER=dbuser_metabase
MB_DB_PASS=DBUser.Metabase
MB_DB_HOST=10.10.10.10

# Application configuration
JAVA_OPTS=-Xmx2g

Recommended: Use a dedicated PostgreSQL database for storing Metabase metadata.

Data Persistence

Metabase metadata (users, questions, dashboards, etc.) is stored in the configured database.

If using H2 database (default), data is saved in the /data/metabase directory. Using PostgreSQL as the metadata database is strongly recommended for production environments.

Performance Optimization

  • Use PostgreSQL: Replace the default H2 database
  • Increase Memory: Add JVM memory with JAVA_OPTS=-Xmx4g
  • Database Indexes: Create indexes for frequently queried fields
  • Result Caching: Enable Metabase query result caching
  • Scheduled Updates: Set reasonable dashboard auto-refresh frequency

Security Recommendations

  1. Change Default Credentials: Modify metadata database username and password
  2. Enable HTTPS: Configure SSL certificates for production
  3. Configure Authentication: Enable SSO or LDAP authentication
  4. Restrict Access: Limit access through firewall
  5. Regular Backups: Back up the Metabase metadata database

6.16 - Registry: Container Image Cache

Deploy a Docker Registry pull-through cache and optional web UI with Pigsty.

Pigsty provides the app/registry template (conf/app/registry.yml) for:

  • Docker Registry cache service (default 5000)
  • Optional management UI (default 5080)

Quick Start

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/registry
vi pigsty.yml                 # update domains, certs, and ports if needed
./deploy.yml
./docker.yml
./app.yml

Default endpoints:

  • Registry API: http://<IP>:5000 or http://d.pigsty
  • Registry UI: http://<IP>:5080 or http://dui.pigsty

Image data is stored in /data/registry by default.

Docker Client Configuration

If you run HTTP without TLS, Docker must trust the registry explicitly:

{
  "registry-mirrors": ["http://d.pigsty"],
  "insecure-registries": ["d.pigsty:5000"]
}

After editing /etc/docker/daemon.json, restart Docker:

systemctl restart docker

Operations

app/registry/Makefile runs in /opt/registry by default:

cd /opt/registry
make up
make status
make health
make log

References

6.17 - JumpServer: Open-Source Bastion Host

Self-host JumpServer Community Edition with Pigsty managing its PostgreSQL backend, backups, ingress, and operations.

JumpServer is an open-source PAM and bastion-host system for centralized access management of SSH, RDP, database, and web assets. Pigsty’s app/jumpserver template runs the JumpServer Community Edition application layer with Docker Compose and uses Pigsty-managed PostgreSQL as its persistent backend database.

The current template is based on JumpServer v4.10.16-ce. It retains the Community Edition core, celery, koko, lion, chen, and web services plus local Redis, while removing the built-in PostgreSQL service from the upstream installer. Pigsty manages PostgreSQL, backups, monitoring, Nginx ingress, and the database lifecycle.


Quick Start

On a fresh x86 or ARM Linux server running a compatible operating system:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/jumpserver
vi pigsty.yml                 # Required: change passwords, keys, domains, and IPs

./deploy.yml                  # Install Pigsty, Infra, Etcd, and PostgreSQL
./docker.yml                  # Install Docker and Compose
./app.yml                     # Install JumpServer

Run the database migration once after the containers start:

cd /opt/jumpserver
make migrate
make health

Default endpoints:

http://jump.pigsty
http://10.10.10.10:8080
ssh -p 2222 [email protected]

Default web login:

admin / ChangeMe

Change the administrator password immediately after the first login.


Pre-Deployment Checklist

  • Prepare a fresh Linux server with at least 2C4G; use more memory and configure swap for production.
  • Verify that the server IP, DNS, NTP, SSH, and sudo work correctly.
  • Verify access to Docker Hub, or configure docker_registry_mirrors / proxy_env.
  • After running ./configure -c app/jumpserver, change the default passwords, SECRET_KEY, BOOTSTRAP_TOKEN, and DOMAINS in pigsty.yml.
  • Ensure that DOMAINS contains the hostname or IP actually used by the browser, such as 10.10.10.10:8080.
  • Ensure that PostgreSQL backup jobs work; check pig pb info or pgbackrest info after deployment.

Configuration Template

conf/app/jumpserver.yml defines a single-node self-hosted JumpServer template. The default topology includes:

  • jumpserver: the node running JumpServer application containers and local Redis.
  • pg-jumpserver: the Pigsty-managed PostgreSQL cluster.
  • infra: Nginx ingress, Grafana, VictoriaMetrics, and other infrastructure.
  • etcd: the distributed configuration store required by Patroni.

app.yml copies app/jumpserver to /opt/jumpserver, overwrites /opt/jumpserver/.env with apps.jumpserver.conf, and then runs docker compose up -d.

Core application services:

  • jms_core: Django API and web backend, listening on container port 8080.
  • jms_celery: asynchronous jobs, scheduled jobs, and background queues.
  • jms_web: Nginx web ingress, mapped to host port 8080 by default.
  • jms_koko: SSH / SFTP terminal endpoint, mapped to host port 2222 by default.
  • jms_lion: Web Terminal component.
  • jms_chen: WebSocket and database-terminal support component.
  • jms_redis: local Redis for caching, queues, and the Channels backend.

Key Parameters

Common parameters:

ParameterDefaultDescription
JUMPSERVER_VERSIONv4.10.16-ceJumpServer Community Edition image version
JUMPSERVER_DATA/data/jumpserverPersistent application directory
DOMAINS10.10.10.10:8080,10.10.10.10,jump.pigstyTrusted domains and IPs allowed for login
SECRET_KEYExample valueEncryption key; replace and retain it for production
BOOTSTRAP_TOKENExample valueComponent registration token; replace and retain it for production
DB_HOST / DB_PORT10.10.10.10 / 5432Pigsty PostgreSQL endpoint
DB_USER / DB_NAMEjumpserver / jumpserverApplication user and database
DB_PASSWORDDBUser.JumpServerApplication user password; replace it for production
DOCKER_SUBNET192.168.250.0/24Internal JumpServer Compose subnet
REDIS_HOST192.168.250.2Fixed IP of the local Redis container
CORE_HOSThttp://192.168.250.4:8080Internal JumpServer core endpoint
HTTP_PORT8080Web ingress port
SSH_PORT2222Koko SSH/SFTP endpoint port
CORE_WORKER2Number of core Gunicorn workers, sized for a 2C4G sandbox
CELERY_WORKER_COUNT2Worker concurrency for each Celery queue

Example commands for generating production keys:

openssl rand -base64 36 | tr -dc A-Za-z0-9 | head -c 48; echo
openssl rand -base64 24 | tr -dc A-Za-z0-9 | head -c 24; echo
Production keys must remain stable

Do not change SECRET_KEY or BOOTSTRAP_TOKEN after production data exists. Store them together with database backups, /data/jumpserver, and /opt/jumpserver/.env. Losing the original SECRET_KEY may make encrypted account credentials in the database unrecoverable.

Password character restrictions

Do not use single or double quotes in DB_PASSWORD or REDIS_PASSWORD. This matches the behavior of the official JumpServer installer.


Login and DOMAINS

JumpServer validates trusted access domains during login. DOMAINS must include the Host actually used by the browser:

DOMAINS=10.10.10.10:8080,10.10.10.10,jump.pigsty

Normal login URL:

http://10.10.10.10:8080/core/auth/login/?admin=1

If the login page shows:

There is a problem with the configuration file; unable to log in...
DOMAINS=10.10.10.10:8080

Check /opt/jumpserver/.env and the container environment:

cd /opt/jumpserver
grep '^DOMAINS=' .env
docker exec jms_core env | grep '^DOMAINS='

Recreate the core container after correcting it:

sudo sed -i 's#^DOMAINS=.*#DOMAINS=10.10.10.10:8080,10.10.10.10,jump.pigsty#' /opt/jumpserver/.env
docker compose up -d --force-recreate core

Also update pigsty.yml or conf/app/jumpserver.yml; otherwise, the next ./app.yml run will overwrite /opt/jumpserver/.env again.

Do not use an old URL containing csrf_failure=1 to determine whether the configuration is still wrong. That page displays the DOMAINS=... warning using the failed request context. Retest with the normal login page and use an incognito window if necessary.


Docker Network

The template uses a fixed Docker bridge subnet:

DOCKER_SUBNET=192.168.250.0/24
REDIS_IP=192.168.250.2
CELERY_IP=192.168.250.3
CORE_IP=192.168.250.4
LION_IP=192.168.250.5
CHEN_IP=192.168.250.6
KOKO_IP=192.168.250.7
WEB_IP=192.168.250.8

Fixed IPs serve two purposes:

  • Avoid transient Docker DNS resolution failures while JumpServer Python and Java components start.
  • Allow PostgreSQL HBA rules to permit the application subnet precisely.

PostgreSQL sees container clients as coming from 192.168.250.0/24, so the template includes:

pg_hba_rules:
  - { user: jumpserver ,db: jumpserver ,addr: 192.168.250.0/24 ,auth: pwd ,order: 560 ,title: 'allow jumpserver access from docker bridge' }
pgb_hba_rules:
  - { user: jumpserver ,db: jumpserver ,addr: 192.168.250.0/24 ,auth: pwd ,order: 390 ,title: 'allow jumpserver pgbouncer access from docker bridge' }

If 192.168.250.0/24 conflicts with an existing network, update all of the following together:

  • DOCKER_SUBNET and the fixed IP for each component.
  • REDIS_HOST and CORE_HOST.
  • pg_hba_rules.addr and pgb_hba_rules.addr.
  • Recreate the Compose network and containers.

Do not set DB_HOST to 127.0.0.1; inside a container, that address refers to the container itself. Use the host’s private IP or the Pigsty L2 VIP.


PostgreSQL

JumpServer 4.x uses PostgreSQL and requires PostgreSQL 16 or later. The template uses Pigsty to create the database, user, HBA rules, backup schedule, and optional PgBouncer endpoint.

The application database does not require additional PostgreSQL extensions:

pg_extensions: []
pg_users:
  - { name: jumpserver ,password: DBUser.JumpServer ,pgbouncer: true ,pool_mode: session ,roles: [ dbrole_admin ] }
pg_databases:
  - { name: jumpserver ,owner: jumpserver }

The template’s pg_version can be pinned to 16, 17, or a later major version for your environment; JumpServer requires at least PostgreSQL 16. For a high-availability database deployment, follow the commented pg_vip_enabled example in the template and point the application’s DB_HOST to the primary-database VIP.

Do not use PgBouncer transaction pooling

JumpServer’s Django migrations and Celery Beat are unsuitable for PgBouncer transaction pooling. The default is a direct PostgreSQL connection on port 5432. If you use PgBouncer, configure session pooling for the jumpserver user.


Deployment Verification

After installation, run:

cd /opt/jumpserver
make status
make health
make migrate

Expected results:

  • jms_core, jms_celery, jms_web, jms_redis, jms_koko, jms_lion, and jms_chen are all healthy.
  • make health returns status=true, db_status=true, and redis_status=true.
  • make migrate prints No migrations to apply or completes any pending migrations.

Database checks:

sudo -iu postgres patronictl -c /etc/patroni/patroni.yml list
sudo -iu postgres psql -Atqc "select current_setting('server_version'), count(*) from information_schema.tables where table_schema='public'" jumpserver
sudo -iu postgres pgbackrest --stanza=pg-jumpserver info

Expected results:

  • The Patroni cluster Leader is running.
  • PostgreSQL is version 16 or later.
  • The public schema contains about 168 tables after JumpServer migrations.
  • The pgBackRest stanza status is ok.

Troubleshooting

Login Page Reports a DOMAINS Configuration Error

Verify that both configuration layers match:

cd /opt/jumpserver
grep '^DOMAINS=' .env
docker exec jms_core env | grep '^DOMAINS='

You must recreate the core container after changing .env:

docker compose up -d --force-recreate core

Also update apps.jumpserver.conf.DOMAINS in the Pigsty inventory; otherwise, the next ./app.yml run will overwrite it.

admin / ChangeMe Cannot Log In

First distinguish between two kinds of errors:

  • A red DOMAINS=... box at the top of the page indicates a domain / CSRF configuration problem, not a password problem.
  • A form message reporting an incorrect username or password indicates a credential problem.

You can verify inside the container whether the default password is still valid:

docker exec -w /opt/jumpserver/apps jms_core python -c '
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
import django; django.setup()
from django.contrib.auth import get_user_model
u = get_user_model().objects.get(username="admin")
print(u.is_active, u.check_password("ChangeMe"))
'

Web Returns 502

Check core and web:

cd /opt/jumpserver
docker compose ps
docker logs --tail 100 jms_core
docker logs --tail 100 jms_web

If the problem is a race over the core log directory during the first start, confirm that /data/jumpserver/core/data/logs exists. The template creates this directory in advance.

Containers Keep Restarting or Health Checks Time Out

JumpServer uses substantial memory on a 2C4G node. The template defaults to:

CORE_WORKER=2
CELERY_WORKER_COUNT=2

If Gunicorn worker timeouts, SIGKILL, or system memory exhaustion still occur, add memory or swap, or reduce the worker counts further. Check resource usage with:

free -h
docker stats --no-stream

Operations

After installation, enter /opt/jumpserver:

cd /opt/jumpserver

make up        # Start JumpServer
make down      # Stop JumpServer
make restart   # Restart containers
make status    # Show container status
make log       # Follow logs
make health    # Check HTTP / DB / Redis health
make migrate   # Run ./jms upgrade_db
make exec      # Enter the core container

When upgrading JumpServer, do not only change the image tag; you must run database migrations:

cd /opt/jumpserver
make pull
make down
docker compose up -d redis core
make migrate
make up

Keep SECRET_KEY and BOOTSTRAP_TOKEN unchanged during the upgrade.


Backup and Restore

JumpServer state has two layers:

  • PostgreSQL database: back up with Pigsty pgBackRest / PITR.
  • Application files: /data/jumpserver and /opt/jumpserver/.env, which contain logs, recordings, component data, Redis persistence, and keys.

Restore the database, .env, and file directory from the same environment:

# 1. Restore PostgreSQL with Pigsty pgBackRest / PITR
# 2. Restore /opt/jumpserver/.env and /data/jumpserver
# 3. Start the containers and run migrations
cd /opt/jumpserver
make up
make migrate
make health

Restoring PostgreSQL without the original SECRET_KEY prevents JumpServer from decrypting stored account credentials correctly.


Community Edition Scope

This template uses PostgreSQL as JumpServer’s own backend database and follows the self-hosted Community Edition deployment path. JumpServer’s “database asset management” is a separate product capability and is not the same as this backend database.


References

6.18 - ByteBase: Schema Migration

Deploy Bytebase with Pigsty’s Docker Compose template and connect it to external PostgreSQL.

Bytebase is a database schema change and version management tool.

Pigsty provides a ready-to-use Compose template in app/bytebase. It listens on 8887 by default and connects to external PostgreSQL via BB_PGURL.

Quick Start

cd ~/pigsty/app/bytebase
vi .env         # check BB_PORT / BB_DOMAIN / BB_PGURL
make up

Access:

  • http://ddl.pigsty
  • http://<IP>:8887

After first startup, initialize the admin account using the Bytebase setup wizard.

External PostgreSQL

Default connection string example:

postgresql://dbuser_bytebase:[email protected]:5432/bytebase?sslmode=prefer

You can create the database user and database in Pigsty first:

bin/pgsql-user pg-meta dbuser_bytebase
bin/pgsql-db   pg-meta bytebase

Common Commands

make up
make log
make info
make stop
make clean

References

6.19 - pgAdmin: PostgreSQL GUI

Deploy pgAdmin4 with Pigsty’s Docker Compose template and safely load the PostgreSQL server inventory.

pgAdmin is an open-source PostgreSQL administration and development GUI. Pigsty v4.5.0 provides the app/pgadmin Docker Compose template and can generate a server list and password file from the current inventory.

Change the defaults first

The template login is [email protected] with password pigsty. It is suitable only for a local demo. Before deployment on a shared network or the Internet, change the credentials, restrict port access, and configure HTTPS.


Quick Start

conf/meta.yml declares pgAdmin on the app group by default. Deploy it against an explicitly limited target:

./docker.yml -l app
./app.yml -l app -e app=pgadmin

The default port is 8885; use http://<app_ip>:8885. http://adm.pigsty works only after infra_portal, Nginx, and DNS are configured.

The first container start can take tens of seconds. Check it on the application node:

cd /opt/pgadmin
make info
make log

Application Configuration

Override .env through apps.pgadmin.conf on the app group in pigsty.yml:

all:
  children:
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true
        app: pgadmin
        apps:
          pgadmin:
            conf:
              PGADMIN_DEFAULT_EMAIL: [email protected]
              PGADMIN_DEFAULT_PASSWORD: <strong-random-password>
              PGADMIN_LISTEN_ADDRESS: 0.0.0.0
              PGADMIN_PORT: 8885
              PGADMIN_SERVER_JSON_FILE: /pgadmin4/servers.json
              PGADMIN_REPLACE_SERVERS_ON_STARTUP: true

app.yml copies the template to /opt/pgadmin and writes overrides to /opt/pgadmin/.env. This file contains the login password and should remain mode 0600.

The current template uses the unpinned dpage/pgadmin4 image. For production, pin a tested version or digest in docker-compose.yml and validate image upgrades as separate changes.


Load the Server List

env_pgadmin generates:

  • /infra/pgadmin/servers.json: PostgreSQL instance list
  • /infra/pgadmin/pgpass: database administrator password file

In the default conf/meta.yml, the infra and app groups point to the same host, so pgAdmin can bind-mount both files read-only. If pgAdmin and Infra run on different hosts, the application node does not automatically have /infra/pgadmin/; securely distribute equivalent files or customize the mounts instead of assuming that a local path is shared across hosts.

For the default colocated topology, regenerate the files and then ask the running container to import the list and password:

./infra.yml -l infra -t env_pgadmin

./app.yml -l app -e app=pgadmin -t app_launch -e app_args=reload

pgpass contains credentials for pg_admin_username. Restrict access to the files, backups, and application host. If pgAdmin should not hold DBA credentials, generate connection definitions for a dedicated least-privilege role instead.


Domain and HTTPS

Add an entry to infra_portal:

all:
  vars:
    infra_portal:
      pgadmin:
        domain: adm.pigsty
        endpoint: "10.10.10.10:8885"

Update Nginx on the explicitly limited Infra group:

./infra.yml -l infra -t nginx

For a real public domain, point DNS at the server and set certbot on the portal entry:

infra_portal:
  pgadmin:
    domain: adm.example.com
    endpoint: "10.10.10.10:8885"
    certbot: adm.example.com
./infra.yml -l infra -t nginx_certbot,nginx_reload -e certbot_sign=true

See CA and Certificates for prerequisites and renewal. The directly exposed port 8885 is not an HTTPS endpoint.


State and Management

From /opt/pgadmin:

make up       # docker compose up -d
make view     # show access endpoints
make log      # follow container logs
make info     # docker inspect
make conf     # re-import server list and pgpass
make stop     # stop the container
make restart  # restart the container

The Compose template does not persist /var/lib/pgadmin. Pigsty can re-import its generated server list, but preferences, users, and other state created in the pgAdmin UI may be lost when the container is recreated. If that state matters, add a protected persistent volume for the directory and include it in backups after validating the template change.

pgAdmin

Security Checklist

  • Change the default pgAdmin login and never distribute real credentials in scripts, screenshots, or tickets.
  • The default port mapping listens on the host network; restrict sources with a firewall and use Nginx with valid HTTPS for Internet access.
  • Protect /infra/pgadmin/pgpass and /opt/pgadmin/.env; prefer a least-privilege database role.
  • Pin and validate the container image, and back up any pgAdmin state you choose to persist.
  • pgAdmin can execute privileged SQL. Dropping a database, table, or data still requires separate target confirmation and a recent backup.

6.20 - PGWeb: Browser-based PostgreSQL Client

Run the bundled pgweb Docker application for small, interactive PostgreSQL queries from a browser.

PGWeb Client

PGWeb is a browser-based PostgreSQL client. Pigsty includes a small Docker Compose template under app/pgweb; it publishes container port 8081 on host port 8886.

cd ~/pigsty/app/pgweb
make up                    # docker compose up -d

Open http://cli.pigsty when that portal entry resolves to the Infra node, or browse directly to http://10.10.10.10:8886. The public demo is http://cli.pigsty.cc.

PGWeb asks for a PostgreSQL connection URL. For example:

postgres://dbuser_meta:[email protected]:5432/meta?sslmode=disable
postgres://test:[email protected]:5432/test?sslmode=disable

These strings contain public demonstration defaults and disable TLS. Use a least-privilege account, a non-default secret, and an appropriate sslmode for real deployments; do not expose an unauthenticated PGWeb container or database credentials to untrusted networks.

PGWeb

Shortcuts

The bundled Makefile provides:

make up         # launch with docker compose
make run        # launch with docker run
make view       # print the local access point and example URL
make log        # follow container logs
make info       # inspect the container with jq
make stop       # stop the container
make clean      # stop and remove the container
make pull       # pull the current unpinned sosedoff/pgweb image
make rmi        # remove the local image
make save       # save the image to /tmp/docker/pgweb.tgz
make load       # load it from /tmp/docker/pgweb.tgz

The template currently uses the unpinned sosedoff/pgweb image. Pin an image digest or version in app/pgweb/docker-compose.yml when reproducible production deployment matters.

6.21 - PostgREST: Auto-Generated API

Deploy PostgREST with Pigsty Compose templates and auto-generate REST APIs from PostgreSQL schema.

PostgREST exposes PostgreSQL schemas directly as REST APIs.

Pigsty provides the app/postgrest template, with default port 8884.

Quick Start

cd ~/pigsty/app/postgrest
vi .env         # check DB_URI / DB_SCHEMA / JWT
make up

Default endpoints:

  • http://<IP>:8884
  • http://api.pigsty (if ingress domain is configured)

Key Settings

Common .env parameters:

  • POSTGREST_DB_URI: database connection string
  • POSTGREST_DB_SCHEMA: exposed schema (default pigsty)
  • POSTGREST_DB_ANON_ROLE: anonymous role
  • POSTGREST_JWT_SECRET: JWT secret

Swagger UI (Optional)

You can run Swagger UI separately to preview APIs:

docker run --rm --name swagger -p 8882:8080 \
  -e API_URL=http://10.10.10.10:8884 \
  swaggerapi/swagger-ui

Then open http://<IP>:8882.

Common Commands

make up
make log
make stop
make clean

References

6.22 - Electric: PostgreSQL Sync Engine

Self-host Electric with Pigsty to sync PostgreSQL data to frontend apps with partial replication and real-time delivery.

Electric is a PostgreSQL sync engine focused on efficiently delivering database changes to frontend and edge applications.

Pigsty provides the app/electric template (conf/app/electric.yml) to bootstrap database, container, and ingress settings in one flow.

Quick Start

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./bootstrap
./configure -c app/electric
vi pigsty.yml                 # update domain, passwords, secrets
./deploy.yml
./docker.yml
./app.yml

Default endpoints:

  • http://<IP>:8002
  • http://elec.pigsty (default domain in the template)

Metrics port defaults to 8003 (ELECTRIC_PROMETHEUS_PORT).

Key Settings

conf/app/electric.yml writes apps.electric.conf into /opt/electric/.env. Common parameters:

  • DATABASE_URL: PostgreSQL connection string used by Electric (replication privileges required)
  • ELECTRIC_PORT: Electric HTTP port (default 8002)
  • ELECTRIC_PROMETHEUS_PORT: metrics port (default 8003)
  • ELECTRIC_INSECURE: can be true in dev; disable in prod and use proper secrets

Operations

cd /opt/electric
make up
make logs
make down

References

6.23 - Jupyter: Notebooks and Data Analysis

Run JupyterLab with Pigsty’s standalone Docker Compose template and access PostgreSQL safely.

JupyterLab is an interactive notebook, terminal, and data-analysis environment. Pigsty v4.5.0 has two distinct deployment paths:

  • The VIBE module, managed by Ansible and systemd, for the complete v4.5.0 development sandbox.
  • The lightweight standalone app/jupyter Docker Compose template documented here.

app/jupyter is not a default apps inventory entry, and data-directory preparation is a separate step. Do not assume that app.yml -e app=jupyter handles its directory ownership.

JupyterLab

Quick Start

cd ~/pigsty/app/jupyter
vi .env                    # change JUPYTER_TOKEN and optionally pin JUPYTER_IMAGE
chmod 600 .env
make dir                   # create /data/jupyter, owned by 1000:100
make up                    # docker compose up -d

Generate a strong token with openssl rand -hex 32. The default port is 8888; open http://<host_ip>:8888.

lab.pigsty works only when that name is configured in infra_portal, Nginx, and DNS. The template default JUPYTER_TOKEN=pigsty is for local demonstrations only and must be replaced in production.


Current Template

The v4.5.0 .env defaults are:

JUPYTER_IMAGE=quay.io/jupyter/minimal-notebook:latest
JUPYTER_PORT=8888
JUPYTER_TOKEN=pigsty

Compose mounts host /data/jupyter at /home/jovyan/work and passes the token into the container. The latest tag changes upstream; production deployments should use a tested, explicit image tag or digest.

For SciPy, R, Julia, TensorFlow, PyTorch, or Spark, select another Jupyter Docker Stacks image listed in .env, while still pinning its version and validating architecture support.


Access PostgreSQL

Install the modern Psycopg driver and optional analysis libraries from a Jupyter terminal:

pip install "psycopg[binary]" pandas sqlalchemy

Do not store real passwords in notebooks. This example obtains the connection string through hidden input and reads system information only:

from getpass import getpass
import psycopg

pgurl = getpass("PostgreSQL URL: ")
with psycopg.connect(pgurl) as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT current_database(), current_user, version()")
        print(cur.fetchone())

Use Pandas and SQLAlchemy with a system statistics view:

import pandas as pd
from sqlalchemy import create_engine

engine = create_engine(pgurl)
df = pd.read_sql(
    "SELECT datname, numbackends, xact_commit, xact_rollback "
    "FROM pg_stat_database ORDER BY datname",
    engine,
)
df

These examples access system views only. Obtain authorization from the data owner before reading application tables, and limit columns, predicates, and result size.


Persistence and Dependencies

Only /home/jovyan/work is mapped to /data/jupyter. The following are not persistent across container recreation by default:

  • Python or Conda packages installed temporarily inside the container
  • notebooks, configuration, and caches outside work
  • the container’s own user state

For production, install dependencies through a pinned image, custom Dockerfile, or reproducible dependency file, and back up /data/jupyter separately. A persistent mount is not a backup.


Management Commands

From ~/pigsty/app/jupyter:

make up      # start JupyterLab
make dir     # create the data directory with 1000:100 ownership
make view    # show access endpoints
make log     # follow logs
make info    # inspect the container
make stop    # stop the container
make pull    # pull the image selected in .env

make clean removes the container but retains /data/jupyter. make purge recursively deletes /data/jupyter; it is an unrecoverable data-deletion operation and requires confirmation of the exact directory and a recent backup.


Security Checklist

  • Use a strong random token, protect .env, and do not disable authentication.
  • The default port mapping listens on the host network. Restrict sources with a firewall and prefer Nginx with valid HTTPS.
  • A notebook can execute arbitrary code and access mounted files and databases. Grant only least-privilege database accounts and host directories.
  • Pin and scan the image, and validate dependency upgrades reproducibly.
  • Back up /data/jupyter regularly and test restoration to a temporary directory.

6.24 - PGLOG: PostgreSQL Log Analysis Application

A sample Applet included with Pigsty for analyzing PostgreSQL CSV log samples

PGLOG is a sample application included with Pigsty that uses the pglog.sample table in MetaDB as its data source. You simply need to load logs into this table, then access the related dashboard.

Pigsty provides convenient commands for pulling CSV logs and loading them into the sample table. On the meta node, the following shortcut commands are available by default:

catlog  [node=localhost]  [date=today]   # Print CSV log to stdout
pglog                                    # Load CSVLOG from stdin
pglog12                                  # Load PG12 format CSVLOG
pglog13                                  # Load PG13 format CSVLOG
pglog14                                  # Load PG14 format CSVLOG (=pglog)

catlog | pglog                       # Analyze current node's log for today
catlog node-1 '2021-07-15' | pglog   # Analyze node-1's csvlog for 2021-07-15

Next, you can access the following links to view the sample log analysis interface.

  • PGLOG Overview: Present the entire CSV log sample details, aggregated by multiple dimensions.

PGLOG overview dashboard

  • PGLOG Session: Present detailed information about a specific connection in the log sample.

PGLOG session dashboard

The catlog command pulls CSV database logs from a specific node for a specific date and writes to stdout

By default, catlog pulls logs from the current node for today. You can specify the node and date through parameters.

Using pglog and catlog together, you can quickly pull database CSV logs for analysis.

catlog | pglog                       # Analyze current node's log for today
catlog node-1 '2021-07-15' | pglog   # Analyze node-1's csvlog for 2021-07-15

6.25 - NOAA ISD Global Weather Station Historical Data Query

Demonstrate how to import data into a database using the ISD dataset as an example

If you have a database and don’t know what to do with it, why not try this open-source project: Vonng/isd

You can directly reuse the monitoring system Grafana to interactively browse sub-hourly meteorological data from nearly 30,000 surface weather stations over the past 120 years.

This is a fully functional data application that can query meteorological observation records from 30,000 global surface weather stations since 1901.

Project URL: https://github.com/Vonng/isd

Online Demo: https://demo.pigsty.io/d/isd-overview

isd-overview.jpg

Quick Start

Clone this repository

git clone https://github.com/Vonng/isd.git; cd isd;

Prepare a PostgreSQL instance

The PostgreSQL instance should have the PostGIS extension enabled. Use the PGURL environment variable to pass database connection information:

# Pigsty uses dbuser_dba as the default admin account with password DBUser.DBA
export PGURL=postgres://dbuser_dba:[email protected]:5432/meta?sslmode=disable
psql "${PGURL}" -c 'SELECT 1'  # Check if connection is available

Fetch and import ISD weather station metadata

This is a daily-updated weather station metadata file containing station longitude/latitude, elevation, name, country, province, and other information. Use the following command to download and import:

make reload-station   # Equivalent to downloading the latest station data then loading: get-station + load-station

Fetch and import the latest isd.daily data

isd.daily is a daily-updated dataset containing daily observation data summaries from global weather stations. Use the following command to download and import. Note that raw data downloaded directly from the NOAA website needs to be parsed before it can be loaded into the database, so you need to download or build an ISD data parser.

make get-parser       # Download the parser binary from Github, or you can build directly with go using make build
make reload-daily     # Download and import the latest isd.daily data for this year into the database

Load pre-parsed CSV dataset

The ISD Daily dataset has some dirty data and duplicate data. If you don’t want to manually parse and clean it, a stable pre-parsed CSV dataset is also provided here.

This dataset contains isd.daily data up to 2023-06-24. You can download and import it directly into PostgreSQL without needing a parser.

make get-stable       # Get the stable isd.daily historical dataset from Github
make load-stable      # Load the downloaded stable historical dataset into the PostgreSQL database

More Data

Two parts of the ISD dataset are updated daily: weather station metadata and the latest year’s isd.daily (e.g., the 2023 tarball).

You can use the following command to download and refresh these two parts. If the dataset hasn’t been updated, these commands won’t re-download the same data package:

make reload           # Actually: reload-station + reload-daily

You can also use the following commands to download and load isd.daily data for a specific year:

bin/get-daily  2022                   # Get daily weather observation summary for 2022 (1900-2023)
bin/load-daily "${PGURL}" 2022        # Load daily weather observation summary for 2022 (1900-2023)

In addition to the daily summary isd.daily, ISD also provides more detailed sub-hourly raw observation records isd.hourly. The download and load methods are similar:

bin/get-hourly  2022                  # Download hourly observation records for a specific year (e.g., 2022, options 1900-2023)
bin/load-hourly "${PGURL}" 2022       # Load hourly observation records for a specific year

Data

Dataset Overview

ISD provides four datasets: sub-hourly raw observation data, daily statistical summary data, monthly statistical summary, and yearly statistical summary

DatasetNotes
ISD HourlySub-hourly observation records
ISD DailyDaily statistical summary
ISD MonthlyNot used, can be calculated from isd.daily
ISD YearlyNot used, can be calculated from isd.daily

Daily Summary Dataset

  • Compressed package size 2.8GB (as of 2023-06-24)
  • Table size 24GB, index size 6GB, total size approximately 30GB in PostgreSQL
  • If timescaledb compression is enabled, total size can be compressed to 4.5 GB

Sub-hourly Observation Data

  • Total compressed package size 117GB
  • After loading into database: table size 1TB+, index size 600GB+, total size 1.6TB

Database Schema

Weather Station Metadata Table

CREATE TABLE isd.station
(
    station    VARCHAR(12) PRIMARY KEY,
    usaf       VARCHAR(6) GENERATED ALWAYS AS (substring(station, 1, 6)) STORED,
    wban       VARCHAR(5) GENERATED ALWAYS AS (substring(station, 7, 5)) STORED,
    name       VARCHAR(32),
    country    VARCHAR(2),
    province   VARCHAR(2),
    icao       VARCHAR(4),
    location   GEOMETRY(POINT),
    longitude  NUMERIC GENERATED ALWAYS AS (Round(ST_X(location)::NUMERIC, 6)) STORED,
    latitude   NUMERIC GENERATED ALWAYS AS (Round(ST_Y(location)::NUMERIC, 6)) STORED,
    elevation  NUMERIC,
    period     daterange,
    begin_date DATE GENERATED ALWAYS AS (lower(period)) STORED,
    end_date   DATE GENERATED ALWAYS AS (upper(period)) STORED
);

Daily Summary Table

CREATE TABLE IF NOT EXISTS isd.daily
(
    station     VARCHAR(12) NOT NULL, -- station number 6USAF+5WBAN
    ts          DATE        NOT NULL, -- observation date
    -- Temperature & Dew Point
    temp_mean   NUMERIC(3, 1),        -- mean temperature ℃
    temp_min    NUMERIC(3, 1),        -- min temperature ℃
    temp_max    NUMERIC(3, 1),        -- max temperature ℃
    dewp_mean   NUMERIC(3, 1),        -- mean dew point ℃
    -- Air Pressure
    slp_mean    NUMERIC(5, 1),        -- sea level pressure (hPa)
    stp_mean    NUMERIC(5, 1),        -- station pressure (hPa)
    -- Visibility
    vis_mean    NUMERIC(6),           -- visible distance (m)
    -- Wind Speed
    wdsp_mean   NUMERIC(4, 1),        -- average wind speed (m/s)
    wdsp_max    NUMERIC(4, 1),        -- max wind speed (m/s)
    gust        NUMERIC(4, 1),        -- max wind gust (m/s)
    -- Precipitation / Snow Depth
    prcp_mean   NUMERIC(5, 1),        -- precipitation (mm)
    prcp        NUMERIC(5, 1),        -- rectified precipitation (mm)
    sndp        NuMERIC(5, 1),        -- snow depth (mm)
    -- FRSHTT (Fog/Rain/Snow/Hail/Thunder/Tornado)
    is_foggy    BOOLEAN,              -- (F)og
    is_rainy    BOOLEAN,              -- (R)ain or Drizzle
    is_snowy    BOOLEAN,              -- (S)now or pellets
    is_hail     BOOLEAN,              -- (H)ail
    is_thunder  BOOLEAN,              -- (T)hunder
    is_tornado  BOOLEAN,              -- (T)ornado or Funnel Cloud
    -- Record counts used for statistical aggregation
    temp_count  SMALLINT,             -- record count for temp
    dewp_count  SMALLINT,             -- record count for dew point
    slp_count   SMALLINT,             -- record count for sea level pressure
    stp_count   SMALLINT,             -- record count for station pressure
    wdsp_count  SMALLINT,             -- record count for wind speed
    visib_count SMALLINT,             -- record count for visible distance
    -- Temperature flags
    temp_min_f  BOOLEAN,              -- aggregate min temperature
    temp_max_f  BOOLEAN,              -- aggregate max temperature
    prcp_flag   CHAR,                 -- precipitation flag: ABCDEFGHI
    PRIMARY KEY (station, ts)
); -- PARTITION BY RANGE (ts);

Sub-hourly Raw Observation Data Table

ISD Hourly
CREATE TABLE IF NOT EXISTS isd.hourly
(
    station    VARCHAR(12) NOT NULL, -- station id
    ts         TIMESTAMP   NOT NULL, -- timestamp
    -- air
    temp       NUMERIC(3, 1),        -- [-93.2,+61.8]
    dewp       NUMERIC(3, 1),        -- [-98.2,+36.8]
    slp        NUMERIC(5, 1),        -- [8600,10900]
    stp        NUMERIC(5, 1),        -- [4500,10900]
    vis        NUMERIC(6),           -- [0,160000]
    -- wind
    wd_angle   NUMERIC(3),           -- [1,360]
    wd_speed   NUMERIC(4, 1),        -- [0,90]
    wd_gust    NUMERIC(4, 1),        -- [0,110]
    wd_code    VARCHAR(1),           -- code that denotes the character of the WIND-OBSERVATION.
    -- cloud
    cld_height NUMERIC(5),           -- [0,22000]
    cld_code   VARCHAR(2),           -- cloud code
    -- water
    sndp       NUMERIC(5, 1),        -- mm snow
    prcp       NUMERIC(5, 1),        -- mm precipitation
    prcp_hour  NUMERIC(2),           -- precipitation duration in hour
    prcp_code  VARCHAR(1),           -- precipitation type code
    -- sky
    mw_code    VARCHAR(2),           -- manual weather observation code
    aw_code    VARCHAR(2),           -- auto weather observation code
    pw_code    VARCHAR(1),           -- weather code of past period of time
    pw_hour    NUMERIC(2),           -- duration of pw_code period
    -- misc
    -- remark     TEXT,
    -- eqd        TEXT,
    data       JSONB                 -- extra data
) PARTITION BY RANGE (ts);

Parser

The raw data provided by NOAA ISD is in a highly compressed proprietary format that needs to be processed through a parser before it can be converted into database table format.

For the Daily and Hourly datasets, two parsers are provided here: isdd and isdh. Both parsers take annual data compressed packages as input, produce CSV results as output, and work in pipeline mode as shown below:

NAME
        isd -- Integrated Surface Dataset Parser

SYNOPSIS
        isd daily   [-i <input|stdin>] [-o <output|stout>] [-v]
        isd hourly  [-i <input|stdin>] [-o <output|stout>] [-v] [-d raw|ts-first|hour-first]

DESCRIPTION
        The isd program takes noaa isd daily/hourly raw tarball data as input.
        and generate parsed data in csv format as output. Works in pipe mode

        cat data/daily/2023.tar.gz | bin/isd daily -v | psql ${PGURL} -AXtwqc "COPY isd.daily FROM STDIN CSV;"

        isd daily  -v -i data/daily/2023.tar.gz  | psql ${PGURL} -AXtwqc "COPY isd.daily FROM STDIN CSV;"
        isd hourly -v -i data/hourly/2023.tar.gz | psql ${PGURL} -AXtwqc "COPY isd.hourly FROM STDIN CSV;"

OPTIONS
        -i  <input>     input file, stdin by default
        -o  <output>    output file, stdout by default
        -p  <profpath>  pprof file path, enable if specified
        -d              de-duplicate rows for hourly dataset (raw, ts-first, hour-first)
        -v              verbose mode
        -h              print help

User Interface

Several dashboards made with Grafana are provided here for exploring the ISD dataset and querying weather stations and historical meteorological data.


ISD Overview

Global overview with overall metrics and weather station navigation.

isd-overview.jpg

ISD Country

Display all weather stations within a single country/region.

isd-country.jpg

ISD Station

Display detailed information for a single weather station, including metadata and daily/monthly/yearly summary metrics.

ISD Station Dashboard

isd-station.jpg


ISD Detail

Display raw sub-hourly observation metric data for a weather station, requires the isd.hourly dataset.

ISD Station Dashboard

isd-detail.jpg


6.26 - WHO COVID-19 Pandemic Dashboard

A sample Applet included with Pigsty for visualizing World Health Organization official pandemic data

Covid is a sample Applet included with Pigsty for visualizing the World Health Organization’s official pandemic data dashboard.

You can browse COVID-19 infection and death cases for each country and region, as well as global pandemic trends.


Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/covid

Online Demo: https://demo.pigsty.io/d/covid

COVID-19 analytics dashboard


Installation

Enter the application directory on the admin node and execute make to complete the installation.

make            # Complete all configuration

Other sub-tasks:

make reload     # download latest data and pour it again
make ui         # install grafana dashboards
make sql        # install database schemas
make download   # download latest data
make load       # load downloaded data into database
make reload     # download latest data and pour it into database

6.27 - StackOverflow Global Developer Survey

Analyze database-related data from StackOverflow’s global developer survey over the past seven years

Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/db

Online Demo: https://demo.pigsty.io/d/sf-survey

Stack Overflow database survey dashboard

6.28 - DB-Engines Database Popularity Trend Analysis

Analyze database management systems on DB-Engines and browse their popularity evolution

Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/db

Online Demo: https://demo.pigsty.io/d/db-engine

Database engine monitoring dashboard

6.29 - AWS & Aliyun Server Pricing

Analyze compute and storage pricing on Aliyun / AWS (ECS/ESSD)

Overview

GitHub Repository: https://github.com/pgsty/pigsty-app/tree/master/cloud

Online Demo: https://demo.pigsty.io/d/ecs

Article: Analyzing Computing Costs: Has Aliyun Really Reduced Prices?

Data Source

Aliyun ECS pricing can be obtained as raw CSV data from Price Calculator - Pricing Details - Price Download.

Schema

Download Aliyun pricing details and import for analysis

CREATE EXTENSION file_fdw;
CREATE SERVER fs FOREIGN DATA WRAPPER file_fdw;

DROP FOREIGN TABLE IF EXISTS aliyun_ecs CASCADE;
CREATE FOREIGN TABLE aliyun_ecs
    (
        "region" text,
        "system" text,
        "network" text,
        "isIO" bool,
        "instanceId" text,
        "hourlyPrice" numeric,
        "weeklyPrice" numeric,
        "standard" numeric,
        "monthlyPrice" numeric,
        "yearlyPrice" numeric,
        "2yearPrice" numeric,
        "3yearPrice" numeric,
        "4yearPrice" numeric,
        "5yearPrice" numeric,
        "id" text,
        "instanceLabel" text,
        "familyId" text,
        "serverType" text,
        "cpu" text,
        "localStorage" text,
        "NvmeSupport" text,
        "InstanceFamilyLevel" text,
        "EniTrunkSupported" text,
        "InstancePpsRx" text,
        "GPUSpec" text,
        "CpuTurboFrequency" text,
        "InstancePpsTx" text,
        "InstanceTypeId" text,
        "GPUAmount" text,
        "InstanceTypeFamily" text,
        "SecondaryEniQueueNumber" text,
        "EniQuantity" text,
        "EniPrivateIpAddressQuantity" text,
        "DiskQuantity" text,
        "EniIpv6AddressQuantity" text,
        "InstanceCategory" text,
        "CpuArchitecture" text,
        "EriQuantity" text,
        "MemorySize" numeric,
        "EniTotalQuantity" numeric,
        "PhysicalProcessorModel" text,
        "InstanceBandwidthRx" numeric,
        "CpuCoreCount" numeric,
        "Generation" text,
        "CpuSpeedFrequency" numeric,
        "PrimaryEniQueueNumber" text,
        "LocalStorageCategory" text,
        "InstanceBandwidthTx" text,
        "TotalEniQueueQuantity" text
        ) SERVER fs OPTIONS ( filename '/tmp/aliyun-ecs.csv', format 'csv',header 'true');

Similarly for AWS EC2, you can download the price list from Vantage:


DROP FOREIGN TABLE IF EXISTS aws_ec2 CASCADE;
CREATE FOREIGN TABLE aws_ec2
    (
        "name" TEXT,
        "id" TEXT,
        "Memory" TEXT,
        "vCPUs" TEXT,
        "GPUs" TEXT,
        "ClockSpeed" TEXT,
        "InstanceStorage" TEXT,
        "NetworkPerformance" TEXT,
        "ondemand" TEXT,
        "reserve" TEXT,
        "spot" TEXT
        ) SERVER fs OPTIONS ( filename '/tmp/aws-ec2.csv', format 'csv',header 'true');



DROP VIEW IF EXISTS ecs;
CREATE VIEW ecs AS
SELECT "region"                                       AS region,
       "id"                                           AS id,
       "instanceLabel"                                AS name,
       "familyId"                                     AS family,
       "CpuCoreCount"                                 AS cpu,
       "MemorySize"                                   AS mem,
       round("5yearPrice" / "CpuCoreCount" / 60, 2)   AS ycm5, -- ¥ / (core·month)
       round("4yearPrice" / "CpuCoreCount" / 48, 2)   AS ycm4, -- ¥ / (core·month)
       round("3yearPrice" / "CpuCoreCount" / 36, 2)   AS ycm3, -- ¥ / (core·month)
       round("2yearPrice" / "CpuCoreCount" / 24, 2)   AS ycm2, -- ¥ / (core·month)
       round("yearlyPrice" / "CpuCoreCount" / 12, 2)  AS ycm1, -- ¥ / (core·month)
       round("standard" / "CpuCoreCount", 2)          AS ycmm, -- ¥ / (core·month)
       round("hourlyPrice" / "CpuCoreCount" * 720, 2) AS ycmh, -- ¥ / (core·month)
       "CpuSpeedFrequency"::NUMERIC                   AS freq,
       "CpuTurboFrequency"::NUMERIC                   AS freq_turbo,
       "Generation"                                   AS generation
FROM aliyun_ecs
WHERE system = 'linux';

DROP VIEW IF EXISTS ec2;
CREATE VIEW ec2 AS
SELECT id,
       name,
       split_part(id, '.', 1)                                                               as family,
       split_part(id, '.', 2)                                                               as spec,
       (regexp_match(split_part(id, '.', 1), '^[a-zA-Z]+(\d)[a-z0-9]*'))[1]                 as gen,
       regexp_substr("vCPUs", '^[0-9]+')::int                                               as cpu,
       regexp_substr("Memory", '^[0-9]+')::int                                              as mem,
       CASE spot
           WHEN 'unavailable' THEN NULL
           ELSE round((regexp_substr("spot", '([0-9]+.[0-9]+)')::NUMERIC * 7.2), 2) END     AS spot,
       CASE ondemand
           WHEN 'unavailable' THEN NULL
           ELSE round((regexp_substr("ondemand", '([0-9]+.[0-9]+)')::NUMERIC * 7.2), 2) END AS ondemand,
       CASE reserve
           WHEN 'unavailable' THEN NULL
           ELSE round((regexp_substr("reserve", '([0-9]+.[0-9]+)')::NUMERIC * 7.2), 2) END  AS reserve,
       "ClockSpeed"                                                                         AS freq
FROM aws_ec2;

Visualization

Browse the interactive panels in the online demo: https://demo.pigsty.io/d/ecs

7 - Configuration Templates

Batteries-included configuration templates for specific scenarios, with detailed explanations.

Use -c with configure to select a template. Its value is a path relative to conf/ without the .yml suffix. If omitted, Pigsty uses the default meta template.

7.1 - meta

Default single-node installation template with extensive configuration parameter descriptions

The meta configuration template is Pigsty’s default template, designed to fulfill Pigsty’s core functionality—deploying PostgreSQL—on a single node.

To maximize compatibility, meta installs only the minimum required software set to ensure it runs across all operating system distributions and architectures.


Overview

  • Config Name: meta
  • Node Count: Single node
  • Description: Default single-node installation template with extensive configuration parameter descriptions and minimum required feature set.
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta, slim, fat

Usage: This is the default config template, so there’s no need to specify -c meta explicitly during configure:

./configure [-i <primary_ip>]

For example, if you want to install PostgreSQL 16 rather than the default 18, you can use the -v arg in configure:

./configure -v 16   # or 17, 15, 14; use the pg19 template for PG19 Beta

Content

Source: pigsty/conf/meta.yml

---
#==============================================================#
# File      :   meta.yml
# Desc      :   Pigsty default 1-node online install config
# Ctime     :   2020-05-22
# Mtime     :   2026-07-10
# Docs      :   https://pigsty.io/docs/conf/meta
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the default 1-node configuration template, with:
# INFRA, NODE, PGSQL, ETCD, MINIO, DOCKER, APP
# with basic pg extensions: postgis, pgvector
#
# Work with PostgreSQL 14-18 on all supported platform
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -g
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql
    #----------------------------------------------#
    # this is an example single-node postgres cluster with pgvector installed, with one biz database & two biz users
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica } # <---- read only replica for read-only online traffic
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline } # <---- offline instance of ETL & interactive queries
      vars:
        pg_cluster: pg-meta

        # install, load, create pg extensions: https://pigsty.io/docs/pgsql/ext/
        pg_extensions: [ postgis, pgvector ]

        # define business users/roles : https://pigsty.io/docs/pgsql/config/user
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }

        # define business databases : https://pigsty.io/docs/pgsql/config/db
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: "pigsty meta database"
            schemas: [pigsty]
            # define extensions in database : https://pigsty.io/docs/pgsql/ext/create
            extensions: [ postgis, vector ]

        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # define (OPTIONAL) L2 VIP that bind to primary
        #pg_vip_enabled: true
        #pg_vip_address: 10.10.10.2/24


    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: false   # disable in 1-node mode :  https://pigsty.io/docs/infra/admin/repo
        #repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # ETCD : https://pigsty.io/docs/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false             # prevent purging running etcd instance?

    #----------------------------------------------#
    # MINIO : https://pigsty.io/docs/minio
    #----------------------------------------------#
    #minio:
    #  hosts:
    #    10.10.10.10: { minio_seq: 1 }
    #  vars:
    #    minio_cluster: minio
    #    minio_users:                      # list of minio user to be created
    #      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
    #      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
    #      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://pigsty.io/docs/docker
    # APP    : https://pigsty.io/docs/app
    #----------------------------------------------#
    # launch example pgadmin app with: ./app.yml (http://10.10.10.10:8885 [email protected] / pigsty)
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true                # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin                        # specify the default app name to be installed (in the apps)
        apps:                               # define all applications, appname: definition
          pgadmin:                          # pgadmin app definition (app/pgadmin -> /opt/pgadmin)
            conf:                           # override /opt/pgadmin/.env
              PGADMIN_DEFAULT_EMAIL: [email protected]
              PGADMIN_DEFAULT_PASSWORD: pigsty


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
      pgadmin : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      #minio  : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts: ['${admin_ip} i.pigsty sss.pigsty']
    node_repo_modules: 'node,infra,pgsql' # add these repos directly to the singleton node
    #node_repo_modules: local             # use this if you want to build & user local repo
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with the latest version
    node_firewall_public_port: [22, 80, 443, 5432]    # expose 5432 for demo convenience, remove in production!

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_packages: [ pgsql-main, pgsql-common ]  # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # BACKUP : https://pigsty.io/docs/pgsql/backup
    #----------------------------------------------#
    # if you want to use minio as backup repo instead of 'local' fs, uncomment this, and configure `pgbackrest_repo`
    # you can also use external object storage as backup repo
    #pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    #pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
    #  local:                          # default pgbackrest repo with local posix fs
    #    path: /pg/backup              # local backup directory, `/pg/backup` by default
    #    retention_full_type: count    # retention full backups by count
    #    retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
    #  minio:                          # optional minio repo for pgbackrest
    #    type: s3                      # minio is s3-compatible, so s3 is used
    #    s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
    #    s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
    #    s3_bucket: pgsql              # minio bucket name, `pgsql` by default
    #    s3_key: pgbackrest            # minio user access key for pgbackrest
    #    s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
    #    s3_uri_style: path            # use path style uri for minio rather than host style
    #    path: /pgbackrest             # minio backup path, default is `/pgbackrest`
    #    storage_port: 9000            # minio port, 9000 by default
    #    storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
    #    block: y                      # Enable block incremental backup
    #    bundle: y                     # bundle small files into a single file
    #    bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
    #    bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
    #    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    #    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    #    retention_full_type: time     # retention full backup by time on minio repo
    #    retention_full: 14            # keep full backup for last 14 days
    #  s3: # aliyun oss (s3 compatible) object storage service
    #    type: s3                      # oss is s3-compatible
    #    s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
    #    s3_region: oss-cn-beijing
    #    s3_bucket: <your_bucket_name>
    #    s3_key: <your_access_key>
    #    s3_key_secret: <your_secret_key>
    #    s3_uri_style: host
    #    path: /pgbackrest
    #    bundle: y                     # bundle small files into a single file
    #    bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
    #    bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
    #    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    #    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    #    retention_full_type: time     # retention full backup by time on minio repo
    #    retention_full: 14            # keep full backup for last 14 days

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The meta template is Pigsty’s default getting-started configuration, designed for quick onboarding.

Use Cases:

  • First-time Pigsty users
  • Quick deployment in development and testing environments
  • Small production environments running on a single machine
  • As a base template for more complex deployments

Key Features:

  • Online installation mode without building local software repository (repo_enabled: false)
  • Default installs PostgreSQL 18 with postgis and pgvector extensions
  • Includes complete observability infrastructure (Grafana, VictoriaMetrics, VictoriaLogs, etc.)
  • Preconfigured Docker and pgAdmin application examples
  • Silo backup storage disabled by default, can be enabled as needed

Notes:

  • Default passwords are sample passwords; must be changed for production environments
  • Single-node etcd has no high availability guarantee, suitable for development and testing
  • If you need to build a local software repository, use the rich template

7.2 - rich

Feature-rich single-node configuration with local software repository, all extensions, Silo backup, and complete examples

The rich configuration template is an enhanced version of meta, designed for users who need to experience complete functionality.

If you want to build a local software repository, use Silo for backup storage, run Docker applications, or need preconfigured business databases, use this template.


Overview

  • Config Name: rich
  • Node Count: Single node
  • Description: Feature-rich single-node configuration, adding local software repository, Silo backup, complete extensions, Docker application examples on top of meta
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta, slim, fat

This template’s main enhancements over meta:

  • Builds local software repository (repo_enabled: true), downloads all PG extensions
  • Enables single-node Silo as PostgreSQL backup storage
  • Preinstalls TimescaleDB, pgvector, pg_wait_sampling and other extensions
  • Includes detailed user/database/service definition comment examples
  • Adds Redis primary-replica instance example
  • Preconfigures pg-test three-node HA cluster configuration stub

Usage:

./configure -c rich [-i <primary_ip>]

Content

Source: pigsty/conf/rich.yml

---
#==============================================================#
# File      :   rich.yml
# Desc      :   Pigsty feature-rich 1-node online install config
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf/rich
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the enhanced version of default meta.yml, which has:
# - almost all available postgres extensions
# - build local software repo for entire env
# - 1 node minio used as central backup repo
# - cluster stub for 3-node pg-test / redis
# - stub for nginx, certs, and website self-hosting config
# - detailed comments for database / user / service
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c rich
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql
    #----------------------------------------------#
    # this is an example single-node postgres cluster with pgvector installed, with one biz database & two biz users
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica } # <---- read only replica for read-only online traffic
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline } # <---- offline instance of ETL & interactive queries
      vars:
        pg_cluster: pg-meta

        # install, load, create pg extensions: https://pigsty.io/docs/pgsql/ext/
        pg_extensions: [ postgis, timescaledb, pgvector, pg_wait_sampling ]
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'

        # define business users/roles : https://pigsty.io/docs/pgsql/config/user
        pg_users:
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, the password. can be a scram-sha-256 hash string or plain text
            pgbouncer: true                 # optional, add this user to the pgbouncer user-list? false by default (production user should be true explicitly)
            comment: pigsty admin user      # optional, comment string for this user/role
            roles: [ dbrole_admin ]         # optional, belonged roles. default roles are: dbrole_{admin|readonly|readwrite|offline}
            #state: create                  # optional, create|absent, 'create' by default, use 'absent' to drop user
            #login: true                    # optional, can log in, true by default (new biz ROLE should be false)
            #superuser: false               # optional, is superuser? false by default
            #createdb: false                # optional, can create databases? false by default
            #createrole: false              # optional, can create role? false by default
            #inherit: true                  # optional, can this role use inherited privileges? true by default
            #replication: false             # optional, can this role do replication? false by default
            #bypassrls: false               # optional, can this role bypass row level security? false by default
            #connlimit: -1                  # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'        # optional, YYYY-MM-DD 'timestamp' when this role is expired (OVERWRITTEN by expire_in)
            #parameters: {}                 # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction         # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1             # optional, max database connections at user level, default -1 disable limit
            # Enhanced roles syntax (PG16+): roles can be string or object with options:
            #   - dbrole_readwrite                       # simple string: GRANT role
            #   - { name: role, admin: true }            # GRANT WITH ADMIN OPTION
            #   - { name: role, set: false }             # PG16: REVOKE SET OPTION
            #   - { name: role, inherit: false }         # PG16: REVOKE INHERIT OPTION
            #   - { name: role, state: absent }          # REVOKE membership
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user for bytebase database   }
          #- {name: dbuser_remove ,state: absent }       # use state: absent to remove a user

        # define business databases : https://pigsty.io/docs/pgsql/config/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among the ansible search path, e.g.: files/)
            schemas: [ pigsty ]             # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - vector                      # install pgvector for vector similarity search
              - postgis                     # install postgis for geospatial type & index
              - timescaledb                 # install timescaledb for time-series data
              - { name: pg_wait_sampling, schema: monitor } # install pg_wait_sampling on monitor schema
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to the pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_reserve: 32               # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_connlimit: 100            # optional, max database connections at database level, default 100
          #- {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }

        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # define (OPTIONAL) L2 VIP that bind to primary
        #pg_vip_enabled: true
        #pg_vip_address: 10.10.10.2/24

    #----------------------------------------------#
    # PGSQL HA Cluster Example: 3-node pg-test
    #----------------------------------------------#
    #pg-test:
    #  hosts:
    #    10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
    #    10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
    #    10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
    #  vars:
    #    pg_cluster: pg-test           # define pgsql cluster name
    #    pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
    #    pg_databases: [{ name: test }]
    #    # define business service here: https://pigsty.io/docs/pgsql/service
    #    pg_services:                        # extra services in addition to pg_default_services, array of service definition
    #      # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
    #      - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
    #        port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
    #        ip: "*"                         # optional, service bind ip address, `*` for all ip by default
    #        selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
    #        dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
    #        check: /sync                    # optional, health check url path, / by default
    #        backup: "[? pg_role == `primary`]"  # backup server selector
    #        maxconn: 3000                   # optional, max allowed front-end connection
    #        balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
    #        options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'
    #    pg_vip_enabled: true
    #    pg_vip_address: 10.10.10.3/24
    #    pg_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
    #      - '00 01 * * 1 /pg/bin/pg-backup full'
    #      - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'

    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: true    # build local repo, and install everything from it:  https://pigsty.io/docs/infra/admin/repo
        # and download all extensions into local repo
        repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # ETCD : https://pigsty.io/docs/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false             # prevent purging running etcd instance?

    #----------------------------------------------#
    # MINIO : https://pigsty.io/docs/minio
    #----------------------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://pigsty.io/docs/docker
    # APP    : https://pigsty.io/docs/app
    #----------------------------------------------#
    # OPTIONAL, launch example pgadmin app with: ./app.yml & ./app.yml -e app=bytebase
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true                # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin                        # specify the default app name to be installed (in the apps)
        apps:                               # define all applications, appname: definition

          # Admin GUI for PostgreSQL, launch with: ./app.yml
          pgadmin:                          # pgadmin app definition (app/pgadmin -> /opt/pgadmin)
            conf:                           # override /opt/pgadmin/.env
              PGADMIN_DEFAULT_EMAIL: [email protected]   # default user name
              PGADMIN_DEFAULT_PASSWORD: pigsty         # default password

          # Schema Migration GUI for PostgreSQL, launch with: ./app.yml -e app=bytebase
          bytebase:
            conf:
              BB_DOMAIN: http://ddl.pigsty  # replace it with your public domain name and postgres database url
              BB_PGURL: "postgresql://dbuser_bytebase:[email protected]:5432/bytebase?sslmode=prefer"

    #----------------------------------------------#
    # REDIS : https://pigsty.io/docs/redis
    #----------------------------------------------#
    # OPTIONAL, launch redis clusters with: ./redis.yml
    redis-ms:
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }



  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    certbot_sign: false               # enable certbot to sign https certificate for infra portal
    certbot_email: [email protected]     # replace your email address to receive expiration notice
    infra_portal:                     # infra services exposed via portal
      home      : { domain: i.pigsty }     # default domain name
      pgadmin   : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      bytebase  : { domain: ddl.pigsty ,endpoint: "${admin_ip}:8887" }
      minio     : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      #website:   # static local website example stub
      #  domain: repo.pigsty              # external domain name for static site
      #  certbot: repo.pigsty             # use certbot to sign https certificate for this static site
      #  path: /www/pigsty                # path to the static site directory

      #supabase:  # dynamic upstream service example stub
      #  domain: supa.pigsty          # external domain name for upstream service
      #  certbot: supa.pigsty         # use certbot to sign https certificate for this upstream server
      #  endpoint: "10.10.10.10:8000" # path to the static site directory
      #  websocket: true              # add websocket support
      #  certbot: supa.pigsty         # certbot cert name, apply with `make cert`

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts:                       # add static domains to all nodes /etc/hosts
      - '${admin_ip} i.pigsty sss.pigsty'
      - '${admin_ip} adm.pigsty ddl.pigsty repo.pigsty supa.pigsty'
    node_repo_modules: local              # use pre-made local repo rather than install from upstream
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with latest version
    #node_timezone: Asia/Hong_Kong        # overwrite node timezone

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_packages: [ pgsql-main, pgsql-common ]                 # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # BACKUP : https://pigsty.io/docs/pgsql/backup
    #----------------------------------------------#
    # if you want to use minio as backup repo instead of 'local' fs, uncomment this, and configure `pgbackrest_repo`
    # you can also use external object storage as backup repo
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days
      s3:                             # you can use cloud object storage as backup repo
        type: s3                      # Add your object storage credentials here!
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: <your_bucket_name>
        s3_key: <your_access_key>
        s3_key_secret: <your_secret_key>
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days
...

Explanation

The rich template is Pigsty’s complete functionality showcase configuration, suitable for users who want to deeply experience all features.

Use Cases:

  • Offline environments requiring local software repository
  • Environments needing Silo as PostgreSQL backup storage
  • Pre-planning multiple business databases and users
  • Running Docker applications (pgAdmin, Bytebase, etc.)
  • Learners wanting to understand complete configuration parameter usage

Main Differences from meta:

  • Enables local software repository building (repo_enabled: true)
  • Enables Silo backup storage (compatibility preset pgbackrest_method: minio)
  • Preinstalls TimescaleDB, pg_wait_sampling and other additional extensions
  • Includes detailed parameter comments for understanding configuration meanings
  • Preconfigures HA cluster stub configuration (pg-test)

Notes:

  • Some extensions unavailable on ARM64 architecture, adjust as needed
  • Building local software repository requires longer time and larger disk space
  • Default passwords are sample passwords, must be changed for production

7.3 - slim

Minimal installation template without monitoring infrastructure, installs PostgreSQL directly from internet

The slim configuration template provides minimal installation capability, installing a PostgreSQL high-availability cluster directly from the internet without deploying Infra monitoring infrastructure.

When you only need an available database instance without the monitoring system, consider using the Slim Installation mode.


Overview

  • Config Name: slim
  • Node Count: Single node
  • Description: Minimal installation template without monitoring infrastructure, installs PostgreSQL directly
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c slim [-i <primary_ip>]
./slim.yml   # Execute slim installation

Content

Source: pigsty/conf/slim.yml

---
#==============================================================#
# File      :   slim.yml
# Desc      :   Pigsty slim installation config template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://pigsty.io/docs/conf/slim
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for slim / minimal installation
# No monitoring & infra will be installed, just raw postgresql
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c slim
#   ./slim.yml

all:
  children:

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        #10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        #10.10.10.12: { etcd_seq: 3 }  # three-member cluster keeps an odd voter count
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd

    #----------------------------------------------#
    # PostgreSQL Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        #10.10.10.11: { pg_seq: 2, pg_role: replica } # you can add more!
        #10.10.10.12: { pg_seq: 3, pg_role: replica, pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ vector ]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The slim template is Pigsty’s minimal installation configuration, designed for quick deployment of bare PostgreSQL clusters.

Use Cases:

  • Only need PostgreSQL database, no monitoring system required
  • Resource-limited small servers or edge devices
  • Quick deployment of temporary test databases
  • Already have monitoring system, only need PostgreSQL HA cluster

Key Features:

  • Uses slim.yml playbook instead of deploy.yml for installation
  • Installs software directly from internet, no local software repository
  • Retains core PostgreSQL HA capability (Patroni + etcd + HAProxy)
  • Minimized package downloads, faster installation
  • Default uses PostgreSQL 18

Differences from meta:

  • slim uses dedicated slim.yml playbook, skips Infra module installation
  • Faster installation, less resource usage
  • Suitable for “just need a database” scenarios

Notes:

  • After slim installation, cannot view database status through Grafana
  • If monitoring is needed, use meta or rich template
  • Can add replicas as needed for high availability

7.4 - fat

Feature-All-Test template, single-node installation of all extensions, builds local repo with PG 14-18 all versions

The fat configuration template is Pigsty’s Feature-All-Test template, installing all extension plugins on a single node and building a local software repository containing all extensions for PostgreSQL 14-18 (five major versions).

This is a full-featured configuration for testing and development, suitable for scenarios requiring complete software package cache or testing all extensions.


Overview

  • Config Name: fat
  • Node Count: Single node
  • Description: Feature-All-Test template, installs all extensions, builds local repo with PG 14-18 all versions
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta, slim, fat

Usage:

./configure -c fat [-i <primary_ip>]

To specify a particular PostgreSQL version:

./configure -c fat -v 16   # Use PostgreSQL 16

Content

Source: pigsty/conf/fat.yml

---
#==============================================================#
# File      :   fat.yml
# Desc      :   Pigsty Feature-All-Test config template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-28
# Docs      :   https://pigsty.io/docs/conf/fat
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the 4-node sandbox for pigsty
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c fat [-v 18|17|16|15]
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql
    #----------------------------------------------#
    # this is an example single-node postgres cluster with pgvector installed, with one biz database & two biz users
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- primary instance with read-write capability
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica } # <---- read only replica for read-only online traffic
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline } # <---- offline instance of ETL & interactive queries
      vars:
        pg_cluster: pg-meta

        # install, load, create pg extensions: https://pigsty.io/docs/pgsql/ext/
        pg_extensions: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'

        # define business users/roles : https://pigsty.io/docs/pgsql/config/user
        pg_users:
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, the password. can be a scram-sha-256 hash string or plain text
            pgbouncer: true                 # optional, add this user to the pgbouncer user-list? false by default (production user should be true explicitly)
            comment: pigsty admin user      # optional, comment string for this user/role
            roles: [ dbrole_admin ]         # optional, belonged roles. default roles are: dbrole_{admin|readonly|readwrite|offline}
            #state: create                   # optional, create|absent, 'create' by default, use 'absent' to drop user
            #login: true                     # optional, can log in, true by default (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create databases? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired (OVERWRITTEN by expire_in)
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
            # Enhanced roles syntax (PG16+): roles can be string or object with options:
            #   - dbrole_readwrite                       # simple string: GRANT role
            #   - { name: role, admin: true }            # GRANT WITH ADMIN OPTION
            #   - { name: role, set: false }             # PG16: REVOKE SET OPTION
            #   - { name: role, inherit: false }         # PG16: REVOKE INHERIT OPTION
            #   - { name: role, state: absent }          # REVOKE membership
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin] ,comment: admin user for bytebase database   }
          #- {name: dbuser_remove ,state: absent }       # use state: absent to remove a user

        # define business databases : https://pigsty.io/docs/pgsql/config/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among the ansible search path, e.g.: files/)
            schemas: [ pigsty ]             # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - vector                      # install pgvector for vector similarity search
              - postgis                     # install postgis for geospatial type & index
              - timescaledb                 # install timescaledb for time-series data
              - { name: pg_wait_sampling, schema: monitor } # install pg_wait_sampling on monitor schema
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to the pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_reserve: 32               # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_connlimit: 100            # optional, max database connections at database level, default 100
          #- {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }

        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # define (OPTIONAL) L2 VIP that bind to primary
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24


    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: true # build local repo:  https://pigsty.io/docs/infra/admin/repo
        #repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
        repo_packages: [
          node-bootstrap, infra-package, infra-addons, node-package1, node-package2, node-package3, pgsql-utility, extra-modules,
          pg18-full,pg18-time,pg18-gis,pg18-rag,pg18-fts,pg18-olap,pg18-feat,pg18-lang,pg18-type,pg18-util,pg18-func,pg18-admin,pg18-stat,pg18-sec,pg18-fdw,pg18-sim,pg18-etl,
          pg17-full,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-util,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
          pg16-full,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-util,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
          pg15-full,pg15-time,pg15-gis,pg15-rag,pg15-fts,pg15-olap,pg15-feat,pg15-lang,pg15-type,pg15-util,pg15-func,pg15-admin,pg15-stat,pg15-sec,pg15-fdw,pg15-sim,pg15-etl,
          pg14-full,pg14-time,pg14-gis,pg14-rag,pg14-fts,pg14-olap,pg14-feat,pg14-lang,pg14-type,pg14-util,pg14-func,pg14-admin,pg14-stat,pg14-sec,pg14-fdw,pg14-sim,pg14-etl,
          infra-extra, kafka-stack, java-runtime, sealos, tigerbeetle, polardb, ivorysql
        ]

    #----------------------------------------------#
    # ETCD : https://pigsty.io/docs/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false             # prevent purging running etcd instance?

    #----------------------------------------------#
    # MINIO : https://pigsty.io/docs/minio
    #----------------------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://pigsty.io/docs/docker
    # APP    : https://pigsty.io/docs/app
    #----------------------------------------------#
    # OPTIONAL, launch example pgadmin app with: ./app.yml & ./app.yml -e app=bytebase
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true                # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin                        # specify the default app name to be installed (in the apps)
        apps:                               # define all applications, appname: definition

          # Admin GUI for PostgreSQL, launch with: ./app.yml
          pgadmin:                          # pgadmin app definition (app/pgadmin -> /opt/pgadmin)
            conf:                           # override /opt/pgadmin/.env
              PGADMIN_DEFAULT_EMAIL: [email protected]   # default user name
              PGADMIN_DEFAULT_PASSWORD: pigsty         # default password

          # Schema Migration GUI for PostgreSQL, launch with: ./app.yml -e app=bytebase
          bytebase:
            conf:
              BB_DOMAIN: http://ddl.pigsty  # replace it with your public domain name and postgres database url
              BB_PGURL: "postgresql://dbuser_bytebase:[email protected]:5432/bytebase?sslmode=prefer"


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    certbot_sign: false               # enable certbot to sign https certificate for infra portal
    certbot_email: [email protected]     # replace your email address to receive expiration notice
    infra_portal:                     # domain names and upstream servers
      home         : { domain: i.pigsty }
      pgadmin      : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      bytebase     : { domain: ddl.pigsty ,endpoint: "${admin_ip}:8887" ,websocket: true}
      minio        : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      #website:   # static local website example stub
      #  domain: repo.pigsty              # external domain name for static site
      #  certbot: repo.pigsty             # use certbot to sign https certificate for this static site
      #  path: /www/pigsty                # path to the static site directory

      #supabase:  # dynamic upstream service example stub
      #  domain: supa.pigsty          # external domain name for upstream service
      #  certbot: supa.pigsty         # use certbot to sign https certificate for this upstream server
      #  endpoint: "10.10.10.10:8000" # path to the static site directory
      #  websocket: true              # add websocket support
      #  certbot: supa.pigsty         # certbot cert name, apply with `make cert`

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: true              # overwrite node hostname on multi-node template
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts:                       # add static domains to all nodes /etc/hosts
      - 10.10.10.10 i.pigsty sss.pigsty
      - 10.10.10.10 adm.pigsty ddl.pigsty repo.pigsty supa.pigsty
    node_repo_modules: local,node,infra,pgsql # use pre-made local repo rather than install from upstream
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with latest version
    #node_timezone: Asia/Hong_Kong        # overwrite node timezone

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_packages: [ pgsql-main, pgsql-common ] # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # BACKUP : https://pigsty.io/docs/pgsql/backup
    #----------------------------------------------#
    # if you want to use minio as backup repo instead of 'local' fs, uncomment this, and configure `pgbackrest_repo`
    # you can also use external object storage as backup repo
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest [CHANGE ACCORDING to minio_users.pgbackrest]
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days
      s3:                             # you can use cloud object storage as backup repo
        type: s3                      # Add your object storage credentials here!
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: <your_bucket_name>
        s3_key: <your_access_key>
        s3_key_secret: <your_secret_key>
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the last 14 days

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The fat template is Pigsty’s full-featured test configuration, designed for completeness testing and offline package building.

Key Features:

  • All Extensions: Installs all categorized extension packages for PostgreSQL 18
  • Multi-version Repository: Local repo contains all five major versions of PostgreSQL 14-18
  • Complete Component Stack: Includes Silo backup, Docker applications, VIP, etc.
  • Enterprise Components: Includes Kafka, PolarDB, IvorySQL, TigerBeetle, etc.

Repository Contents:

CategoryDescription
PostgreSQL 14-18Five major versions’ kernels and all extensions
Extension Categoriestime, gis, rag, fts, olap, feat, lang, type, util, func, admin, stat, sec, fdw, sim, etl
Enterprise Componentskafka-stack, Java Runtime, Sealos, TigerBeetle
Database KernelsPolarDB, IvorySQL

Differences from rich:

  • fat contains all five versions of PostgreSQL 14-18, rich only contains current default version
  • fat contains additional enterprise components (Kafka, PolarDB, IvorySQL, etc.)
  • fat requires larger disk space and longer build time

Use Cases:

  • Pigsty development testing and feature validation
  • Building complete multi-version offline software packages
  • Testing all extension compatibility scenarios
  • Enterprise environments pre-caching all software packages

Notes:

  • Requires large disk space (100GB+ recommended) for storing all packages
  • Building local software repository requires longer time
  • Some extensions unavailable on ARM64 architecture
  • Default passwords are sample passwords, must be changed for production

7.5 - infra

Only installs observability infrastructure, dedicated template without PostgreSQL and etcd

The infra configuration template only deploys Pigsty’s observability infrastructure components (VictoriaMetrics/Grafana/VictoriaLogs/Nginx, etc.), without PostgreSQL and etcd.

Suitable for scenarios requiring a standalone monitoring stack, such as monitoring external PostgreSQL/RDS instances or other data sources.


Overview

  • Config Name: infra
  • Node Count: Single or multiple nodes
  • Description: Only installs observability infrastructure, without PostgreSQL and etcd
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c infra [-i <primary_ip>]
./infra.yml    # Only execute infra playbook

Content

Source: pigsty/conf/infra.yml

---
#==============================================================#
# File      :   infra.yml
# Desc      :   Infra Only Config
# Ctime     :   2025-12-16
# Mtime     :   2025-12-30
# Docs      :   https://pigsty.io/docs/conf/infra
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for deploy victoria stack alone
# tutorial: https://pigsty.io/docs/infra
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c infra
#   ./infra.yml

all:
  children:
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
        #10.10.10.11: { infra_seq: 2 } # you can add more nodes if you want
        #10.10.10.12: { infra_seq: 3 } # don't forget to assign unique infra_seq for each node
      vars:
        docker_enabled: true            # enabled docker with ./docker.yml
        docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        pg_exporters:     # bin/pgmon-add pg-rds
          20001: { pg_cluster: pg-rds ,pg_seq: 1 ,pg_host: 10.10.10.10 ,pg_exporter_url: 'postgres://postgres:[email protected]:5432/postgres' }

  vars:                                 # global variables
    version: v4.5.0                     # pigsty version string
    admin_ip: 10.10.10.10               # admin node ip address
    region: default                     # upstream mirror region: default,china,europe
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    infra_portal:                       # infra services exposed via portal
      home : { domain: i.pigsty }       # default domain name
    repo_enabled: false                 # online installation without repo
    node_repo_modules: node,infra,pgsql # add these repos directly
    #haproxy_enabled: false              # enable haproxy on infra node?
    #vector_enabled: false               # enable vector on infra node?

    # DON't FORGET TO CHANGE DEFAULT PASSWORDS!
    grafana_admin_password: pigsty
    haproxy_admin_password: pigsty
...

Explanation

The infra template is Pigsty’s pure monitoring stack configuration, designed for standalone deployment of observability infrastructure.

Use Cases:

  • Monitoring external PostgreSQL instances (RDS, self-hosted, etc.)
  • Need standalone monitoring/alerting platform
  • Already have PostgreSQL clusters, only need to add monitoring
  • As a central console for multi-cluster monitoring

Included Components:

  • VictoriaMetrics: Time series database for storing metrics
  • VictoriaLogs: Log aggregation system
  • VictoriaTraces: Distributed tracing system
  • Grafana: Visualization dashboards
  • Alertmanager: Alert management
  • Nginx: Reverse proxy and web entry

Not Included:

  • PostgreSQL database cluster
  • etcd distributed coordination service
  • Silo object storage

Monitoring External Instances: After configuration, add monitoring for external PostgreSQL instances via the pgsql-monitor.yml playbook:

pg_exporters:
  20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.100 }
  20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.101 }

Notes:

  • This template will not install any databases
  • For full functionality, use meta or rich template
  • Can add multiple infra nodes for high availability as needed

7.6 - vibe

VIBE AI coding sandbox config template, integrating Code-Server, JupyterLab, Claude Code, Codex CLI, and JuiceFS

The vibe config template provides a ready-to-use AI coding sandbox, integrating Code-Server (Web VS Code), JupyterLab, Claude Code observability, Codex CLI, JuiceFS distributed filesystem, and a feature-rich PostgreSQL database.


Overview

  • Config Name: vibe
  • Node Count: Single node
  • Description: VIBE AI coding sandbox with Code-Server + JupyterLab + Claude Code + Codex CLI + JuiceFS + PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c vibe [-i <primary_ip>]

Content

Source: pigsty/conf/vibe.yml

---
#==============================================================#
# File      :   vibe.yml
# Desc      :   Pigsty ai vibe coding sandbox
# Ctime     :   2026-01-19
# Mtime     :   2026-06-28
# Docs      :   https://pigsty.io/docs/conf/vibe
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# VIBE CODING SANDBOX
# PostgreSQL with related extensions
# Code-Server, Jupyter, Claude Code, optional Codex CLI
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c vibe
#   ./deploy.yml
#   ./juice.yml     # pgfs: juicefs on pgsql, mount on /fs
#   ./vibe.yml      # code-server, jupyter, claude-code, and codex cli

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    pgsql: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } } ,vars: { pg_cluster: pgsql }}

    # optional modules
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}
    #redis-ms:
    #  hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
    #  vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

  vars:
    #----------------------------------------------#
    # INFRA: https://pigsty.io/docs/infra
    #----------------------------------------------#
    version: v4.5.0                     # pigsty version string
    admin_ip: 10.10.10.10               # admin node ip address
    region: default                     # upstream mirror region: default,china,europe
    infra_portal:                       # infra services exposed via portal
      home : { domain: i.pigsty }       # default domain name
    dns_enabled: false                  # disable dns service
    #blackbox_enabled: false            # disable blackbox exporter
    #alertmanager_enabled: false        # disable alertmanager
    infra_extra_services:               # home page navigation entries
      - { name: Code Server  ,url: '/code'             ,desc: 'VS Code Server'       ,icon: 'code'     }
      - { name: Jupyter      ,url: '/jupyter'          ,desc: 'Jupyter Notebook'     ,icon: 'jupyter'  }
      - { name: Claude Code  ,url: '/ui/d/claude-code' ,desc: 'Claude Observability' ,icon: 'claude'   }

    #----------------------------------------------#
    # NODE: https://pigsty.io/docs/node
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit
    node_dns_method: none               # do not setup dns
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_packages: [ openssh-server, juicefs, restic, rclone, uv, opencode, golang, asciinema, tmux ]
    docker_enabled: true                # enable docker service
    node_firewall_mode: zone            # default: trust intranet, expose selected public ports
    node_firewall_public_port: [22, 80, 443, 5432]    # expose 5432 for remote access, remove in production!
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    #----------------------------------------------#
    # PGSQL: https://pigsty.io/docs/pgsql
    #----------------------------------------------#
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_packages: [ pgsql-main, patroni, pgbackrest, pg-exporter, pgbackrest-exporter ]
    pg_extensions: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_users:
      - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ postgis, timescaledb, vector, age ]}
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'
    pg_hba_rules:
      - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
      # WARNING: devbox only. Remove world access in production.
      - { user: all ,db: all ,addr: world ,auth: pwd ,title: 'everyone world access with password'    ,order: 900 }
    pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am
    patroni_mode: remove                # remove patroni after deployment
    pgbouncer_enabled: false            # disable pgbouncer pool
    pgbouncer_exporter_enabled: false   # disable pgbouncer_exporter on pgsql hosts?
    pgbackrest_exporter_enabled: false  # disable pgbackrest_exporter
    pg_default_services: []             # do not provision pg services
    #pg_reload: false                   # do not reload patroni/service

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty

    #----------------------------------------------#
    # OPTIONAL VIBE COMPONENTS
    #----------------------------------------------#
    code_enabled: true                # install & enable code-server via vibe role
    code_password: DBUser.Meta
    jupyter_enabled: true             # enable jupyter (disabled by default, enable for vibe sandbox)
    jupyter_password: DBUser.Meta
    juice_instances:
      jfs:
        path  : /fs
        meta  : postgres://dbuser_meta:[email protected]:5432/meta
        data  : --storage postgres --bucket 10.10.10.10:5432/meta --access-key dbuser_meta --secret-key DBUser.Meta
        port  : 9567

    # Claude Code is the default coding agent. Node.js is installed on demand when agents are enabled.
    nodejs_enabled: true              # standalone nodejs runtime
    npm_packages: []                  # extra global npm packages
    codex_enabled: true
    claude_enabled: true
    #claude_env:                      # use 3rd party Anthropic-compatible API service
    #  ANTHROPIC_BASE_URL: https://open.bigmodel.cn/api/anthropic
    #  ANTHROPIC_API_URL: https://open.bigmodel.cn/api/anthropic
    #  ANTHROPIC_AUTH_TOKEN: your_api_service_token
    #  ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-5.2[1m]"
    #  ANTHROPIC_DEFAULT_SONNET_MODEL: "glm-5.2[1m]"
    #  ANTHROPIC_DEFAULT_HAIKU_MODEL: "glm-4.7"
    #  CLAUDE_CODE_AUTO_COMPACT_WINDOW: "1000000"

...

Explanation

The vibe template is an AI-era Web coding sandbox, enabling development, data analysis, AI app building all in browser.

Core Components:

ComponentDescriptionAccess Method
Code-ServerWeb version of VS Code, full-featured code editorhttp://<ip>/code
JupyterLabInteractive data science notebook, Python/SQLhttp://<ip>/jupyter
Claude CodeAI coding runtime and observability entrypoint (claude_env customizable)Terminal / Dashboard
Codex CLIOpenAI agentic coding CLI; VIBE installs it but does not manage its configurationTerminal
JuiceFSPostgreSQL-based distributed filesystemMount point /fs
PostgreSQL 18Feature-rich database with pg18-main + categorized extension package groupsPort 5432

Node tools explicitly installed by this template (node_packages):

  • openssh-server, juicefs, restic, rclone
  • uv, opencode, golang
  • asciinema, tmux

PostgreSQL Extensions:

This template installs PostgreSQL 18 extension groups by category:

pg18-main, pg18-time, pg18-gis, pg18-rag, pg18-fts, pg18-olap,
pg18-feat, pg18-lang, pg18-type, pg18-util, pg18-func, pg18-admin,
pg18-stat, pg18-sec, pg18-fdw, pg18-sim, pg18-etl

By default, the meta database enables postgis, timescaledb, and vector; other extensions can be enabled as needed.


VIBE Module Components

The VIBE module provides AI coding sandbox capability; vibe.yml explicitly enables Code-Server and Jupyter and installs Claude Code and Codex CLI by default.

Code-Server: VS Code in browser

  • Full VS Code functionality, extension support
  • HTTPS access via Nginx reverse proxy
  • Supports Open VSX and Microsoft extension marketplaces
  • Explicit template params: code_enabled, code_password
  • Optional params: code_port, code_data, code_gallery

JupyterLab: Interactive computing environment

  • Python/SQL/Markdown notebook support
  • Pre-configured Python venv with data science libraries
  • HTTPS access via Nginx reverse proxy
  • Explicit template params: jupyter_enabled, jupyter_password
  • Optional params: jupyter_port, jupyter_data, jupyter_venv

Claude Code: AI coding assistant runtime

  • Uses module default behavior to bootstrap Claude runtime
  • Supports endpoint/API key overrides through claude_env
  • Provides claude-code dashboard for usage monitoring

Codex CLI: AI coding assistant

  • Controlled by codex_enabled, which defaults to true
  • VIBE installs @openai/codex only; it does not write Codex configuration or connect Codex to the Claude Code dashboard

JuiceFS Filesystem

This template uses JuiceFS for distributed filesystem capability, with a special feature: both metadata and data stored in PostgreSQL.

Architecture Features:

  • Metadata Engine: Uses PostgreSQL for filesystem metadata storage
  • Data Storage: Uses PostgreSQL Large Object for file data storage
  • Mount Point: Default mount at /fs (controlled by juice_instances.jfs.path)
  • Monitoring Port: 9567 provides Prometheus metrics

Use Cases:

  • Persistent storage for code projects
  • Working directory for Jupyter Notebooks
  • Storage for AI models and datasets
  • File sharing across instances (when scaled to multiple nodes)

Config Example:

juice_instances:
  jfs:
    path  : /fs
    meta  : postgres://dbuser_meta:[email protected]:5432/meta
    data  : --storage postgres --bucket 10.10.10.10:5432/meta --access-key dbuser_meta --secret-key DBUser.Meta
    port  : 9567

Deployment Steps

# 1. Download Pigsty
curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty

# 2. Use vibe config template
./configure -c vibe

# 3. Modify passwords (important!)
vi pigsty.yml
# Change code_password, jupyter_password, database, and infrastructure defaults

# 4. Deploy infrastructure and PostgreSQL
./deploy.yml

# 5. Optional: deploy the JuiceFS filesystem
./juice.yml -l 10.10.10.10

# 6. Deploy VIBE (Code-Server, JupyterLab, Claude Code, Codex CLI)
./vibe.yml -l 10.10.10.10

Access Methods

After deployment, access via browser:

# Code-Server (VS Code Web)
https://<domain>/code/
# Use the rotated code_password

# JupyterLab
https://<domain>/jupyter/
# Use the rotated jupyter_password token

# Claude Code Dashboard
https://<domain>/ui/d/claude-code
# Use the rotated Grafana administrator credentials

# PostgreSQL
psql 'host=<ip> port=5432 dbname=meta user=dbuser_meta sslmode=require'

Use Cases

  • AI App Development: Build RAG, Agent, LLM applications
  • Data Science: Use JupyterLab for data analysis and visualization
  • Remote Development: Setup Web IDE environment on cloud servers
  • Teaching Demos: Provide consistent dev environment for students
  • Rapid Prototyping: Quickly validate ideas without local env setup
  • Claude Code Observability: Monitor AI coding assistant usage

Notes

  • Must change passwords: code_password and jupyter_password defaults are for testing only
  • Jupyter boundary: The template listens on 0.0.0.0:8888, allows any Origin, disables XSRF checks, and relies on the token by default; restrict the port and portal sources and never expose it directly to the Internet
  • Network security: This template exposes 5432 (node_firewall_public_port) and includes addr: world HBA by default; remove those public paths for production and add portal Basic Auth when appropriate
  • Resource requirements: Recommend at least 2 cores 4GB memory, SSD disk
  • Simplified architecture: This template disables Patroni, PgBouncer etc HA components, suitable for single-node dev env
  • Claude API: Using Claude Code requires configuring API key in claude_env

7.7 - docker

Pigsty Docker single-node template for quickly bootstrapping Pigsty in containers.

The docker configuration template runs Pigsty inside a Docker container and provides a minimal single-node stack for infrastructure and PostgreSQL.

For full workflow details, see Docker Deployment.


Overview

  • Config Name: docker
  • Node Count: Single node (container runtime)
  • Description: Quick-start container template using 127.0.0.1 and trimmed system capabilities for Docker scenarios
  • OS Distro: Container image runtime (official Pigsty Docker image recommended)
  • OS Arch: x86_64, aarch64
  • Related: meta, vibe

Usage:

./configure -c docker -i 127.0.0.1 -g

Content

Source: pigsty/conf/docker.yml

---
#==============================================================#
# File      :   docker.yml
# Desc      :   Pigsty docker coding environment
# Ctime     :   2026-01-19
# Mtime     :   2026-01-27
# Docs      :   https://pigsty.io/docs/conf/docker
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# DOCKER CONFIG, use 127.0.0.1 inside docker
# mount the /data volume when running docker container
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c docker -i 127.0.0.1 -g
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    pgsql: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary  }} ,vars: { pg_cluster: pgsql }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

  vars:

    #----------------------------------------------#
    # Infra
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10               # admin node ip address
    region: china                     # upstream mirror region: default|china|europe
    dns_enabled: false                # disable dnsmasq service on single node
    infra_portal:
      home : { domain: i.pigsty }
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,10.10.10.10,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    #----------------------------------------------#
    # Node
    #----------------------------------------------#
    nodename: pigsty
    node_id_from_pg: false
    node_tune: oltp
    node_write_etc_hosts: false
    node_dns_method: none
    node_ntp_enabled: false
    node_kernel_modules: []
    node_repo_remove: true
    node_repo_modules: 'node,infra,pgsql'


    #----------------------------------------------#
    # PGSQL: https://pigsty.io/docs/pgsql
    #----------------------------------------------#
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_extensions: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_users:
      - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ postgis, timescaledb, vector ]}
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'
    pg_hba_rules:
      - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
      - { user: all ,db: all ,addr: world ,auth: pwd ,title: 'everyone world access with password'    ,order: 900 }
    pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am
    #pg_reload: false                   # do not reload patroni/service

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

    #----------------------------------------------#
    # OPTIONAL
    #----------------------------------------------#
    #code_password: DBUser.Meta
    #jupyter_password: DBUser.Meta
    #juice_instances:  # dict of juicefs filesystems to deploy
    #  jfs:
    #    path  : /fs
    #    meta  : postgres://dbuser_meta:[email protected]:5432/meta
    #    data  : --storage postgres --bucket 10.10.10.10:5432/meta --access-key dbuser_meta --secret-key DBUser.Meta
    #    port  : 9567
    #node_packages: [ openssh-server, tmux, juicefs, restic, rclone, uv, code-server ]
    #npm_packages: [ '@anthropic-ai/claude-code' , 'happy-coder' ]
    #claude_env:
    #  ANTHROPIC_BASE_URL: https://open.bigmodel.cn/api/anthropic
    #  ANTHROPIC_API_URL: https://open.bigmodel.cn/api/anthropic
    #  ANTHROPIC_AUTH_TOKEN: your_api_service_token
    #  ANTHROPIC_MODEL: glm-4.7
    #  ANTHROPIC_SMALL_FAST_MODEL: glm-4.5-air
...

Explanation

The docker template is optimized for development and validation inside containers.

Key Features:

  • Disables local repo build (repo_enabled: false) to avoid extra build overhead in containers
  • Simplifies node behavior by disabling NTP, kernel module loading, and /etc/hosts rewrite
  • Uses PostgreSQL 18 by default with a broad preset extension package bundle (pg18-*)
  • Allows password access from both intra and world ranges in pg_hba_rules for fast testing
  • Keeps optional capabilities (Code-Server, Jupyter, JuiceFS, Claude CLI) as commented settings

Notes:

  • This template is designed for development and demos; tighten pg_hba_rules and password policy for production
  • Mount /data in the container runtime to persist PostgreSQL and component data

7.8 - pgsql

Native PostgreSQL kernel with stable support for PostgreSQL 14 to 18 and a PG19 Beta evaluation option

The pgsql configuration template uses the native PostgreSQL kernel, Pigsty’s default database kernel, with stable support for PostgreSQL 14 to 18. The current configure also accepts version 19, but PG19 remains Beta; use the dedicated pg19 template for evaluation.


Overview

  • Config Name: pgsql
  • Node Count: Single node
  • Description: Native PostgreSQL kernel configuration template
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c pgsql [-i <primary_ip>]

To specify a non-default PostgreSQL version (e.g., 16):

./configure -c pgsql -v 16

Content

Source: pigsty/conf/pgsql.yml

---
#==============================================================#
# File      :   pgsql.yml
# Desc      :   1-node PostgreSQL Config template
# Ctime     :   2025-02-23
# Mtime     :   2025-12-28
# Docs      :   https://pigsty.io/docs/conf/pgsql
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for basical PostgreSQL Kernel.
# Nothing special, just a basic setup with one node.
# tutorial: https://pigsty.io/docs/pgsql/kernel/postgres
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c pgsql
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # PostgreSQL Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ postgis, timescaledb, vector ]}
        pg_extensions: [ postgis, timescaledb, pgvector, pg_wait_sampling ]
        pg_libs: 'timescaledb, pg_stat_statements, auto_explain, pg_wait_sampling'
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    #repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The pgsql template is Pigsty’s standard kernel configuration, using community-native PostgreSQL.

Version Support:

  • PostgreSQL 18 (default)
  • PostgreSQL 17, 16, 15, 14
  • PostgreSQL 19 Beta (evaluation; use ./configure -c pg19)

Use Cases:

  • Need to use the latest PostgreSQL features
  • Need the widest extension support
  • Standard production environment deployment
  • Same functionality as meta template, explicitly declaring native kernel usage

Differences from meta:

  • pgsql template explicitly declares using native PostgreSQL kernel
  • Suitable for scenarios needing clear distinction between different kernel types

7.9 - pg19

Single-node PostgreSQL 19 Beta evaluation template with the PGDG Beta repository and default backup capabilities

pg19 is the single-node PostgreSQL 19 Beta evaluation template. It follows the meta topology, enables the beta repository, and limits the local repository’s additional cache to core PGSQL packages without preinstalling extensions.


Overview

  • Config Name: pg19
  • Node Count: Single node
  • PostgreSQL Version: 19 Beta
  • Use Cases: New-version evaluation and compatibility testing
  • Related: meta, pgsql

Usage:

./configure -c pg19 [-i <primary_ip>]

Content

Source: pigsty/conf/pg19.yml

---
#==============================================================#
# File      :   pg19.yml
# Desc      :   Pigsty 1-node PostgreSQL 19 beta config
# Ctime     :   2026-06-11
# Mtime     :   2026-06-11
# Docs      :   https://pigsty.io/docs/conf/pg19
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the PostgreSQL 19 beta variant of meta.yml.
# It enables the PGDG beta repository and installs a minimal PG19 runtime.
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c pg19
#   ./deploy.yml

all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        #x.xx.xx.xx: { pg_seq: 2, pg_role: replica }
        #x.xx.xx.xy: { pg_seq: 3, pg_role: offline }
      vars:
        pg_cluster: pg-meta

        # PG19 is beta; extension packages are intentionally not installed here.
        pg_extensions: []

        # define business users/roles : https://pigsty.io/docs/pgsql/config/user
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }

        # define business databases : https://pigsty.io/docs/pgsql/config/db
        pg_databases:
          - { name: meta, baseline: cmdb.sql, comment: "pigsty meta database", schemas: [pigsty] }

        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }

        pg_crontab:     # make a full backup every day at 1am
          - '00 01 * * * /pg/bin/pg-backup full'

        # define (OPTIONAL) L2 VIP that bind to primary
        #pg_vip_enabled: true
        #pg_vip_address: 10.10.10.2/24


    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: false   # disable local repo in 1-node mode
        #repo_extra_packages: [ pgsql-core ]  # if local repo is enabled, mirror PG19 beta core packages

    #----------------------------------------------#
    # ETCD : https://pigsty.io/docs/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false

    #----------------------------------------------#
    # MINIO : https://pigsty.io/docs/minio
    #----------------------------------------------#
    #minio:
    #  hosts:
    #    10.10.10.10: { minio_seq: 1 }
    #  vars:
    #    minio_cluster: minio
    #    minio_users:
    #      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
    #      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
    #      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # DOCKER : https://pigsty.io/docs/docker
    # APP    : https://pigsty.io/docs/app
    #----------------------------------------------#
    app:
      hosts: { 10.10.10.10: {} }
      vars:
        docker_enabled: true
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: pgadmin
        apps:
          pgadmin:
            conf:
              PGADMIN_DEFAULT_EMAIL: [email protected]
              PGADMIN_DEFAULT_PASSWORD: pigsty


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:
      home : { domain: i.pigsty }
      pgadmin : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      #minio  : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts: [ '${admin_ip} i.pigsty sss.pigsty' ]
    node_repo_modules: 'node,infra,pgsql,beta' # PG19 beta packages come from PGDG testing repo
    #node_repo_modules: local             # use this if you want to build & use local repo
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    node_firewall_public_port: [22, 80, 443, 5432]

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 19                      # PostgreSQL 19 beta
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                 # prevent purging running postgres instance?
    pg_extensions: []                   # do not install extension packages during PG19 beta trial
    repo_modules: node,infra,pgsql,beta # add PGDG testing repo when building a local repo
    repo_extra_packages: [ pgsql-core ] # only mirror PG19 beta core packages

    #----------------------------------------------#
    # BACKUP : https://pigsty.io/docs/pgsql/backup
    #----------------------------------------------#
    pgbackrest_enabled: true            # pgBackRest 2.59 supports PostgreSQL 19 beta2
    pgbackrest_exporter_enabled: true   # expose pgBackRest metrics to the monitoring system
    #pgbackrest_method: minio
    #pgbackrest_repo:
    #  minio:
    #    type: s3
    #    s3_endpoint: sss.pigsty
    #    s3_region: us-east-1
    #    s3_bucket: pgsql
    #    s3_key: pgbackrest
    #    s3_key_secret: S3User.Backup
    #    s3_uri_style: path
    #    path: /pgbackrest
    #    storage_port: 9000
    #    storage_ca_file: /etc/pki/ca.crt
    #    bundle: y
    #    bundle_limit: 20MiB
    #    bundle_size: 128MiB
    #    cipher_type: aes-256-cbc
    #    cipher_pass: pgBackRest
    #    retention_full_type: time
    #    retention_full: 14

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

Important defaults and limitations:

  • node_repo_modules: node,infra,pgsql,beta obtains PG19 packages from the PGDG Beta repository
  • repo_extra_packages: [pgsql-core] limits the local repository’s additional cache to core PGSQL packages; instances still use the role’s default pgsql-main pgsql-common installation set
  • pg_extensions: [] installs no extension packages
  • pgbackrest_enabled: true and pgbackrest_exporter_enabled: true; pg-meta retains its daily 01:00 full-backup job
  • INFRA, ETCD, PGSQL, and optional pgAdmin remain available for a single-node evaluation

This is a Beta evaluation configuration, not a production template. Do not treat -v 19 on an ordinary template as a production-ready PG19 deployment; validate extension compatibility, backup and recovery, and upgrade procedures separately.

7.10 - mssql

Babelfish template pinned to a PostgreSQL 17-compatible kernel with SQL Server protocol and T-SQL support

The mssql configuration template uses a PostgreSQL 17-compatible Babelfish kernel instead of native PostgreSQL, providing Microsoft SQL Server wire protocol (TDS) and T-SQL syntax compatibility. The current template is pinned to pg_version: 17; configure does not apply -v overrides to this fixed-kernel template.

Since Pigsty v4.2, Babelfish is built directly by Pigsty, no longer using the WiltonDB repository, and is available on all supported Linux platforms.

For the complete tutorial, see: Babelfish (MSSQL) Kernel Guide


Overview

  • Config Name: mssql
  • Node Count: Single node
  • Description: Babelfish (PG17) configuration template with SQL Server protocol compatibility
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c mssql [-i <primary_ip>]

Content

Source: pigsty/conf/mssql.yml

---
#==============================================================#
# File      :   mssql.yml
# Desc      :   Babelfish (MSSQL Wire-Compatible) template
# Ctime     :   2020-08-01
# Mtime     :   2026-07-08
# Docs      :   https://pigsty.io/docs/conf/mssql
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for Babelfish Kernel made by Pigsty
# Which is a PostgreSQL 17/18 fork with SQL Server Compatibility
# tutorial: https://pigsty.io/docs/pgsql/kernel/babelfish
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c mssql [-v 17/18]
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # Babelfish Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_mssql ,password: DBUser.MSSQL ,superuser: true, pgbouncer: true ,roles: [dbrole_admin], comment: superuser & owner for babelfish  }
        pg_databases:
          - name: mssql
            baseline: mssql.sql
            extensions: [uuid-ossp, babelfishpg_common, babelfishpg_tsql, babelfishpg_tds, babelfishpg_money ]
            owner: dbuser_mssql
            parameters: { 'babelfishpg_tsql.migration_mode' : 'multi-db' }
            comment: babelfish cluster, a MSSQL compatible pg cluster
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # Babelfish Ad Hoc Settings
        pg_mode: mssql                     # Microsoft SQL Server Compatible Mode
        pg_version: 17
        pg_packages: [ babelfish, pgsql-common, sqlcmd ]
        pg_libs: 'babelfishpg_tds, pg_stat_statements, auto_explain' # preload Babelfish TDS listener
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: dbuser_mssql ,db: mssql ,addr: intra ,auth: md5 ,title: 'allow mssql dbsu intranet access'      ,order: 525 } # <--- use md5 auth method for mssql user
          - { user: all          ,db: all   ,addr: intra ,auth: md5 ,title: 'everyone intranet access with md5 pwd' ,order: 800 }
        pg_default_services: # route primary & replica service to mssql port 1433
          - { name: primary ,port: 5433 ,dest: 1433  ,check: /primary   ,selector: "[]" }
          - { name: replica ,port: 5434 ,dest: 1433  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
          - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
          - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]" }

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false                 # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql       # babelfish kernel is in the pgsql repo
    node_tune: oltp                           # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 17                            # Babelfish kernel is compatible with postgres 17
    pg_conf: oltp.yml                         # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The mssql template allows you to use SQL Server Management Studio (SSMS) or other SQL Server client tools to connect to PostgreSQL (through Babelfish protocol compatibility).

Key Features:

  • Uses TDS protocol (port 1433), compatible with SQL Server clients
  • Supports T-SQL syntax, low migration cost
  • Retains PostgreSQL’s ACID properties and extension ecosystem (the current template uses PG17)
  • Supports multi-db and single-db migration modes
  • Default package set: babelfish + pgsql-common + sqlcmd
  • Creates uuid-ossp, babelfishpg_common, babelfishpg_tsql, babelfishpg_tds, and babelfishpg_money by default
  • v4.2.0 adds full mainstream platform coverage (EL 8/9/10, Debian 12/13, Ubuntu 22/24/26; x86_64 / aarch64)

Connection Methods:

# Using sqlcmd command line tool
sqlcmd -S 10.10.10.10,1433 -U dbuser_mssql -P DBUser.MSSQL -d mssql

# Using SSMS or Azure Data Studio
# Server: 10.10.10.10,1433
# Authentication: SQL Server Authentication
# Login: dbuser_mssql
# Password: DBUser.MSSQL

Use Cases:

  • Migrating from SQL Server to PostgreSQL
  • Applications needing to support both SQL Server and PostgreSQL clients
  • Leveraging PostgreSQL ecosystem while maintaining T-SQL compatibility

Notes:

  • The current mssql template is pinned to a PostgreSQL 17-compatible kernel; do not rely on -v to switch its major version
  • Default migration mode is multi-db (babelfishpg_tsql.migration_mode), configurable to single-db when needed
  • Some T-SQL syntax may have compatibility differences, refer to Babelfish compatibility documentation
  • Must use md5 authentication method (not scram-sha-256)

7.11 - polar

PolarDB for PostgreSQL kernel, provides Aurora-style storage-compute separation capability

The polar configuration template uses Alibaba Cloud’s PolarDB for PostgreSQL database kernel instead of native PostgreSQL, providing “cloud-native” Aurora-style storage-compute separation capability.

For the complete tutorial, see: PolarDB for PostgreSQL (POLAR) Kernel Guide. For kernel differences and version references, see the PGSQL kernel overview.


Overview

  • Config Name: polar
  • Node Count: Single node
  • Description: Uses PolarDB for PostgreSQL kernel
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c polar [-i <primary_ip>]

Content

Source: pigsty/conf/polar.yml

---
#==============================================================#
# File      :   polar.yml
# Desc      :   Pigsty 1-node PolarDB Kernel Config Template
# Ctime     :   2020-08-05
# Mtime     :   2026-07-08
# Docs      :   https://pigsty.io/docs/conf/polar
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for PolarDB PG Kernel,
# Which is a PostgreSQL 17 fork with RAC flavor features
# tutorial: https://pigsty.io/docs/pgsql/kernel/polardb
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c polar
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # PolarDB Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # PolarDB Ad Hoc Settings
        pg_version: 17                            # PolarDB PG is based on PG 17
        pg_mode: polar                            # PolarDB PG Compatible mode
        pg_packages: [ polardb, pgsql-common ]    # Replace PG kernel with PolarDB kernel
        pg_exporter_exclude_database: 'template0,template1,postgres,polardb_admin'
        pg_default_roles:                         # PolarDB require replicator as superuser
          - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
          - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
          - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
          - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
          - { name: postgres     ,superuser: true  ,comment: system superuser }
          - { name: replicator   ,superuser: true  ,replication: true ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator } # <- superuser is required for replication
          - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
          - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 17                      # PolarDB is compatible with PG 17
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

...

Explanation

The polar template uses Alibaba Cloud’s open-source PolarDB for PostgreSQL kernel, providing cloud-native database capabilities.

Key Features:

  • Storage-compute separation architecture, compute and storage nodes can scale independently
  • Supports one-write-multiple-read, read replicas scale in seconds
  • Compatible with PostgreSQL ecosystem, maintains SQL compatibility
  • Supports shared storage scenarios, suitable for cloud environment deployment
  • Default PolarDB kernel path is /usr/polar-17
  • Available extensions follow the PolarDB 17 kernel catalog. Common extensions include pgaudit, pg_partman, pg_profile, pg_repack, pg_stat_kcache, pg_cron, and pg_hint_plan

Use Cases:

  • Cloud-native scenarios requiring storage-compute separation architecture
  • Read-heavy write-light workloads
  • Scenarios requiring quick scaling of read replicas
  • Test environments for evaluating PolarDB features

Notes:

  • PolarDB is now based on PostgreSQL 17
  • Replication user requires superuser privileges (different from native PostgreSQL)
  • Some PostgreSQL extensions may have compatibility issues
  • The current template provides packages for both x86_64 and aarch64

7.12 - ivory

IvorySQL kernel, provides Oracle syntax and PL/SQL compatibility

The ivory configuration template uses Highgo’s IvorySQL database kernel instead of native PostgreSQL, providing Oracle syntax and PL/SQL compatibility.

For the complete tutorial, see: IvorySQL (Oracle Compatible) Kernel Guide


Overview

  • Config Name: ivory
  • Node Count: Single node
  • Description: Uses IvorySQL Oracle-compatible kernel
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c ivory [-i <primary_ip>]

Content

Source: pigsty/conf/ivory.yml

---
#==============================================================#
# File      :   ivory.yml
# Desc      :   IvorySQL 5 (Oracle Compatible) template
# Ctime     :   2024-08-05
# Mtime     :   2026-07-08
# Docs      :   https://pigsty.io/docs/conf/ivory
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for IvorySQL 5 Kernel,
# Which is a PostgreSQL 18 fork with Oracle Compatibility
# tutorial: https://pigsty.io/docs/pgsql/kernel/ivorysql
# Oracle compatible port (PGSQL Wire) is 1521
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c ivory
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # IvorySQL Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # IvorySQL Ad Hoc Settings
        pg_mode: ivory                                                 # Use IvorySQL Oracle Compatible Mode
        pg_packages: [ ivorysql, pgsql-common ]                        # install IvorySQL instead of postgresql kernel
        pg_libs: 'liboracle_parser, pg_stat_statements, auto_explain'  # pre-load oracle parser

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # IvorySQL kernel is compatible with postgres 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ivory template uses Highgo’s open-source IvorySQL kernel, providing Oracle database compatibility.

Key Features:

  • Supports Oracle PL/SQL syntax
  • Compatible with Oracle data types (NUMBER, VARCHAR2, etc.)
  • Supports Oracle-style packages
  • Retains all standard PostgreSQL functionality

Use Cases:

  • Migrating from Oracle to PostgreSQL
  • Applications needing both Oracle and PostgreSQL syntax support
  • Leveraging PostgreSQL ecosystem while maintaining PL/SQL compatibility
  • Test environments for evaluating IvorySQL features

Notes:

  • IvorySQL 5 is based on PostgreSQL 18
  • Using liboracle_parser requires loading into shared_preload_libraries
  • pgbackrest may have checksum issues in Oracle-compatible mode, PITR capability is limited
  • The current package matrix covers EL 8/9/10, Debian 12/13, Ubuntu 22/24/26, and both architectures

7.13 - agens

AgensGraph kernel template with property graph model and Cypher query support

The agens configuration template replaces native PostgreSQL with the AgensGraph kernel and enables property-graph modeling plus Cypher queries.

For the full guide, see: AgensGraph kernel guide


Overview

  • Config name: agens
  • Node count: Single node
  • Description: AgensGraph (PG17) graph database kernel template
  • Supported OS: el8, el9, el10, d12, d13, u22, u24, u26
  • Supported arch: x86_64, aarch64
  • Related templates: meta, pgsql

Enable with:

./configure -c agens [-i <primary_ip>]

Template Content

Source: pigsty/conf/agens.yml

---
#==============================================================#
# File      :   agens.yml
# Desc      :   1-node AgensGraph (Graph DB) template
# Ctime     :   2026-02-26
# Mtime     :   2026-07-06
# Docs      :   https://pigsty.io/docs/conf/agens
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for AgensGraph Kernel,
# Which is a PostgreSQL 17 fork with graph capabilities.
# tutorial: https://pigsty.io/docs/pgsql/kernel/agensgraph
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c agens
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # AgensGraph Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # AgensGraph Ad Hoc Settings
        pg_mode: agens                                   # AgensGraph compatible mode
        pg_packages: [ agensgraph, pgsql-common ]        # install AgensGraph kernel package + common utils

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 17                      # AgensGraph kernel is compatible with postgres 17
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Notes

The agens template enables pg_mode: agens in the pg-meta cluster and installs the agensgraph kernel package instead of standard PostgreSQL.

Key features:

  • Property graph model support (Vertex / Edge)
  • Cypher query syntax, can be combined with SQL
  • Compatible with PostgreSQL ecosystem and standard operations
  • Based on PostgreSQL 17-compatible kernel by default

Typical use cases:

  • Graph relationship analysis and path queries
  • Social graph, risk linkage, knowledge graph scenarios
  • Workloads requiring graph queries within PostgreSQL operations

Caveats:

  • Current AgensGraph template is pinned to pg_version: 17
  • Default topology is single-node for quick validation; production should extend with HA topology planning
  • Graph schema and Cypher semantics should follow official AgensGraph docs

7.14 - pgedge

pgEdge kernel template for distributed multi-master PostgreSQL in edge scenarios

The pgedge configuration template replaces native PostgreSQL with the pgEdge kernel and provides distributed, multi-master capabilities for edge deployments.

For the full guide, see: pgEdge kernel guide. For kernel differences and version references, see the PGSQL kernel overview.


Overview

  • Config name: pgedge
  • Node count: Single node
  • Description: pgEdge (PG18) distributed kernel template
  • Supported OS: d12, d13, u22, u24, u26 for PG18 packages. For EL/RPM platforms, check current PGSQL repository availability for pgedge_18.
  • Supported arch: x86_64, aarch64
  • Related templates: meta, pgsql

Enable with:

./configure -c pgedge [-i <primary_ip>]

Template Content

Source: pigsty/conf/pgedge.yml

---
#==============================================================#
# File      :   pgedge.yml
# Desc      :   1-node pgEdge (Distributed PG) template
# Ctime     :   2026-02-26
# Mtime     :   2026-07-08
# Docs      :   https://pigsty.io/docs/conf/pgedge
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for pgEdge Kernel,
# Which is a PostgreSQL 15/16/17/18 compatible fork, default to 18.
# tutorial: https://pigsty.io/docs/pgsql/kernel/pgedge
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c pgedge [-v 15/16/17/18]
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # pgEdge Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [spock, snowflake, lolor]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # pgEdge Ad Hoc Settings
        pg_mode: pgedge                               # pgEdge compatible mode
        pg_packages: [ pgedge, pgsql-common ]         # install pgEdge kernel package + common utils
        pg_libs: 'spock, lolor, pg_stat_statements, auto_explain' # preload required libs for pgEdge logical replication

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # pgEdge kernel is compatible with postgres 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Notes

The pgedge template enables pg_mode: pgedge in pg-meta and pre-installs pgEdge core extensions for logical replication and edge distribution.

Key features:

  • Uses the pgedge kernel package (PG15/16/17/18 compatible, default PG18)
  • Bundles spock, snowflake, and lolor in the pgedge-$v kernel package and creates them in the meta database by default
  • Preloads spock and lolor for multi-master setup readiness
  • Keeps Pigsty standard backup, monitoring, and operations workflow

Typical use cases:

  • Multi-region edge deployment with nearby writes
  • Multi-master logical replication with conflict handling
  • Single-node validation before distributed rollout

Caveats:

  • Current template is for single-node kernel validation; production multi-master needs explicit topology and replication strategy planning
  • Default is pg_version: 18; keep consistent with target cluster versions
  • Evaluate latency and conflict policy before cross-region replication

7.15 - mysql

OpenHalo kernel, provides MySQL protocol and syntax compatibility

The mysql configuration template uses OpenHalo database kernel instead of native PostgreSQL, providing MySQL wire protocol and SQL syntax compatibility.


Overview

  • Config Name: mysql
  • Node Count: Single node
  • Description: OpenHalo MySQL-compatible kernel configuration
  • OS Distro: EL 8/9/10, Debian 12/13, Ubuntu 22/24/26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c mysql [-i <primary_ip>]

Content

Source: pigsty/conf/mysql.yml

---
#==============================================================#
# File      :   mysql.yml
# Desc      :   1-node OpenHaloDB (MySQL Compatible) template
# Ctime     :   2025-04-03
# Mtime     :   2026-07-08
# Docs      :   https://pigsty.io/docs/conf/mysql
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for OpenHalo PG Kernel,
# Which is a PostgreSQL 14 fork with MySQL Wire Compatibility
# tutorial: https://pigsty.io/docs/pgsql/kernel/openhalo
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c mysql
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # OpenHalo Database Cluster
    #----------------------------------------------#
    # connect with mysql client: mysql -h 10.10.10.10 -u dbuser_meta -D mysql (the actual database is 'postgres', and 'mysql' is a schema)
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: postgres, extensions: [aux_mysql]} # the mysql compatible database
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # OpenHalo Ad Hoc Setting
        pg_mode: mysql                    # MySQL Compatible Mode by HaloDB
        pg_version: 14                    # OpenHaloDB is compatible with PG Major Version 14
        pg_packages: [ openhalo, pgsql-common ]  # install openhalodb instead of postgresql kernel

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 14                      # OpenHalo is compatible with PG 14
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The mysql template uses the OpenHalo kernel, allowing you to connect to PostgreSQL using MySQL client tools.

Key Features:

  • Uses MySQL protocol (port 3306), compatible with MySQL clients
  • Supports a subset of MySQL SQL syntax
  • Retains PostgreSQL’s ACID properties and storage engine
  • Supports both PostgreSQL and MySQL protocol connections simultaneously

Connection Methods:

# Using MySQL client
mysql -h 10.10.10.10 -P 3306 -u dbuser_meta -pDBUser.Meta

# Also retains PostgreSQL connection capability
psql postgres://dbuser_meta:[email protected]:5432/meta

Use Cases:

  • Migrating from MySQL to PostgreSQL
  • Applications needing to support both MySQL and PostgreSQL clients
  • Leveraging PostgreSQL ecosystem while maintaining MySQL compatibility

Notes:

  • OpenHalo is based on PostgreSQL 14, does not support higher version features
  • Some MySQL syntax may have compatibility differences
  • The current openhalo package alias covers Pigsty’s supported Linux platforms on both architectures; actual installation still depends on the target platform’s repository index

7.16 - pgtde

Percona PostgreSQL kernel, provides Transparent Data Encryption (pg_tde) capability

The pgtde configuration template uses Percona PostgreSQL database kernel, providing Transparent Data Encryption (TDE) capability.


Overview

  • Config Name: pgtde
  • Node Count: Single node
  • Description: Percona PostgreSQL transparent data encryption configuration
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c pgtde [-i <primary_ip>]

Content

Source: pigsty/conf/pgtde.yml

---
#==============================================================#
# File      :   pgtde.yml
# Desc      :   PG TDE with Percona PostgreSQL 1-node template
# Ctime     :   2025-07-04
# Mtime     :   2026-07-23
# Docs      :   https://pigsty.io/docs/conf/pgtde
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for Percona PostgreSQL Distribution
# with pg_tde, currently based on PostgreSQL 18
# tutorial: https://pigsty.io/docs/pgsql/kernel/percona
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c pgtde
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # Percona Postgres Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: pgtde
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: pigsty tde database
            schemas: [pigsty]
            extensions: [ vector, postgis, pg_tde ,pgaudit, { name: pg_stat_monitor, schema: monitor } ]
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # Percona PostgreSQL TDE Kernel Settings
        pg_packages: [ pgtde, pgsql-common ]  # install Pigsty private-prefix Percona packages
        pg_libs: 'pg_tde, pgaudit, pg_stat_statements, pg_stat_monitor, auto_explain'

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql
    node_tune: oltp

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # Default Percona TDE PG Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The pgtde template selects pg_mode: pgtde and installs the pgtde package alias. Pigsty links the private /usr/pgtde-$v prefix (currently /usr/pgtde-18) to its stable /usr/pgsql entry point.

Key Features:

  • Transparent Data Encryption: Data automatically encrypted on disk, transparent to applications
  • Key Management: Supports local keys and external Key Management Systems (KMS)
  • Table-level Encryption: Selectively encrypt sensitive tables
  • Full Compatibility: Fully compatible with native PostgreSQL

Use Cases:

  • Meeting data security compliance requirements (e.g., PCI-DSS, HIPAA)
  • Storing sensitive data (e.g., personal information, financial data)
  • Scenarios requiring data-at-rest encryption
  • Enterprise environments with strict data security requirements

Usage:

CREATE EXTENSION pg_tde;

SELECT pg_tde_add_database_key_provider_file(
    'local-file',
    '/secure/path/pg_tde_keys'
);
SELECT pg_tde_set_principal_key('app-principal-key', 'local-file');

-- Create encrypted table
CREATE TABLE sensitive_data (
    id SERIAL PRIMARY KEY,
    ssn VARCHAR(11)
) USING tde_heap;

-- Or enable encryption on existing table
ALTER TABLE existing_table SET ACCESS METHOD tde_heap;

Notes:

  • Percona PostgreSQL is based on PostgreSQL 18
  • Encryption brings some performance overhead (typically 5-15%)
  • Encryption keys must be properly managed
  • Both x86_64 and aarch64 packages are available on the listed distributions

7.17 - oriole

OrioleDB kernel, provides bloat-free OLTP enhanced storage engine

The oriole configuration template uses OrioleDB storage engine instead of PostgreSQL’s default Heap storage, providing bloat-free, high-performance OLTP capability.


Overview

  • Config Name: oriole
  • Node Count: Single node
  • Description: OrioleDB bloat-free storage engine configuration
  • PostgreSQL Major: 16, 17, or 18
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c oriole [-i <primary_ip>]

# Select a PostgreSQL major version explicitly
./configure -c oriole -v 16
./configure -c oriole -v 17
./configure -c oriole -v 18

Content

Source: pigsty/conf/oriole.yml

---
#==============================================================#
# File      :   oriole.yml
# Desc      :   1-node OrioleDB (OLTP Enhancement) template
# Ctime     :   2025-04-05
# Mtime     :   2026-07-08
# Docs      :   https://pigsty.io/docs/conf/oriole
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for OrioleDB Kernel,
# Which is a Patched PostgreSQL 16/17/18 fork
# tutorial: https://pigsty.io/docs/pgsql/kernel/orioledb
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c oriole [-v 16/17/18]
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }} ,vars: { etcd_cluster: etcd  }}
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------------------#
    # OrioleDB Database Cluster
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty], extensions: [orioledb]}
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # OrioleDB Ad Hoc Settings
        pg_mode: oriole                                         # OrioleDB compatible mode
        pg_packages: [ orioledb, pgsql-common ]                 # install OrioleDB kernel
        pg_libs: 'orioledb, pg_stat_statements, auto_explain'   # Load OrioleDB Extension

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname on single node mode
    node_repo_modules: node,infra,pgsql # add these repos directly to the singleton node
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # OrioleDB Kernel is based on PG 16/17/18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The oriole template uses OrioleDB storage engine, fundamentally solving PostgreSQL table bloat problems.

Key Features:

  • Bloat-free Design: Uses UNDO logs instead of Multi-Version Concurrency Control (MVCC)
  • No VACUUM Required: Eliminates performance jitter from autovacuum
  • Row-level WAL: More efficient logging and replication
  • Compressed Storage: Built-in data compression, reduces storage space

Use Cases:

  • High-frequency update OLTP workloads
  • Applications sensitive to write latency
  • Need for stable response times (eliminates VACUUM impact)
  • Large tables with frequent updates causing bloat

Usage:

-- Create table using OrioleDB storage
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INT,
    amount DECIMAL(10,2)
) USING orioledb;

-- Existing tables cannot be directly converted, need to be rebuilt

Notes:

  • OrioleDB supports PostgreSQL 16, 17, and 18; the template defaults to PG18, and you can select a major version with -v 16, -v 17, or -v 18
  • Need to add orioledb to shared_preload_libraries
  • Some PostgreSQL features may not be fully supported
  • Use the matching OrioleDB packages for the selected PostgreSQL major and OS architecture

7.18 - PostgreSQL Mongo Mode

Run PostgreSQL in Mongo-compatible mode with DocumentDB and the FerretDB Docker APP.

The mongo configuration template is a PostgreSQL deployment mode, not an independent Pigsty module. It combines:

  • PostgreSQL 18 managed by the standard PGSQL module
  • The documentdb extension and its required preload libraries
  • A stateless FerretDB proxy deployed with Pigsty’s Docker APP workflow

All data, high availability, backup, monitoring, and lifecycle management remain PostgreSQL responsibilities. FerretDB only provides the MongoDB wire-compatible endpoint.


Quick Start

The default template is a single-node deployment on 10.10.10.10. FerretDB listens on loopback by default.

Install mongosh separately if it is not already available, or use another MongoDB-compatible client.

./configure -c mongo
./deploy.yml
./docker.yml -l pg-meta
./app.yml -l pg-meta
mongosh 'mongodb://mongod:[email protected]:27017/'

The dedicated mongod PostgreSQL login is declared by the template. FerretDB authentication is enabled, but MongoDB authorization roles are not implemented; PostgreSQL remains the security boundary.


Architecture

LayerImplementationResponsibility
DataPostgreSQL + DocumentDBDurable storage, transactions, HA, PITR, ACL, monitoring
ProtocolFerretDB Docker APPStateless MongoDB wire compatibility
Access127.0.0.1:27017 by defaultLocal MongoDB client endpoint

The container connects to Pigsty’s local primary service on port 5436 through host.docker.internal. The default Mongo endpoint is not exposed to the network; change FERRETDB_BIND_ADDR only when remote access is required.


Configuration

Source: pigsty/conf/mongo.yml

---
#==============================================================#
# File      :   mongo.yml
# Desc      :   PostgreSQL Mongo Mode (DocumentDB + FerretDB)
# Ctime     :   2025-02-23
# Mtime     :   2026-08-05
# Docs      :   https://pigsty.io/docs/conf/mongo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the PostgreSQL Mongo mode template, powered by DocumentDB + FerretDB
# It provides a MongoDB wire-compatible endpoint backed by PostgreSQL
# This config template works with PostgreSQL 16, 17, 18
# tutorial: https://pigsty.io/docs/conf/mongo
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c mongo
#   ./deploy.yml
#   ./docker.yml -l pg-meta
#   ./app.yml -l pg-meta
#   # install mongosh separately if it is not already available
#   mongosh 'mongodb://mongod:[email protected]:27017/'

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }} ,vars: { repo_enabled: false }}
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
        #10.10.10.11: { etcd_seq: 2 }
        #10.10.10.12: { etcd_seq: 3 }
      vars: { etcd_cluster: etcd }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

    #----------------------------------#
    # PGSQL Database Cluster
    #----------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: mongod      ,password: DBUser.Mongo  ,superuser: true  ,comment: FerretDB backend user }
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: postgres, extensions: [ documentdb, postgis, vector, pg_cron, rum ]}  # run on the postgres database
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
          # WARNING: demo/dev only. Avoid world access for dbsu in production.
          - { user: postgres    , db: all ,addr: world ,auth: pwd ,title: 'dbsu password access everywhere' }
          - { user: all ,db: all ,addr: localhost ,order: 1  ,auth: trust ,title: 'documentdb localhost trust access' }
          - { user: all ,db: all ,addr: local     ,order: 1  ,auth: trust ,title: 'documentdb local     trust access' }
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_parameters: { cron.database_name: postgres }
        pg_extensions: [ documentdb, postgis, pgvector, pg_cron, rum ]
        pg_libs: 'pg_documentdb, pg_documentdb_core, pg_documentdb_extended_rum, pg_cron, pg_stat_statements, auto_explain'
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'

        # FerretDB Docker APP on the same node, exposed at 127.0.0.1:27017
        docker_enabled: true
        app: ferretdb
        apps:
          ferretdb:
            conf:
              FERRETDB_IMAGE: ghcr.io/ferretdb/ferretdb:2.7.0
              FERRETDB_POSTGRESQL_URL: 'postgres://mongod:[email protected]:5436/postgres?pool_min_conns=1&pool_max_conns=20'
              FERRETDB_BIND_ADDR: 127.0.0.1
              FERRETDB_PORT: 27017
              FERRETDB_LISTEN_ADDR: ':27017'
              FERRETDB_AUTH: true
              FERRETDB_TELEMETRY: disabled

    #--------------------------------------------------------------------------#
    # OPTIONAL: Three-node PostgreSQL + DocumentDB + FerretDB HA cluster
    # Uncomment this entire block and the two additional etcd members above.
    # Then run: ./docker.yml -l pg-mongo && ./app.yml -l pg-mongo
    # Endpoint: mongodb://mongod:[email protected]:27017/
    #--------------------------------------------------------------------------#
    # pg-mongo:
    #   hosts:
    #     10.10.10.11: { pg_seq: 1, pg_role: primary, vip_role: master }
    #     10.10.10.12: { pg_seq: 2, pg_role: replica, vip_role: backup }
    #     10.10.10.13: { pg_seq: 3, pg_role: replica, vip_role: backup }
    #   vars:
    #     pg_cluster: pg-mongo
    #     node_cluster: pg-mongo
    #     pg_users:
    #       - { name: mongod, password: DBUser.Mongo, superuser: true, comment: FerretDB backend user }
    #     pg_databases:
    #       - { name: postgres, extensions: [ documentdb, postgis, vector, pg_cron, rum ] }
    #     pg_hba_rules:
    #       - { user: all, db: all, addr: localhost, order: 1, auth: trust, title: 'documentdb localhost trust access' }
    #       - { user: all, db: all, addr: local, order: 1, auth: trust, title: 'documentdb local trust access' }
    #       - { user: mongod, db: postgres, addr: intra, order: 800, auth: pwd, title: 'ferretdb intranet access with password' }
    #     pg_parameters: { cron.database_name: postgres }
    #     pg_extensions: [ documentdb, postgis, pgvector, pg_cron, rum ]
    #     pg_libs: 'pg_documentdb, pg_documentdb_core, pg_documentdb_extended_rum, pg_cron, pg_stat_statements, auto_explain'
    #     pg_crontab:
    #       - '00 01 * * 1 /pg/bin/pg-backup full'
    #       - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'
    #
    #     # FerretDB Docker cluster and HAProxy service
    #     docker_enabled: true
    #     app: ferretdb
    #     apps:
    #       ferretdb:
    #         conf:
    #           FERRETDB_IMAGE: ghcr.io/ferretdb/ferretdb:2.7.0
    #           FERRETDB_POSTGRESQL_URL: 'postgres://mongod:[email protected]:5436/postgres?pool_min_conns=1&pool_max_conns=20'
    #           FERRETDB_BIND_ADDR: '{{ inventory_hostname }}'
    #           FERRETDB_PORT: 27018
    #           FERRETDB_LISTEN_ADDR: ':27017'
    #           FERRETDB_AUTH: true
    #           FERRETDB_TELEMETRY: disabled
    #
    #     # HA Mongo endpoint: mongo.pigsty / 10.10.10.4:27017
    #     vip_enabled: true
    #     vip_vrid: 27
    #     vip_address: 10.10.10.4
    #     vip_preempt: false
    #     haproxy_services:
    #       - name: mongo
    #         port: 27017
    #         protocol: tcp
    #         balance: leastconn
    #         options:
    #           - option tcp-check
    #         servers:
    #           - { name: ferretdb-1, ip: 10.10.10.11, port: 27018, options: 'check port 27018' }
    #           - { name: ferretdb-2, ip: 10.10.10.12, port: 27018, options: 'check port 27018' }
    #           - { name: ferretdb-3, ip: 10.10.10.13, port: 27018, options: 'check port 27018' }

  vars:                               # global variables
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false           # do not overwrite node hostname
    node_repo_modules: node,infra,pgsql # install from upstream repo directly
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # default postgres version (16,17,18)
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

FerretDB settings are ordinary APP overrides under apps.ferretdb.conf:

app: ferretdb
apps:
  ferretdb:
    conf:
      FERRETDB_IMAGE: ghcr.io/ferretdb/ferretdb:2.7.0
      FERRETDB_POSTGRESQL_URL: 'postgres://mongod:[email protected]:5436/postgres?pool_min_conns=1&pool_max_conns=20'
      FERRETDB_BIND_ADDR: 127.0.0.1
      FERRETDB_PORT: 27017
      FERRETDB_AUTH: true
      FERRETDB_TELEMETRY: disabled

Use the standard PostgreSQL parameters, playbooks, dashboards, and administration procedures for the backend cluster. There are no mongo_* inventory parameters or standalone mongo.yml playbook.


Optional HA Topology

The template contains a commented pg-mongo example for three PostgreSQL/FerretDB nodes. Uncomment that block and the two additional etcd members when needed.

In HA mode, each FerretDB container binds {{ inventory_hostname }}:27018; HAProxy exposes all three backends through the floating endpoint 10.10.10.4:27017 (mongo.pigsty). PostgreSQL failover is still handled by Patroni, while FerretDB remains stateless.


Notes

  • The template includes development-friendly HBA examples; tighten them for production.
  • Client-side MongoDB TLS is not enabled by default.
  • Monitor the backend with the standard PostgreSQL and Docker dashboards; there is no separate FERRET module or dedicated module dashboard.
  • Repeat an authenticated CRUD smoke test after upgrading FerretDB or DocumentDB.

7.19 - ha/simu

20-node production environment simulation for large-scale deployment testing

The ha/simu configuration template is a 20-node production environment simulation, requiring a powerful host machine to run.


Overview

  • Config Name: ha/simu
  • Node Count: 20 nodes, pigsty/vagrant/spec/simu.rb
  • Description: 20-node production environment simulation, requires powerful host machine
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64

Usage:

./configure -c ha/simu [-i <primary_ip>]

Content

Source: pigsty/conf/ha/simu.yml

---
#==============================================================#
# File      :   simu.yml
# Desc      :   Pigsty Simubox: a 20 node prod simulation env
# Ctime     :   2023-07-20
# Mtime     :   2026-01-19
# Docs      :   https://pigsty.io/docs/conf/simu
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license
# Copyright :   2018-2025  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:

  children:

    #==========================================================#
    # infra: 3 nodes
    #==========================================================#
    # ./infra.yml -l infra
    # ./docker.yml -l infra (optional)
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars:
        docker_enabled: true
        node_tune: oltp         # use oltp template for infra nodes
        pg_conf: oltp.yml       # use oltp template for infra pgsql
        pg_exporters:           # bin/pgmon-add pg-meta2/pg-src2/pg-dst2
          20001: {pg_cluster: pg-meta2   ,pg_seq: 1 ,pg_host: 10.10.10.10, pg_databases: [{ name: meta }]}
          20002: {pg_cluster: pg-meta2   ,pg_seq: 2 ,pg_host: 10.10.10.11, pg_databases: [{ name: meta }]}
          20003: {pg_cluster: pg-meta2   ,pg_seq: 3 ,pg_host: 10.10.10.12, pg_databases: [{ name: meta }]}

          20004: {pg_cluster: pg-src2    ,pg_seq: 1 ,pg_host: 10.10.10.31, pg_databases: [{ name: src }]}
          20005: {pg_cluster: pg-src2    ,pg_seq: 2 ,pg_host: 10.10.10.32, pg_databases: [{ name: src }]}
          20006: {pg_cluster: pg-src2    ,pg_seq: 3 ,pg_host: 10.10.10.33, pg_databases: [{ name: src }]}

          20007: {pg_cluster: pg-dst2    ,pg_seq: 1 ,pg_host: 10.10.10.41, pg_databases: [{ name: dst }]}
          20008: {pg_cluster: pg-dst2    ,pg_seq: 2 ,pg_host: 10.10.10.42, pg_databases: [{ name: dst }]}
          20009: {pg_cluster: pg-dst2    ,pg_seq: 3 ,pg_host: 10.10.10.43, pg_databases: [{ name: dst }]}


    #==========================================================#
    # etcd: 5 nodes dedicated etcd cluster
    #==========================================================#
    # ./etcd.yml -l etcd;
    etcd:
      hosts:
        10.10.10.25: { etcd_seq: 1 }
        10.10.10.26: { etcd_seq: 2 }
        10.10.10.27: { etcd_seq: 3 }
        10.10.10.28: { etcd_seq: 4 }
        10.10.10.29: { etcd_seq: 5 }
      vars:
        etcd_cluster: etcd

    #==========================================================#
    # minio: 4 nodes dedicated minio cluster
    #==========================================================#
    # ./minio.yml -l minio;
    minio:
      hosts:
        10.10.10.21: { minio_seq: 1 }
        10.10.10.22: { minio_seq: 2 }
        10.10.10.23: { minio_seq: 3 }
        10.10.10.24: { minio_seq: 4 }
      vars:
        minio_cluster: minio
        minio_data: '/data{1...4}' # 4 node x 4 disk
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }


    #==========================================================#
    # proxy: 2 nodes used as dedicated haproxy server
    #==========================================================#
    # ./node.yml -l proxy
    proxy:
      hosts:
        10.10.10.18: { vip_role: master }
        10.10.10.19: { vip_role: backup }
      vars:
        vip_enabled: true
        vip_address: 10.10.10.20
        vip_vrid: 20
        haproxy_services:      # expose minio service : sss.pigsty:9000
          - name: minio        # [REQUIRED] service name, unique
            port: 9000         # [REQUIRED] service port, unique
            balance: leastconn # Use leastconn algorithm and minio health check
            options: [ "option httpchk", "option http-keep-alive", "http-check send meth OPTIONS uri /minio/health/live", "http-check expect status 200" ]
            servers:           # reload service with ./node.yml -t haproxy_config,haproxy_reload
              - { name: minio-1 ,ip: 10.10.10.21 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-2 ,ip: 10.10.10.22 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-3 ,ip: 10.10.10.23 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-4 ,ip: 10.10.10.24 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

    #==========================================================#
    # pg-meta: reuse infra node as meta cmdb
    #==========================================================#
    # ./pgsql.yml -l pg-meta
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1 , pg_role: primary }
        10.10.10.11: { pg_seq: 2 , pg_role: replica }
        10.10.10.12: { pg_seq: 3 , pg_role: replica }
      vars:
        pg_cluster: pg-meta
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_users:
          - {name: dbuser_meta     ,password: DBUser.Meta     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
          - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
          - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
          - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
          - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
          - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
          - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: vector}]}
          - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
          - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
          - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
          - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }
        pg_libs: 'pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries

    #==========================================================#
    # pg-src: dedicate 3 node source cluster
    #==========================================================#
    # ./pgsql.yml -l pg-src
    pg-src:
      hosts:
        10.10.10.31: { pg_seq: 1, pg_role: primary }
        10.10.10.32: { pg_seq: 2, pg_role: replica }
        10.10.10.33: { pg_seq: 3, pg_role: replica }
      vars:
        pg_cluster: pg-src
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: src }]


    #==========================================================#
    # pg-dst: dedicate 3 node destination cluster
    #==========================================================#
    # ./pgsql.yml -l pg-dst
    pg-dst:
      hosts:
        10.10.10.41: { pg_seq: 1, pg_role: primary }
        10.10.10.42: { pg_seq: 2, pg_role: replica }
        10.10.10.43: { pg_seq: 3, pg_role: replica }
      vars:
        pg_cluster: pg-dst
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.4/24
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: dst } ]


    #==========================================================#
    # redis-meta: reuse the 5 etcd nodes as redis sentinel
    #==========================================================#
    # ./redis.yml -l redis-meta
    redis-meta:
      hosts:
        10.10.10.25: { redis_node: 1 , redis_instances: { 26379: {} } }
        10.10.10.26: { redis_node: 2 , redis_instances: { 26379: {} } }
        10.10.10.27: { redis_node: 3 , redis_instances: { 26379: {} } }
        10.10.10.28: { redis_node: 4 , redis_instances: { 26379: {} } }
        10.10.10.29: { redis_node: 5 , redis_instances: { 26379: {} } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 256MB
        redis_sentinel_monitor:  # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-src, host: 10.10.10.31, port: 6379 ,password: redis.src, quorum: 1 }
          - { name: redis-dst, host: 10.10.10.41, port: 6379 ,password: redis.dst, quorum: 1 }

    #==========================================================#
    # redis-src: reuse pg-src 3 nodes for redis
    #==========================================================#
    # ./redis.yml -l redis-src
    redis-src:
      hosts:
        10.10.10.31: { redis_node: 1 , redis_instances: {6379: {  } }}
        10.10.10.32: { redis_node: 2 , redis_instances: {6379: { replica_of: '10.10.10.31 6379' }, 6380: { replica_of: '10.10.10.32 6379' } }}
        10.10.10.33: { redis_node: 3 , redis_instances: {6379: { replica_of: '10.10.10.31 6379' }, 6380: { replica_of: '10.10.10.33 6379' } }}
      vars:
        redis_cluster: redis-src
        redis_password: 'redis.src'
        redis_max_memory: 64MB

    #==========================================================#
    # redis-dst: reuse pg-dst 3 nodes for redis
    #==========================================================#
    # ./redis.yml -l redis-dst
    redis-dst:
      hosts:
        10.10.10.41: { redis_node: 1 , redis_instances: {6379: {  }                               }}
        10.10.10.42: { redis_node: 2 , redis_instances: {6379: { replica_of: '10.10.10.41 6379' } }}
        10.10.10.43: { redis_node: 3 , redis_instances: {6379: { replica_of: '10.10.10.41 6379' } }}
      vars:
        redis_cluster: redis-dst
        redis_password: 'redis.dst'
        redis_max_memory: 64MB

    #==========================================================#
    # pg-tmp: reuse proxy nodes as pgsql cluster
    #==========================================================#
    # ./pgsql.yml -l pg-tmp
    pg-tmp:
      hosts:
        10.10.10.18: { pg_seq: 1 ,pg_role: primary }
        10.10.10.19: { pg_seq: 2 ,pg_role: replica }
      vars:
        pg_cluster: pg-tmp
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: tmp } ]

    #==========================================================#
    # pg-etcd: reuse etcd nodes as pgsql cluster
    #==========================================================#
    # ./pgsql.yml -l pg-etcd
    pg-etcd:
      hosts:
        10.10.10.25: { pg_seq: 1 ,pg_role: primary }
        10.10.10.26: { pg_seq: 2 ,pg_role: replica }
        10.10.10.27: { pg_seq: 3 ,pg_role: replica }
        10.10.10.28: { pg_seq: 4 ,pg_role: replica }
        10.10.10.29: { pg_seq: 5 ,pg_role: offline }
      vars:
        pg_cluster: pg-etcd
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: etcd } ]

    #==========================================================#
    # pg-minio: reuse minio nodes as pgsql cluster
    #==========================================================#
    # ./pgsql.yml -l pg-minio
    pg-minio:
      hosts:
        10.10.10.21: { pg_seq: 1 ,pg_role: primary }
        10.10.10.22: { pg_seq: 2 ,pg_role: replica }
        10.10.10.23: { pg_seq: 3 ,pg_role: replica }
        10.10.10.24: { pg_seq: 4 ,pg_role: replica }
      vars:
        pg_cluster: pg-minio
        pg_users: [ { name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] } ]
        pg_databases: [ { name: minio } ]

  #============================================================#
  # Global Variables
  #============================================================#
  vars:

    #==========================================================#
    # INFRA
    #==========================================================#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      minio        : { domain: m.pigsty    ,endpoint: "10.10.10.21:9001" ,scheme: https ,websocket: true }
      postgrest    : { domain: api.pigsty  ,endpoint: "127.0.0.1:8884" }
      pgadmin      : { domain: adm.pigsty  ,endpoint: "127.0.0.1:8885" }
      pgweb        : { domain: cli.pigsty  ,endpoint: "127.0.0.1:8886" }
      bytebase     : { domain: ddl.pigsty  ,endpoint: "127.0.0.1:8887" }
      jupyter      : { domain: lab.pigsty  ,endpoint: "127.0.0.1:8888"  , websocket: true }
      supa         : { domain: supa.pigsty ,endpoint: "10.10.10.10:8000", websocket: true }

    #==========================================================#
    # NODE
    #==========================================================#
    node_id_from_pg: true             # use nodename rather than pg identity as hostname
    node_tune: tiny                   # use small node template
    node_firewall_mode: zone          # default: trust intranet, expose selected public ports
    node_timezone: Asia/Hong_Kong     # use Asia/Hong_Kong Timezone
    node_dns_servers:                 # DNS servers in /etc/resolv.conf
      - 10.10.10.10
      - 10.10.10.11
    node_etc_hosts:
      - 10.10.10.10 i.pigsty
      - 10.10.10.20 sss.pigsty        # point minio service domain to the L2 VIP of proxy cluster
    node_ntp_servers:                 # NTP servers in /etc/chrony.conf
      - pool cn.pool.ntp.org iburst
      - pool 10.10.10.10 iburst
    node_admin_ssh_exchange: false    # exchange admin ssh key among node cluster

    #==========================================================#
    # PGSQL
    #==========================================================#
    pg_conf: tiny.yml
    pgbackrest_method: minio          # USE THE HA MINIO THROUGH A LOAD BALANCER
    pg_dbsu_ssh_exchange: false       # do not exchange dbsu ssh key among pgsql cluster
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `//pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days
    pg_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
      - '00 01  * * * /pg/bin/pg-backup'
      - '00 05 * * *  /pg/bin/pg-vacuum'
    pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
      - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }

    #==========================================================#
    # Repo
    #==========================================================#
    repo_packages: [
      node-bootstrap, infra-package, infra-addons, node-package1, node-package2, node-package3, pgsql-utility, extra-modules,
      pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl
    ]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/simu template is a large-scale production environment simulation for testing and validating complex scenarios.

Architecture:

  • 2-node HA INFRA (monitoring/alerting/Nginx/DNS)
  • 5-node HA ETCD and MINIO (Silo, multi-disk)
  • 2-node Proxy (HAProxy + Keepalived VIP)
  • Multiple PostgreSQL clusters:
    • pg-meta: 2-node HA
    • pg-v14~v18: Single-node multi-version testing
    • pg-pitr: Single-node PITR testing
    • pg-test: 4-node HA
    • pg-src/pg-dst: 3+2 node replication testing
    • pg-citus: 10-node distributed cluster
  • Multiple Redis modes: primary-replica, sentinel, cluster

Use Cases:

  • Large-scale deployment testing and validation
  • High availability failover drills
  • Performance benchmarking
  • New feature preview and evaluation

Notes:

  • Requires powerful host machine (64GB+ RAM recommended)
  • Uses Vagrant virtual machines for simulation

7.20 - ha/octo

Compact eight-node HA simulation with three INFRA nodes, five etcd nodes, eight object-storage nodes, and two PostgreSQL clusters.

ha/octo uses the first eight nodes from vagrant/spec/deci.rb to build a compact high-availability simulation. It exercises co-located modules, VIPs, remote backup, and larger membership counts. Do not use it directly as a production blueprint without reviewing capacity, security, and failure domains.


Overview

  • Config name: ha/octo
  • Node addresses: 10.10.10.10 through 10.10.10.17
  • INFRA: 3 nodes; only the first builds and serves the local repository, while Docker can be installed separately on all three as noted in comments
  • ETCD: 5 nodes on the last five hosts
  • Object storage: one eight-node, single-drive cluster; the template does not override minio_type, so both deployment and removal roles default to Silo; verify that value, the exact target, and data paths before removal
  • pg-meta: 3-node PostgreSQL cluster with VIP 10.10.10.2/24
  • pg-test: 5-node PostgreSQL cluster whose final instance has the offline role, with VIP 10.10.10.3/24
  • Backup: uses the object-storage repository through sss.pigsty:9002 and also retains a local repository
./configure -c ha/octo
./deploy.yml

This template depends on fixed eight-node addresses and VIPs. For any other environment, update the host addresses, VIPs, interfaces, DNS, repository node, and every public example credential together.


Content

Source: pigsty/conf/ha/octo.yml

---
#==============================================================#
# File      :   octo.yml
# Desc      :   Pigsty 8-node compact HA simulation config
# Ctime     :   2026-07-29
# Mtime     :   2026-07-29
# Docs      :   https://pigsty.io/docs/conf
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# Use the first 8 nodes from `vagrant/spec/deci.rb`:
#
#  node  address      vagrant name  modules
#  1     10.10.10.10  meta-0        infra(repo,docker), minio-1, pg-meta-1
#  2     10.10.10.11  meta-1        infra(docker),      minio-2, pg-meta-2
#  3     10.10.10.12  meta-2        infra(docker),      minio-3, pg-meta-3
#  4     10.10.10.13  node-3        etcd-1, minio-4, pg-test-1
#  5     10.10.10.14  node-4        etcd-2, minio-5, pg-test-2
#  6     10.10.10.15  node-5        etcd-3, minio-6, pg-test-3
#  7     10.10.10.16  node-6        etcd-4, minio-7, pg-test-4
#  8     10.10.10.17  node-7        etcd-5, minio-8, pg-test-5 (offline)
#
# Nodes 10.10.10.18 and 10.10.10.19 from the deci template are unused.

all:

  #============================================================#
  # Clusters, Nodes, and Modules
  #============================================================#
  children:

    # 3-node infra cluster; only node 1 builds and serves the repo
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1, repo_enabled: true }
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars:
        docker_enabled: true          # install with ./docker.yml -l infra

    # 5-node etcd cluster, co-located with pg-test
    etcd:
      hosts:
        10.10.10.13: { etcd_seq: 1 }
        10.10.10.14: { etcd_seq: 2 }
        10.10.10.15: { etcd_seq: 3 }
        10.10.10.16: { etcd_seq: 4 }
        10.10.10.17: { etcd_seq: 5 }
      vars:
        etcd_cluster: etcd

    # 8-node single-drive MinIO cluster, spanning all nodes
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1, vip_role: master }
        10.10.10.11: { minio_seq: 2 }
        10.10.10.12: { minio_seq: 3 }
        10.10.10.13: { minio_seq: 4 }
        10.10.10.14: { minio_seq: 5 }
        10.10.10.15: { minio_seq: 6 }
        10.10.10.16: { minio_seq: 7 }
        10.10.10.17: { minio_seq: 8 }
      vars:
        minio_cluster: minio
        minio_data: /data/minio       # 8 nodes x 1 disk
        minio_users:
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

        # HA MinIO endpoint: https://sss.pigsty:9002
        vip_enabled: true
        vip_vrid: 128
        vip_address: 10.10.10.9
        haproxy_services:
          - name: minio
            port: 9002
            balance: leastconn
            options:
              - option httpchk
              - option http-keep-alive
              - http-check send meth OPTIONS uri /minio/health/live
              - http-check expect status 200
            servers:
              - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-5 ,ip: 10.10.10.14 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-6 ,ip: 10.10.10.15 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-7 ,ip: 10.10.10.16 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-8 ,ip: 10.10.10.17 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

    # 3-node PostgreSQL meta cluster, co-located with infra
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica }
        10.10.10.12: { pg_seq: 3, pg_role: replica }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] }
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24
        pg_crontab:
          - '00 01 * * * /pg/bin/pg-backup full'

    # 5-node PostgreSQL test cluster; node 8 is the offline instance
    pg-test:
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
        10.10.10.15: { pg_seq: 3, pg_role: replica }
        10.10.10.16: { pg_seq: 4, pg_role: replica }
        10.10.10.17: { pg_seq: 5, pg_role: offline }
      vars:
        pg_cluster: pg-test
        pg_users:
          - { name: test ,password: test ,pgbouncer: true ,roles: [ dbrole_admin ] }
        pg_databases:
          - { name: test }
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_crontab:
          - '00 01 * * 1 /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'

  #============================================================#
  # Global Parameters
  #============================================================#
  vars:
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default
    node_tune: oltp
    pg_conf: oltp.yml

    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:
      # https_proxy:
      # all_proxy:

    infra_portal:
      home:  { domain: i.pigsty }
      minio: { domain: m.pigsty ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }

    # Node 1 serves the local repository; every node installs from it
    repo_remove: true
    node_repo_remove: true
    node_repo_modules: local
    repo_extra_packages: [ pg18-main ]
    pg_version: 18

    # MinIO VIP and pgBackRest object-storage repository
    minio_endpoint: https://sss.pigsty:9002
    node_etc_hosts:
      - '${admin_ip} i.pigsty'
      - '10.10.10.9 sss.pigsty'
    pgbackrest_method: minio
    pgbackrest_repo:
      local:
        path: /pg/backup
        retention_full_type: count
        retention_full: 2
      minio:
        type: s3
        s3_endpoint: sss.pigsty
        s3_region: us-east-1
        s3_bucket: pgsql
        s3_key: pgbackrest
        s3_key_secret: S3User.Backup
        s3_uri_style: path
        path: /pgbackrest
        storage_port: 9002
        storage_ca_file: /etc/pki/ca.crt
        block: y
        bundle: y
        bundle_limit: 20MiB
        bundle_size: 128MiB
        cipher_type: aes-256-cbc
        cipher_pass: pgBackRest
        retention_full_type: time
        retention_full: 14

    # Default credentials for this disposable sample
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

...

Explanation

  • The three INFRA nodes and five etcd nodes are separate sets. The pg-meta and pg-test PostgreSQL clusters are co-located with those two sets respectively.
  • Object storage spans all eight nodes and exposes sss.pigsty through Keepalived VIP 10.10.10.9 and HAProxy port 9002. Silo is the current default engine, while the module and variables retain minio_* compatibility names.
  • pg-meta takes one full backup daily. pg-test takes a weekly full backup and incremental backups on the remaining days; both write to the encrypted S3 pgBackRest repository.
  • The two INFRA replicas with repo_enabled: false do not build local repositories. Every node still installs packages from the first node’s local repository.
  • The database, Grafana, Patroni, HAProxy, Silo, and etcd passwords at the end of the template are suitable only for a disposable simulation and must all be rotated in real environments.

For a conventional minimal HA deployment, prefer ha/trio. For a larger full-scenario simulation, see ha/simu.

7.21 - ha/full

Four-node complete feature demonstration environment with two PostgreSQL clusters, Silo, Redis, etc.

The ha/full configuration template is Pigsty’s recommended sandbox demonstration environment, deploying two PostgreSQL clusters across four nodes for testing and demonstrating various Pigsty capabilities.

Most Pigsty tutorials and examples are based on this template’s sandbox environment.


Overview

  • Config Name: ha/full
  • Node Count: Four nodes
  • Description: Four-node complete feature demonstration environment with two PostgreSQL clusters, Silo, Redis, etc.
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: ha/trio, ha/safe, demo/demo

Usage:

./configure -c ha/full [-i <primary_ip>]

After configuration, modify the IP addresses of the other three nodes.


Content

Source: pigsty/conf/ha/full.yml

---
#==============================================================#
# File      :   full.yml
# Desc      :   Pigsty Local Sandbox 4-node Demo Config
# Ctime     :   2020-05-22
# Mtime     :   2026-01-16
# Docs      :   https://pigsty.io/docs/conf/full
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    # infra: monitor, alert, repo, etc..
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        docker_enabled: true      # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        #repo_extra_packages: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    # etcd cluster for HA postgres DCS
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd

    # minio (single node, used as backup repo)
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    # postgres cluster: pg-meta
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta     ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] }
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24


    # pgsql 3 node ha cluster: pg-test
    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
        10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
        10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
      vars:
        pg_cluster: pg-test           # define pgsql cluster name
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: test }]
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'

    #----------------------------------#
    # redis ms, sentinel, native cluster
    #----------------------------------#
    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
      #minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------#
    # MinIO Related Options
    #----------------------------------#
    node_etc_hosts: [ '${admin_ip} i.pigsty sss.pigsty' ]
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl ,pg18-olap]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/full template is Pigsty’s complete feature demonstration configuration, showcasing the collaboration of various components.

Components Overview:

ComponentNode DistributionDescription
INFRANode 1Monitoring/Alerting/Nginx/DNS
ETCDNode 1DCS Service
SiloNode 1S3-compatible Storage
pg-metaNode 1Single-node PostgreSQL
pg-testNodes 2-4Three-node HA PostgreSQL
redis-msNode 1Redis Primary-Replica Mode
redis-metaNode 2Redis Sentinel Mode
redis-testNodes 3-4Redis Native Cluster Mode

Use Cases:

  • Pigsty feature demonstration and learning
  • Development testing environments
  • Evaluating HA architecture
  • Comparing different Redis modes

Differences from ha/trio:

  • Added second PostgreSQL cluster (pg-test)
  • Added three Redis cluster mode examples
  • Infrastructure uses single node (instead of three nodes)

Notes:

  • This template is mainly for demonstration and testing; for production, refer to ha/trio or ha/safe
  • MINIO object-storage backup is enabled by default. The current source defaults to Silo; comment out the related configuration if it is not needed

7.22 - ha/safe

Three-node high-availability and security-hardening configuration example.

ha/safe uses a three-node high-availability topology to demonstrate TLS, client certificates, password checks, backup encryption, the CRIT parameter template, and related security settings. It is a configuration example to customize, not a compliance-certified template.


Overview

  • Configuration: ha/safe
  • Nodes: 3 INFRA, etcd, and PostgreSQL nodes; optional delayed replica
  • Operating systems: el8, el9, el10, d12, d13, u22, u24, u26
  • Architecture: x86_64; some security extensions do not have ARM64 packages
  • Related configurations: ha/trio, ha/full

Generate the configuration:

./configure -c ha/safe -g [-i <primary_ip>]

-g randomizes only credentials recognized by the configuration wizard. You must still replace Silo users, the pgBackRest cipher_pass, and other template example values.


Hardening Controls

SettingTemplate BehaviorBoundary and Follow-up
PostgreSQL HBAMain TCP rules use ssl; public administrator access uses certLocal ident and selected localhost pwd rules remain
PgBouncerpgbouncer_sslmode: requireClients must still verify the server certificate where required
PatroniREST API uses HTTPS and a constrained listen addressBasic Auth remains; rotate the password
Password checkpasswordcheck is preloaded through pg_libsAffects only newly set or changed passwords
Account lifetimeBuilt-in and example application users set expire_in: 7300Twenty years is not a rotation policy; shorten it to organizational requirements
Listen addressesPostgreSQL is limited to ${ip},${vip},${lo}Firewalls and HBA are still required
BackupUses Silo with AES-256-CBCpgBR.${pg_cluster} is a predictable example and must be replaced
PostgreSQL parameterspg-meta uses crit.ymlStrict synchronous mode can block writes without a synchronous replica
LoggingCRIT logs connection and disconnection eventsFine-grained SQL auditing requires explicit pgaudit configuration
Security extensionsInstalls passwordcheck, credcheck, pgaudit, and related packagesInstallation does not preload, create, or configure an extension
Delayed replicaProvides a commented one-hour delayed-cluster exampleNot created by default; enable it explicitly

Preflight Checklist

  • Replace every public example credential, especially minio_users, pgbackrest_repo, application users, and API passwords.
  • Confirm that the three nodes occupy independent failure domains, and update IPs, VIP, and domains for the target network.
  • Configure database clients with sslmode=verify-full and a trusted CA.
  • Confirm that the availability impact of strict synchronous mode meets application requirements.
  • Preload and configure pgaudit, credcheck, and other extensions as required.
  • Check extension package availability on ARM64.
  • Test backup recovery, failover, and certificate verification.

See Security Model, Authentication, Encrypted Communication, and Data Security for the underlying mechanisms.


Configuration

Source: pigsty/conf/ha/safe.yml

---
#==============================================================#
# File      :   safe.yml
# Desc      :   Pigsty 3-node security enhance template
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf/safe
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


#===== SECURITY ENHANCEMENT CONFIG TEMPLATE WITH 3 NODES ======#
#   * 3 infra nodes, 3 etcd nodes, single minio node
#   * 3-instance pgsql cluster with an extra delayed instance
#   * crit.yml templates, no data loss, checksum enforced
#   * enforce ssl on postgres & pgbouncer, use postgres by default
#   * enforce an expiration date for all users (20 years by default)
#   * enforce strong password policy with passwordcheck extension
#   * enforce changing default password for all users
#   * log connections and disconnections
#   * restrict listen ip address for postgres/patroni/pgbouncer


all:
  children:

    infra: # infra cluster for proxy, monitor, alert, etc
      hosts: # 1 for common usage, 3 nodes for production
        10.10.10.10: { infra_seq: 1 } # identity required
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars: { patroni_watchdog_mode: 'off' }

    minio: # minio cluster, s3 compatible object storage
      hosts: { 10.10.10.10: { minio_seq: 1 } }
      vars: { minio_cluster: minio }

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        10.10.10.12: { etcd_seq: 3 }  # three-member cluster keeps an odd voter count
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd
        etcd_safeguard: false # safeguard against purging

    pg-meta: # 3 instance postgres cluster `pg-meta`
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica }
        10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
      vars:
        pg_cluster: pg-meta
        pg_conf: crit.yml
        pg_users:
          - { name: dbuser_meta , password: Pleas3-ChangeThisPwd ,expire_in: 7300 ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view , password: Make.3ure-Compl1ance  ,expire_in: 7300 ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector } ] }
        pg_services:
          - { name: standby , ip: "*" ,port: 5435 , dest: default ,selector: "[]" , backup: "[? pg_role == `primary`]" }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'
        pg_listen: '${ip},${vip},${lo}'
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24

    # OPTIONAL delayed cluster for pg-meta
    #pg-meta-delay: # delayed instance for pg-meta (1 hour ago)
    #  hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.10, pg_delay: 1h } }
    #  vars: { pg_cluster: pg-meta-delay }


  ####################################################################
  #                          Parameters                              #
  ####################################################################
  vars: # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
    patroni_ssl_enabled: true         # secure patroni RestAPI communications with SSL?
    pgbouncer_sslmode: require        # pgbouncer client ssl mode: disable|allow|prefer|require|verify-ca|verify-full, disable by default
    pg_default_service_dest: postgres # default service destination to postgres instead of pgbouncer
    pgbackrest_method: minio          # pgbackrest repo method: local,minio,[user-defined...]

    #----------------------------------#
    # MinIO Related Options
    #----------------------------------#
    minio_users: # and configure `pgbackrest_repo` & `minio_users` accordingly
      - { access_key: dba , secret_key: S3User.DBA.Strong.Password, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: Min10.bAckup ,policy: readwrite }
    pgbackrest_repo: # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local: # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio: # optional minio repo for pgbackrest
        s3_key: pgbackrest            # <-------- CHANGE THIS, SAME AS `minio_users` access_key
        s3_key_secret: Min10.bAckup   # <-------- CHANGE THIS, SAME AS `minio_users` secret_key
        cipher_pass: 'pgBR.${pg_cluster}'  # <-------- CHANGE THIS, you can use cluster name as part of password
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days


    #----------------------------------#
    # Access Control
    #----------------------------------#
    # add passwordcheck_cracklib extension to enforce strong password policy
    pg_libs: '$libdir/passwordcheck_cracklib, pg_stat_statements, auto_explain'
    pg_extensions:
      - passwordcheck_cracklib, supautils, pgsodium, pg_vault, pg_session_jwt, pg_anon, pgsmcrypto, pgauditlogtofile, pgaudit #, pgaudit17, pgaudit16, pgaudit15, pgaudit14
      - pg_auth_mon, credcheck, pgcryptokey, pg_jobmon, logerrors, login_hook, set_user, pgextwlist, pg_auditor, sslutils, pg_noset #pg_tde #pg_snakeoil
    pg_default_roles: # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [ dbrole_readonly ]               ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [ pg_monitor, dbrole_readwrite ]  ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,expire_in: 7300                        ,comment: system superuser }
      - { name: replicator ,replication: true  ,expire_in: 7300 ,roles: [ pg_monitor, dbrole_readonly ]   ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,expire_in: 7300 ,roles: [ dbrole_admin ]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [ pg_monitor ] ,expire_in: 7300 ,pgbouncer: true ,parameters: { log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_hba_rules: # postgres host-based auth rules by default, order by `order`
      - { user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'   ,order: 100}
      - { user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident'  ,order: 150}
      - { user: '${repl}'    ,db: replication ,addr: localhost ,auth: ssl   ,title: 'replicator replication from localhost' ,order: 200}
      - { user: '${repl}'    ,db: replication ,addr: intra     ,auth: ssl   ,title: 'replicator replication from intranet'  ,order: 250}
      - { user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: ssl   ,title: 'replicator postgres db from intranet'  ,order: 300}
      - { user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password'  ,order: 350}
      - { user: '${monitor}' ,db: all         ,addr: infra     ,auth: ssl   ,title: 'monitor from infra host with password' ,order: 400}
      - { user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'    ,order: 450}
      - { user: '${admin}'   ,db: all         ,addr: world     ,auth: cert  ,title: 'admin @ everywhere with ssl & cert'    ,order: 500}
      - { user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: ssl   ,title: 'pgbouncer read/write via local socket' ,order: 550}
      - { user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: ssl   ,title: 'read/write biz user via password'      ,order: 600}
      - { user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: ssl   ,title: 'allow etl offline tasks from intranet' ,order: 650}
    pgb_default_hba_rules: # pgbouncer host-based authentication rules, order by `order`
      - { user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident' ,order: 100}
      - { user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd'  ,order: 150}
      - { user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: ssl   ,title: 'monitor access via intranet with pwd'  ,order: 200}
      - { user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr'  ,order: 250}
      - { user: '${admin}'   ,db: all         ,addr: intra     ,auth: ssl   ,title: 'admin access via intranet with pwd'    ,order: 300}
      - { user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'    ,order: 350}
      - { user: 'all'        ,db: all         ,addr: intra     ,auth: ssl   ,title: 'allow all user intra access with pwd'  ,order: 400}

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    #node_selinux_mode: enforcing     # set selinux mode: enforcing,permissive,disabled
    node_firewall_mode: zone          # firewall mode: zone (default), off (disable), none (skip & self-managed)
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    #grafana_admin_username: admin
    grafana_admin_password: You.Have2Use-A_VeryStrongPassword
    grafana_view_password: DBUser.Viewer
    #pg_admin_username: dbuser_dba
    pg_admin_password: PessWorb.Should8eStrong-eNough
    #pg_monitor_username: dbuser_monitor
    pg_monitor_password: MekeSuerYour.PassWordI5secured
    #pg_replication_username: replicator
    pg_replication_password: doNotUseThis-PasswordFor.AnythingElse
    #patroni_username: postgres
    patroni_password: don.t-forget-to-change-thEs3-password
    #haproxy_admin_username: admin
    haproxy_admin_password: GneratePasswordWith-pwgen-s-16-1
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

7.23 - ha/trio

Three-node standard HA configuration where PostgreSQL, ETCD, and Silo tolerate one node failure

Three nodes is the minimum scale for majority-based high availability. The ha/trio template distributes INFRA, ETCD, PGSQL, and Silo across three servers. PostgreSQL, ETCD, and object storage continue serving when one server is unavailable.


Overview

  • Config Name: ha/trio
  • Node Count: Three nodes
  • Description: Three-node standard HA architecture with a three-node, single-drive Silo cluster and one HA S3 endpoint
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: ha/dual, ha/full, ha/safe

Usage:

./configure -c ha/trio [-i <primary_ip>]

After configuration, modify placeholder IPs 10.10.10.11 and 10.10.10.12 to actual node IP addresses.


Content

Source: pigsty/conf/ha/trio.yml

---
#==============================================================#
# File      :   trio.yml
# Desc      :   Pigsty 3-node security enhance template
# Ctime     :   2020-05-23
# Mtime     :   2026-08-14
# Docs      :   https://pigsty.io/docs/conf/trio
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# 3 infra node, 3 etcd node, 3 pgsql node, and 3 minio nodes
all:  # top level object
  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:
    #----------------------------------#
    # infra: monitor, alert, repo, etc..
    #----------------------------------#
    infra: # infra cluster for proxy, monitor, alert, etc
      hosts: # 1 for common usage, 3 nodes for production
        10.10.10.10: { infra_seq: 1 } # identity required
        10.10.10.11: { infra_seq: 2, repo_enabled: false }
        10.10.10.12: { infra_seq: 3, repo_enabled: false }
      vars:
        patroni_watchdog_mode: 'off' # do not fencing infra

    etcd: # dcs service for postgres/patroni ha consensus
      hosts: # 1 node for testing, 3 or 5 for production
        10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
        10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
        10.10.10.12: { etcd_seq: 3 }  # three-member cluster keeps an odd voter count
      vars: # cluster level parameter override roles/etcd
        etcd_cluster: etcd  # mark etcd cluster name etcd
        etcd_safeguard: false # safeguard against purging

    # compact 3-node x 1-drive Silo cluster: EC:1, tolerates one node failure
    # use a dedicated local mount for /data/minio; do not expand a 1-node cluster in place
    minio: # minio cluster, s3 compatible object storage
      hosts:
        10.10.10.10: { minio_seq: 1, vip_role: master }
        10.10.10.11: { minio_seq: 2 }
        10.10.10.12: { minio_seq: 3 }
      vars:
        minio_cluster: minio
        minio_data: /data/minio
        minio_users:
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }
        vip_enabled: true
        vip_vrid: 128
        vip_address: 10.10.10.9
        haproxy_services:
          - name: minio
            port: 9002
            balance: leastconn
            options:
              - option httpchk
              - option http-keep-alive
              - http-check send meth OPTIONS uri /minio/health/live
              - http-check expect status 200
            servers:
              - { name: minio-1, ip: 10.10.10.10, port: 9000, options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-2, ip: 10.10.10.11, port: 9000, options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-3, ip: 10.10.10.12, port: 9000, options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

    pg-meta:  # 3 instance postgres cluster `pg-meta`
      hosts:  # pg-meta-3 is marked as offline readable replica
        10.10.10.10: { pg_seq: 1, pg_role: primary }
        10.10.10.11: { pg_seq: 2, pg_role: replica }
        10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
      vars:   # cluster level parameters
        pg_cluster: pg-meta
        pg_users: # https://pigsty.io/docs/pgsql/config/user
          - { name: dbuser_meta , password: DBUser.Meta ,pgbouncer: true   ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view , password: DBUser.Viewer ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector } ] }
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:
    #----------------------------------#
    # Meta Data
    #----------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      minio        : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------#
    # MinIO Related Options
    #----------------------------------#
    minio_endpoint: https://sss.pigsty:9002
    node_etc_hosts:
      - '${admin_ip} i.pigsty'        # static dns record that point to repo node
      - '10.10.10.9 sss.pigsty'       # static dns record that point to minio vip
    pgbackrest_method: minio          # if you want to use minio as backup repo instead of 'local' fs, uncomment this
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9002            # minio ha endpoint exposed by haproxy
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

...

Explanation

The ha/trio template is Pigsty’s standard HA configuration, providing true automatic failover capability.

Architecture:

  • Three-node INFRA: Distributed deployment of VictoriaMetrics/Grafana/Nginx
  • Three-node ETCD: DCS majority election, tolerates single-point failure
  • Three-node PostgreSQL: One primary, two replicas, automatic failover
  • Three-node Silo: One data path per node, using EC:1 by default (two data shards and one parity shard)
  • HA S3 endpoint: Keepalived VIP 10.10.10.9 with HAProxy listening on 9002 on all three nodes

HA Guarantees:

  • Three-node ETCD tolerates one node failure, maintains majority
  • PostgreSQL primary failure triggers automatic Patroni election for new primary
  • L2 VIP follows primary, applications don’t need to modify connection config
  • Silo retains read and write quorum while one node or one data drive is unavailable
  • sss.pigsty resolves to the object-storage VIP; pgBackRest and mcli use https://sss.pigsty:9002

Object Storage:

  • minio_data: /data/minio is a filesystem directory, not a raw device such as /dev/sdb.
  • Distributed Silo rejects data paths on the root filesystem. /data/minio must reside on a separately mounted /data filesystem or be a mount point itself.
  • The backing storage may be a local disk, cloud volume, separate partition, or LVM logical volume. For production, prefer dedicated persistent drives of similar capacity on all three nodes.
  • Use findmnt -T /data/minio to inspect the actual mount. A result that still points to / means the path is only a directory on the root drive.
  • The three-node, single-drive topology provides about two-thirds raw capacity efficiency. It is compact HA; use a multi-node, multi-drive topology for greater capacity, throughput, and drive redundancy.
  • A single-node object-storage pool cannot be converted in place by adding two members. Create a new three-node cluster and migrate the objects instead.

The template’s S3 API endpoint is highly available. The Portal administration UI still connects to port 9001 on the first node and is outside this API HA path.

Use Cases:

  • Minimum HA deployment for production environments
  • Critical business requiring automatic failover
  • Foundation architecture for larger scale deployments

Extension Suggestions:

  • For stronger data security, refer to ha/safe template
  • For more demo features, refer to ha/full template
  • Use a multi-drive Silo cluster when object-storage capacity or performance requirements are higher

7.24 - ha/dual

Two-node configuration, limited HA deployment tolerating specific server failure

The ha/dual template uses two-node deployment, implementing a “semi-HA” architecture with one primary and one standby. If you only have two servers, this is a pragmatic choice.


Overview

  • Config Name: ha/dual
  • Node Count: Two nodes
  • Description: Two-node limited HA deployment, tolerates specific server failure
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: ha/trio, slim

Usage:

./configure -c ha/dual [-i <primary_ip>]

After configuration, modify placeholder IP 10.10.10.11 to actual standby node IP address.


Content

Source: pigsty/conf/ha/dual.yml

---
#==============================================================#
# File      :   dual.yml
# Desc      :   Pigsty deployment example for two nodes
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf/dual
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


# It is recommended to use at least three nodes in production deployment.
# But sometimes, there are only two nodes available, that's dual.yml for
#
# In this setup, we have two nodes, .10 (admin_node) and .11 (pgsql_primary):
#
# If .11 is down, .10 will take over since the dcs:etcd is still alive
# If .10 is down, .11 (pgsql primary) will still be functioning as a primary if:
#   - Only dcs:etcd is down
#   - Only pgsql is down
# if both etcd & pgsql are down (e.g. node down), the primary will still demote itself.


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, optional backup repo for pgbackrest
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # postgres cluster 'pg-meta' with single primary instance
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: replica }
        10.10.10.11: { pg_seq: 2, pg_role: primary }  # <----- use this as primary by default
      vars:
        pg_cluster: pg-meta
        pg_databases: [ { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [ pigsty ] ,extensions: [ { name: vector }] } ]
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [ dbrole_admin ]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [ dbrole_readonly ] ,comment: read-only viewer for meta database }
        pg_hba_rules:   # https://pigsty.io/docs/pgsql/config/hba
          - { user: all ,db: all ,addr: intra ,auth: pwd ,title: 'everyone intranet access with password' ,order: 800 }
        pg_crontab:     # https://pigsty.io/docs/pgsql/admin/crontab
          - '00 01 * * * /pg/bin/pg-backup full'
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24

  vars:                               # global parameters
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
    infra_portal:                     # domain names and upstream servers
      home   : { domain: i.pigsty }
      #minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg18-main ] #,pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The ha/dual template is Pigsty’s two-node limited HA configuration, designed for scenarios with only two servers.

Architecture:

  • Node A (10.10.10.10): Admin node, runs Infra + etcd + PostgreSQL replica
  • Node B (10.10.10.11): Data node, runs PostgreSQL primary only

Failure Scenario Analysis:

Failed NodeImpactAuto Recovery
Node B downPrimary switches to Node AAuto
Node A etcd downPrimary continues running (no DCS)Manual
Node A pgsql downPrimary continues runningManual
Node A complete failurePrimary degrades to standaloneManual

Use Cases:

  • Budget-limited environments with only two servers
  • Acceptable that some failure scenarios need manual intervention
  • Transitional solution before upgrading to three-node HA

Notes:

  • True HA requires at least three nodes (DCS needs majority)
  • Recommend upgrading to three-node architecture as soon as possible
  • L2 VIP requires network environment support (same broadcast domain)

7.25 - ha/citus

13-node Citus distributed PostgreSQL cluster, 1 coordinator + 5 worker groups with HA

The ha/citus template deploys a complete Citus distributed PostgreSQL cluster with 1 infra node, 1 coordinator group, and 5 worker groups (12 Citus nodes total), providing transparent horizontal scaling and data sharding.


Overview

  • Config Name: ha/citus
  • Node Count: 13 nodes (1 infra + 1 coordinator×2 + 5 workers×2)
  • Description: Citus distributed PostgreSQL HA cluster
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64
  • Related: meta, ha/trio

Usage:

./configure -c ha/citus

Note: 13-node template, modify IP addresses after generation


Content

Source: pigsty/conf/ha/citus.yml

---
#==============================================================#
# File      :   citus.yml
# Desc      :   13-node Citus (6-group Distributive) Config Template
# Ctime     :   2020-05-22
# Mtime     :   2025-01-20
# Docs      :   https://pigsty.io/docs/conf/citus
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# This is the config template for Citus Distributive Cluster
# tutorial: https://pigsty.io/docs/pgsql/kernel/citus
# we will use the local repo for cluster bootstrapping
#
# Topology:
#   - pg-citus0: coordinator (10.10.10.10)         VIP: 10.10.10.19
#   - pg-citus1: worker group 1 (10.10.10.21, 22)  VIP: 10.10.10.29
#   - pg-citus2: worker group 2 (10.10.10.31, 32)  VIP: 10.10.10.39
#   - pg-citus3: worker group 3 (10.10.10.41, 42)  VIP: 10.10.10.49
#   - pg-citus4: worker group 4 (10.10.10.51, 52)  VIP: 10.10.10.59
#   - pg-citus5: worker group 5 (10.10.10.61, 62)  VIP: 10.10.10.69
#   - pg-citus6: worker group 6 (10.10.10.71, 72)  VIP: 10.10.10.79
#
# Usage:
#   curl https://repo.pigsty.io/get | bash
#   ./configure -c citus
#   ./deploy.yml

all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 }}}
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1  }}, vars: { etcd_cluster: etcd }}
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: "pigsty meta database"
            schemas: [pigsty]
            extensions: [ postgis, vector ]
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every day 1am

    #----------------------------------------------------------#
    # pg-citus: 6 cluster groups, 12 nodes total
    #----------------------------------------------------------#
    pg-citus:
      hosts:

        # coordinator (group 0) on infra node
        10.10.10.21: { pg_group: 0, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.29/24 ,pg_seq: 1, pg_role: primary }
        10.10.10.22: { pg_group: 0, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.29/24 ,pg_seq: 2, pg_role: replica }

        # worker group 2
        10.10.10.31: { pg_group: 1, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.39/24 ,pg_seq: 1, pg_role: primary }
        10.10.10.32: { pg_group: 1, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.39/24 ,pg_seq: 2, pg_role: replica }

        # worker group 3
        10.10.10.41: { pg_group: 2, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.49/24 ,pg_seq: 1, pg_role: primary }
        10.10.10.42: { pg_group: 2, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.49/24 ,pg_seq: 2, pg_role: replica }

        # worker group 4
        10.10.10.51: { pg_group: 3, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.59/24 ,pg_seq: 1, pg_role: primary }
        10.10.10.52: { pg_group: 3, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.59/24 ,pg_seq: 2, pg_role: replica }

        # worker group 5
        10.10.10.61: { pg_group: 4, pg_cluster: pg-citus5 ,pg_vip_address: 10.10.10.69/24 ,pg_seq: 1, pg_role: primary }
        10.10.10.62: { pg_group: 4, pg_cluster: pg-citus5 ,pg_vip_address: 10.10.10.69/24 ,pg_seq: 2, pg_role: replica }

        # worker group 6
        10.10.10.71: { pg_group: 5, pg_cluster: pg-citus6 ,pg_vip_address: 10.10.10.79/24 ,pg_seq: 1, pg_role: primary }
        10.10.10.72: { pg_group: 5, pg_cluster: pg-citus6 ,pg_vip_address: 10.10.10.79/24 ,pg_seq: 2, pg_role: replica }

      vars:
        pg_mode: citus                            # pgsql cluster mode: citus
        pg_shard: pg-citus                        # citus shard name: pg-citus
        pg_primary_db: citus                      # primary database used by citus
        pg_dbsu_password: DBUser.Postgres         # enable dbsu password access for citus
        pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]
        pg_libs: 'citus, pg_cron, pg_stat_statements'
        pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ] }]
        pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
        pg_parameters:
          cron.database_name: citus
          citus.node_conninfo: 'sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
        pg_hba_rules:
          - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl ,title: 'all user ssl access from localhost' }
          - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl ,title: 'all user ssl access from intranet'  }
        pg_vip_enabled: true
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every day 1am

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default
    infra_portal:
      home : { domain: i.pigsty }

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: true
    node_repo_modules: node,infra,pgsql
    node_tune: oltp

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18  # PostgreSQL 14-18
    pg_conf: oltp.yml
    pg_packages: [ pgsql-main, pgsql-common ]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Topology

ClusterNodesIP AddressesVIPRole
pg-meta110.10.10.10-Infra + CMDB
pg-citus1210.10.10.21, 2210.10.10.29Coordinator (group 0)
pg-citus2210.10.10.31, 3210.10.10.39Worker (group 1)
pg-citus3210.10.10.41, 4210.10.10.49Worker (group 2)
pg-citus4210.10.10.51, 5210.10.10.59Worker (group 3)
pg-citus5210.10.10.61, 6210.10.10.69Worker (group 4)
pg-citus6210.10.10.71, 7210.10.10.79Worker (group 5)

Architecture:

  • pg-meta: Infra node running Grafana, VictoriaMetrics, etcd, plus a standalone CMDB
  • pg-citus1: Coordinator (group 0), receives queries and routes to workers, 1 primary + 1 replica
  • pg-citus2~6: Workers (group 1~5), store sharded data, each with 1 primary + 1 replica via Patroni
  • VIP: Each group has L2 VIP managed by vip-manager for transparent failover

Explanation

The ha/citus template deploys production-grade Citus cluster for large-scale horizontal scaling scenarios.

Key Features:

  • Horizontal Scaling: 5 worker groups for linear storage/compute scaling
  • High Availability: Each group with 1 primary + 1 replica, auto-failover
  • L2 VIP: Virtual IP per group, transparent failover to clients
  • SSL Encryption: Inter-node communication uses SSL certificates
  • Transparent Sharding: Data auto-distributed across workers

Pre-installed Extensions:

pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]
pg_libs: 'citus, pg_cron, pg_stat_statements'

Security:

  • pg_dbsu_password enabled for Citus inter-node communication
  • HBA rules require SSL authentication
  • Inter-node uses certificate verification: sslmode=verify-full

Deployment

# 1. Download Pigsty
curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty

# 2. Use ha/citus template
./configure -c ha/citus

# 3. Modify IPs and passwords
vi pigsty.yml

# 4. Deploy entire cluster
./deploy.yml

Verify after deployment:

-- Connect to coordinator
psql -h 10.10.10.29 -U dbuser_citus -d citus

-- Check worker nodes
SELECT * FROM citus_get_active_worker_nodes();

-- Check shard distribution
SELECT * FROM citus_shards;

Examples

Create Distributed Table:

-- Create table
CREATE TABLE events (
    tenant_id INT,
    event_id BIGSERIAL,
    event_time TIMESTAMPTZ DEFAULT now(),
    payload JSONB,
    PRIMARY KEY (tenant_id, event_id)
);

-- Distribute by tenant_id
SELECT create_distributed_table('events', 'tenant_id');

-- Insert (auto-routed to correct shard)
INSERT INTO events (tenant_id, payload)
VALUES (1, '{"type": "click"}');

-- Query (parallel execution)
SELECT tenant_id, count(*)
FROM events
GROUP BY tenant_id;

Create Reference Table (replicated to all nodes):

CREATE TABLE tenants (
    tenant_id INT PRIMARY KEY,
    name TEXT
);

SELECT create_reference_table('tenants');

Use Cases

  • Multi-tenant SaaS: Shard by tenant_id for data isolation and parallel queries
  • Real-time Analytics: Large-scale event data aggregation
  • Timeseries Data: Combine with TimescaleDB for massive timeseries
  • Horizontal Scaling: When single-table data exceeds single-node capacity

Notes

  • PostgreSQL Version: Citus supports PG 14~18, this template defaults to PG18
  • Distribution Column: Choose wisely (typically tenant_id or timestamp), critical for performance
  • Cross-shard Limits: Foreign keys must include distribution column, some DDL restrictions
  • Network: pg_vip_interface defaults to auto; specify an interface explicitly for unusual network environments
  • Architecture: Citus extension does not support ARM64

7.26 - supabase

Self-host Supabase using Pigsty-managed PostgreSQL, an open-source Firebase alternative

The supabase configuration template provides a reference configuration for self-hosting Supabase, using Pigsty-managed PostgreSQL as the underlying storage.

For more details, see Supabase Self-Hosting Tutorial


Overview

  • Config Name: supabase
  • Node Count: Single node
  • Description: Self-host Supabase using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, d12, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • PostgreSQL: 15, 16, 17, 18 (template default: 18)
  • Related: meta, rich

Usage:

./configure -c supabase [-i <primary_ip>]

Content

Source: pigsty/conf/supabase.yml

---
#==============================================================#
# File      :   supabase.yml
# Desc      :   Pigsty configuration for self-hosting supabase
# Ctime     :   2023-09-19
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/conf/supabase
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# supabase is available on el8/el9/u22/u24/u26/d12 with pg15,16,17,18
# tutorial: https://pigsty.io/docs/app/supabase
# Usage:
#   curl https://repo.pigsty.io/get | bash    # install pigsty
#   ./configure -c supabase   # use this supabase conf template
#   ./deploy.yml              # install pigsty & pgsql & minio
#   ./docker.yml              # install docker & docker compose
#   ./app.yml                 # launch supabase with docker compose

all:
  children:


    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        repo_enabled: false    # disable local repo

    #----------------------------------------------#
    # ETCD : https://pigsty.io/docs/etcd
    #----------------------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd
        etcd_safeguard: false  # enable to prevent purging running etcd instance

    #----------------------------------------------#
    # MINIO : https://pigsty.io/docs/minio
    #----------------------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------------------#
    # PostgreSQL cluster for Supabase self-hosting
    #----------------------------------------------#
    pg-meta:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-meta
        pg_users:
          # supabase roles: anon, authenticated, dashboard_user
          - { name: anon           ,login: false }
          - { name: authenticated  ,login: false }
          - { name: dashboard_user ,login: false ,replication: true ,createdb: true ,createrole: true }
          - { name: service_role   ,login: false ,bypassrls: true }
          # supabase users: please use the same password
          - { name: supabase_admin             ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: true   ,roles: [ dbrole_admin ] ,superuser: true ,replication: true ,createdb: true ,createrole: true ,bypassrls: true }
          - { name: authenticator              ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin, authenticated ,anon ,service_role ] }
          - { name: supabase_auth_admin        ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin ] ,createrole: true }
          - { name: supabase_storage_admin     ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin, authenticated ,anon ,service_role ] ,createrole: true }
          - { name: supabase_functions_admin   ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin ] ,createrole: true }
          - { name: supabase_replication_admin ,password: 'DBUser.Supa' ,replication: true ,roles: [ dbrole_admin ]}
          - { name: supabase_etl_admin         ,password: 'DBUser.Supa' ,replication: true ,roles: [ pg_read_all_data, dbrole_readonly ]}
          - { name: supabase_read_only_user    ,password: 'DBUser.Supa' ,bypassrls: true ,roles:   [ pg_read_all_data, dbrole_readonly ]}
        pg_databases:
          - name: postgres
            baseline: supabase.sql
            owner: supabase_admin
            comment: supabase postgres database
            schemas: [ extensions ,auth ,realtime ,storage ,graphql_public ,supabase_functions ,_realtime ]
            extensions:
              - { name: pgcrypto         ,schema: extensions } # cryptographic functions
              - { name: pg_net           ,schema: extensions } # async HTTP
              - { name: pgjwt            ,schema: extensions } # json web token API for postgres
              - { name: uuid-ossp        ,schema: extensions } # generate universally unique identifiers (UUIDs)
              - { name: pgsodium         ,schema: extensions } # pgsodium is a modern cryptography library for Postgres.
              - { name: supabase_vault   ,schema: extensions } # Supabase Vault Extension
              - { name: pg_jsonschema    ,schema: extensions } # pg_jsonschema: Validate json schema
              - { name: wrappers         ,schema: extensions } # wrappers: FDW collections
              - { name: http             ,schema: extensions } # http: allows web page retrieval inside the database.
              - { name: pg_cron          ,schema: extensions } # pg_cron: Job scheduler for PostgreSQL
              - { name: timescaledb      ,schema: extensions } # timescaledb: Enables scalable inserts and complex queries for time-series data
              - { name: pg_tle           ,schema: extensions } # pg_tle: Trusted Language Extensions for PostgreSQL
              - { name: vector           ,schema: extensions } # pgvector: the vector similarity search
              - { name: pgmq             ,schema: extensions } # pgmq: A lightweight message queue like AWS SQS and RSMQ
          - name: _supabase
            owner: supabase_admin
            comment: supabase internal analytics database
            schemas: [ _analytics ]
            extensions:
              - { name: pgcrypto         ,schema: extensions } # cryptographic functions
        # supabase required extensions
        pg_libs: 'timescaledb, pgsodium, plpgsql, plpgsql_check, pg_cron, pg_net, pg_stat_statements, auto_explain, pg_wait_sampling, pg_tle, plan_filter'
        pg_extensions: [ pg18-main ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
        pg_parameters: { cron.database_name: postgres }
        pg_hba_rules: # supabase hba rules, require access from docker network
          - { user: all ,db: postgres  ,addr: intra         ,auth: pwd ,title: 'allow supabase access from intranet'    ,order: 50 }
          - { user: all ,db: postgres  ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow access from local docker network' ,order: 50 }
          - { user: all ,db: _supabase ,addr: intra         ,auth: pwd ,title: 'allow supabase internal access from intranet'    ,order: 50 }
          - { user: all ,db: _supabase ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow internal access from local docker network' ,order: 50 }
        pg_crontab:
          - '00 01 * * * /pg/bin/pg-backup full'  # make a full backup every 1am
          - '*  *  * * * /pg/bin/supa-kick'       # kick supabase _analytics lag per minute: https://github.com/pgsty/pigsty/issues/581

    #----------------------------------------------#
    # Supabase
    #----------------------------------------------#
    # ./docker.yml
    # ./app.yml

    # the supabase stateless containers (default username & password: supabase/pigsty)
    supabase:
      hosts:
        10.10.10.10: {}
      vars:
        docker_enabled: true                              # enable docker on this group
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]
        app: supabase                                     # specify app name (supa) to be installed (in the apps)
        apps:                                             # define all applications
          supabase:                                       # the definition of supabase app
            conf:                                         # override /opt/supabase/.env

              # IMPORTANT: CHANGE JWT_SECRET AND REGENERATE CREDENTIAL ACCORDING!!!!!!!!!!!
              # https://supabase.com/docs/guides/self-hosting/docker#securing-your-services
              JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
              ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
              SERVICE_ROLE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
              SUPABASE_PUBLISHABLE_KEY: ""
              SUPABASE_SECRET_KEY: ""
              JWT_KEYS: ""
              JWT_JWKS: ""
              ANON_KEY_ASYMMETRIC: ""
              SERVICE_ROLE_KEY_ASYMMETRIC: ""
              PG_META_CRYPTO_KEY: your-encryption-key-32-chars-min
              SECRET_KEY_BASE: UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
              REALTIME_DB_ENC_KEY: supabaserealtime

              DASHBOARD_USERNAME: supabase
              DASHBOARD_PASSWORD: pigsty

              # 32~64 random characters string for logflare
              LOGFLARE_PUBLIC_ACCESS_TOKEN: 1234567890abcdef1234567890abcdef
              LOGFLARE_PRIVATE_ACCESS_TOKEN: fedcba0987654321fedcba0987654321
              LOGFLARE_DB: _supabase
              LOGFLARE_SCHEMA: _analytics

              # postgres connection string (use the correct ip and port)
              POSTGRES_HOST: 10.10.10.10      # point to the local postgres node
              POSTGRES_PORT: 5436             # access via the 'default' service, which always route to the primary postgres
              POSTGRES_DB: postgres           # the supabase underlying database
              POSTGRES_PASSWORD: DBUser.Supa  # password for supabase_admin and multiple supabase users

              # expose supabase via domain name
              SITE_URL: https://supa.pigsty                 # <------- Change This to your external site URL
              API_EXTERNAL_URL: https://supa.pigsty/auth/v1 # <------- Auth service external URL, keep /auth/v1 suffix
              SUPABASE_PUBLIC_URL: https://supa.pigsty      # <------- DO NOT FORGET TO PUT IT IN infra_portal!

              # if using s3/minio as file storage
              S3_BUCKET: data
              GLOBAL_S3_BUCKET: data
              S3_ENDPOINT: https://sss.pigsty:9000
              S3_ACCESS_KEY: s3user_data
              S3_SECRET_KEY: S3User.Data
              S3_FORCE_PATH_STYLE: true
              S3_PROTOCOL: https
              S3_REGION: stub
              REGION: stub
              STORAGE_TENANT_ID: stub
              S3_PROTOCOL_ACCESS_KEY_ID: s3user_data
              S3_PROTOCOL_ACCESS_KEY_SECRET: S3User.Data
              MINIO_DOMAIN_IP: 10.10.10.10  # sss.pigsty domain name will resolve to this ip statically
              PGRST_DB_SCHEMAS: public,graphql_public
              PGRST_DB_MAX_ROWS: 1000
              PGRST_DB_EXTRA_SEARCH_PATH: public
              IMGPROXY_AUTO_WEBP: true
              FUNCTIONS_VERIFY_JWT: false
              DOCKER_SOCKET_LOCATION: /var/run/docker.sock

              # if using SMTP (optional)
              #SMTP_ADMIN_EMAIL: [email protected]
              #SMTP_HOST: supabase-mail
              #SMTP_PORT: 2500
              #SMTP_USER: fake_mail_user
              #SMTP_PASS: fake_mail_password
              #SMTP_SENDER_NAME: fake_sender
              #ENABLE_ANONYMOUS_USERS: false


  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra
    #----------------------------------------------#
    version: v4.5.0                       # pigsty version string
    admin_ip: 10.10.10.10                 # admin node ip address
    region: default                       # upstream mirror region: default|china|europe
    proxy_env:                            # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    certbot_sign: false                   # enable certbot to sign https certificate for infra portal
    certbot_email: [email protected]         # replace your email address to receive expiration notice
    infra_portal:                         # infra services exposed via portal
      home      : { domain: i.pigsty }    # default domain name
      pgadmin   : { domain: adm.pigsty ,endpoint: "${admin_ip}:8885" }
      bytebase  : { domain: ddl.pigsty ,endpoint: "${admin_ip}:8887" }
      #minio     : { domain: m.pigsty   ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      # Nginx / Domain / HTTPS : https://pigsty.io/docs/infra/admin/portal
      supa :                              # nginx server config for supabase
        domain: supa.pigsty               # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8000"      # supabase service endpoint: IP:PORT
        websocket: true                   # add websocket support
        certbot: supa.pigsty              # certbot cert name, apply with `make cert`

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    nodename_overwrite: false             # do not overwrite node hostname on single node mode
    node_tune: oltp                       # node tuning specs: oltp,olap,tiny,crit
    node_etc_hosts:                       # add static domains to all nodes /etc/hosts
      - 10.10.10.10 i.pigsty sss.pigsty supa.pigsty
    node_repo_modules: node,pgsql,infra   # use pre-made local repo rather than install from upstream
    node_repo_remove: true                # remove existing node repo for node managed by pigsty
    #node_packages: [openssh-server]      # packages to be installed current nodes with latest version
    #node_timezone: Asia/Hong_Kong        # overwrite node timezone

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                        # default postgres version
    pg_conf: oltp.yml                     # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_safeguard: false                   # prevent purging running postgres instance?
    pg_default_schemas: [ monitor, extensions ] # add new schema: extensions
    pg_default_extensions:                # default extensions to be created
      - { name: pg_stat_statements ,schema: monitor     }
      - { name: pgstattuple        ,schema: monitor     }
      - { name: pg_buffercache     ,schema: monitor     }
      - { name: pageinspect        ,schema: monitor     }
      - { name: pg_prewarm         ,schema: monitor     }
      - { name: pg_visibility      ,schema: monitor     }
      - { name: pg_freespacemap    ,schema: monitor     }
      - { name: pg_wait_sampling   ,schema: monitor     }
      # move default extensions to `extensions` schema for supabase
      - { name: postgres_fdw       ,schema: extensions  }
      - { name: file_fdw           ,schema: extensions  }
      - { name: btree_gist         ,schema: extensions  }
      - { name: btree_gin          ,schema: extensions  }
      - { name: pg_trgm            ,schema: extensions  }
      - { name: intagg             ,schema: extensions  }
      - { name: intarray           ,schema: extensions  }
      - { name: pg_repack          ,schema: extensions  }

    #----------------------------------------------#
    # BACKUP : https://pigsty.io/docs/pgsql/backup
    #----------------------------------------------#
    minio_endpoint: https://sss.pigsty:9000 # explicit overwrite minio endpoint with haproxy port
    pgbackrest_method: minio              # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_repo:                      # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                              # default pgbackrest repo with local posix fs
        path: /pg/backup                  # local backup directory, `/pg/backup` by default
        retention_full_type: count        # retention full backups by count
        retention_full: 2                 # keep 2, at most 3 full backups when using local fs repo
      minio:                              # optional minio repo for pgbackrest
        type: s3                          # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty           # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1              # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql                  # minio bucket name, `pgsql` by default
        s3_key: pgbackrest                # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup      # minio user secret key for pgbackrest <------------------ HEY, DID YOU CHANGE THIS?
        s3_uri_style: path                # use path style uri for minio rather than host style
        path: /pgbackrest                 # minio backup path, default is `/pgbackrest`
        storage_port: 9000                # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                          # Enable block incremental backup
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest           # AES encryption password, default is 'pgBackRest'  <----- HEY, DID YOU CHANGE THIS?
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days
      s3:                                 # you can use cloud object storage as backup repo
        type: s3                          # Add your object storage credentials here!
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: <your_bucket_name>
        s3_key: <your_access_key>
        s3_key_secret: <your_secret_key>
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest           # AES encryption password, default is 'pgBackRest'
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Installation Demo

demo/supabase.cast

Explanation

The supabase template provides a complete self-hosted Supabase solution, allowing you to run this open-source Firebase alternative on your own infrastructure.

Architecture:

  • PostgreSQL: Production-grade Pigsty-managed PostgreSQL (with HA support)
  • Docker Containers: Supabase stateless services (Auth, Storage, Realtime, Edge Functions, etc.)
  • Silo: S3-compatible object storage deployed by the MINIO module for file storage and PostgreSQL backup
  • Nginx: Reverse proxy and HTTPS termination

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Supabase’s built-in database container
  • Supports PostgreSQL high availability (can be expanded to three-node cluster)
  • Installs all Supabase-required extensions (pg_net, pgjwt, pg_graphql, vector, etc.)
  • Stores internal analytics data in the dedicated _supabase database and advances processing with the scheduled supa-kick task
  • Integrated Silo object storage for file uploads and backups
  • HTTPS support with Let’s Encrypt automatic certificates

Deployment Steps:

curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
./configure -c supabase                   # Use supabase config template
./deploy.yml                              # Install Pigsty, PostgreSQL, Silo
./docker.yml -l supabase                  # Install Docker on the supabase group
./app.yml -l supabase                     # Start containers on the supabase group

Access:

# Supabase Studio
http://<IP>:8000
http://supa.pigsty   (username: supabase, password: pigsty)

# Direct PostgreSQL connection
psql postgres://supabase_admin:[email protected]:5432/postgres

Use Cases:

  • Need to self-host BaaS (Backend as a Service) platform
  • Want full control over data and infrastructure
  • Need enterprise-grade PostgreSQL HA and backups
  • Compliance or cost concerns with Supabase cloud service

Notes:

  • Must change JWT_SECRET: Use at least 32-character random string, and regenerate ANON_KEY and SERVICE_ROLE_KEY
  • Configure proper domain names (SITE_URL, API_EXTERNAL_URL)
  • Production environments should enable HTTPS (can use certbot for auto certificates)
  • Docker network needs access to PostgreSQL (172.17.0.0/16 HBA rule configured)

7.27 - app/odoo

Deploy Odoo open-source ERP system using Pigsty-managed PostgreSQL

The app/odoo configuration template provides a reference configuration for self-hosting Odoo open-source ERP system, using Pigsty-managed PostgreSQL as the database.

For more details, see Odoo Deployment Tutorial


Overview

  • Config Name: app/odoo
  • Node Count: Single node
  • Description: Deploy Odoo ERP using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/odoo [-i <primary_ip>]

Content

Source: pigsty/conf/app/odoo.yml

---
#==============================================================#
# File      :   odoo.yml
# Desc      :   pigsty config for running 1-node odoo app
# Ctime     :   2025-01-11
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/app/odoo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://pigsty.io/docs/app/odoo
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/odoo   # Use this odoo config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql & minio
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install odoo

all:
  children:

    # the odoo application (default username & password: admin/admin)
    odoo:
      hosts: { 10.10.10.10: {} }
      vars:
        app: odoo   # specify app name to be installed (in the apps)
        apps:       # define all applications
          odoo:     # app name, should have corresponding ~/pigsty/app/odoo folder
            file:   # optional directory to be created
              - { path: /data/odoo         ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/webdata ,state: directory, owner: 100, group: 101 }
              - { path: /data/odoo/addons  ,state: directory, owner: 100, group: 101 }
            conf:   # override /opt/<app>/.env config file
              PG_HOST: 10.10.10.10            # postgres host
              PG_PORT: 5432                   # postgres port
              PG_USERNAME: odoo               # postgres user
              PG_PASSWORD: DBUser.Odoo        # postgres password
              ODOO_PORT: 8069                 # odoo app port
              ODOO_DATA: /data/odoo/webdata   # odoo webdata
              ODOO_ADDONS: /data/odoo/addons  # odoo plugins
              ODOO_DBNAME: odoo               # odoo database name
              ODOO_VERSION: 19.0              # odoo image version

    # the odoo database
    pg-odoo:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-odoo
        pg_users:
          - { name: odoo    ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_admin ] ,createdb: true ,comment: admin user for odoo service }
          - { name: odoo_ro ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readonly ]  ,comment: read only user for odoo service  }
          - { name: odoo_rw ,password: DBUser.Odoo ,pgbouncer: true ,roles: [ dbrole_readwrite ] ,comment: read write user for odoo service }
        pg_databases:
          - { name: odoo ,owner: odoo ,revokeconn: true ,comment: odoo main database  }
        pg_hba_rules:
          - { user: all ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow access from local docker network' }
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home  : { domain: i.pigsty }
      minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      odoo:                           # nginx server config for odoo
        domain: odoo.pigsty           # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8069"  # odoo service endpoint: IP:PORT
        websocket: true               # add websocket support
        certbot: odoo.pigsty          # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/odoo template provides a one-click deployment solution for Odoo open-source ERP system.

What is Odoo:

  • World’s most popular open-source ERP system
  • Covers CRM, Sales, Purchasing, Inventory, Finance, HR, and other enterprise management modules
  • Supports thousands of community and official application extensions
  • Provides web interface and mobile support

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Odoo’s built-in database
  • Supports Odoo 19.0 latest version
  • Data persisted to independent directory /data/odoo
  • Supports custom plugin directory /data/odoo/addons

Access:

# Odoo Web interface
http://<IP>:8069
http://odoo.pigsty

# Create or set the administrator account on first access

Use Cases:

  • SMB ERP systems
  • Alternative to SAP, Oracle ERP and other commercial solutions
  • Enterprise applications requiring customized business processes

Notes:

  • Odoo container runs as uid=100, gid=101, data directory needs correct permissions
  • First access requires creating database and setting admin password
  • Production environments should enable HTTPS
  • Custom modules can be installed via /data/odoo/addons

7.28 - app/dify

Deploy Dify AI application development platform using Pigsty-managed PostgreSQL

The app/dify configuration template provides a reference configuration for self-hosting Dify AI application development platform, using Pigsty-managed PostgreSQL and pgvector as vector storage.

For more details, see Dify Deployment Tutorial


Overview

  • Config Name: app/dify
  • Node Count: Single node
  • Description: Deploy Dify using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/dify [-i <primary_ip>]

Content

Source: pigsty/conf/app/dify.yml

---
#==============================================================#
# File      :   dify.yml
# Desc      :   pigsty config for running 1-node dify app
# Ctime     :   2025-02-24
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/dify
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Last Verified Dify Version: v1.15.0 on 2026-07-09
# tutorial: https://pigsty.io/docs/app/dify
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/dify   # use this dify config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install dify with docker-compose
#
# To replace domain name:
#   sed -ie 's/dify.pigsty/dify.pigsty.cc/g' pigsty.yml


all:
  children:

    # the dify application
    dify:
      hosts: { 10.10.10.10: {} }
      vars:
        app: dify   # specify app name to be installed (in the apps)
        apps:       # define all applications
          dify:     # app name, should have corresponding ~/pigsty/app/dify folder
            file:   # data directory to be created
              - { path: /data/dify ,state: directory ,mode: 0755 }
            conf:   # override /opt/dify/.env config file

              # change domain, mirror, proxy, secret key
              NGINX_SERVER_NAME: dify.pigsty
              # A secret key for signing and encryption, gen with `openssl rand -base64 42` (CHANGE PASSWORD!)
              SECRET_KEY: sk-somerandomkey
              # expose DIFY nginx service with port 5001 by default
              DIFY_PORT: 5001
              # where to store dify files? the default is ./volume, we'll use another volume created above
              DIFY_DATA: /data/dify
              # enable the upstream websocket sidecar, while keeping PostgreSQL/pgvector external
              COMPOSE_PROFILES: collaboration
              NEXT_PUBLIC_SOCKET_URL: ws://dify.pigsty
              TRIGGER_URL: http://dify.pigsty
              ENDPOINT_URL_TEMPLATE: http://dify.pigsty/e/{hook_id}

              # proxy and mirror settings
              #PIP_MIRROR_URL: https://pypi.tuna.tsinghua.edu.cn/simple
              #SANDBOX_HTTP_PROXY: http://10.10.10.10:12345
              #SANDBOX_HTTPS_PROXY: http://10.10.10.10:12345

              # database credentials
              DB_TYPE: postgresql
              DB_USERNAME: dify
              DB_PASSWORD: difyai123456
              DB_HOST: 10.10.10.10
              DB_PORT: 5432
              DB_DATABASE: dify
              DB_SSL_MODE: disable
              VECTOR_STORE: pgvector
              PGVECTOR_HOST: 10.10.10.10
              PGVECTOR_PORT: 5432
              PGVECTOR_USER: dify
              PGVECTOR_PASSWORD: difyai123456
              PGVECTOR_DATABASE: dify
              PGVECTOR_MIN_CONNECTION: 2
              PGVECTOR_MAX_CONNECTION: 10

              # optional MinIO/S3 storage, disabled by default to avoid touching backup MinIO
              #STORAGE_TYPE: s3
              #S3_ENDPOINT: http://10.10.10.10:9000
              #S3_BUCKET_NAME: dify
              #S3_ACCESS_KEY: dify
              #S3_SECRET_KEY: S3User.Dify
              #S3_REGION: us-east-1
              #S3_ADDRESS_STYLE: path

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_extensions: [ pgvector ]
        pg_users:
          - { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
        pg_databases:
          - { name: dify        ,owner: dify ,extensions: [ { name: vector } ] ,comment: dify main database  }
          - { name: dify_plugin ,owner: dify ,comment: dify plugin daemon database }
        pg_hba_rules:
          - { user: dify ,db: all ,addr: 172.16.0.0/12  ,auth: pwd ,title: 'allow dify access from local docker networks' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home   :  { domain: i.pigsty }
      #minio :  { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      dify:                            # nginx server config for dify
        domain: dify.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5001"   # dify service endpoint: IP:PORT
        websocket: true                # add websocket support
        certbot: dify.pigsty           # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    # Dify v1.15.0 is patched in app/dify/patches for PostgreSQL 18's built-in uuidv7().
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/dify template provides a one-click deployment solution for Dify and is currently validated with Dify v1.15.0.

What is Dify:

  • Open-source LLM application development platform
  • Supports RAG, Agent, Workflow and other AI application modes
  • Provides visual Prompt orchestration and application building interface
  • Supports multiple LLM backends (OpenAI, Claude, local models, etc.)

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Dify’s built-in database
  • Uses pgvector as vector storage (replaces Weaviate/Qdrant)
  • Enables the collaboration Compose profile and WebSocket sidecar
  • Supports HTTPS and custom domain names
  • Data persisted to independent directory /data/dify

Access:

# Direct Dify Web access
http://<IP>:5001

# Or via Nginx proxy
https://dify.pigsty

Use Cases:

  • Enterprise internal AI application development platform
  • RAG knowledge base Q&A systems
  • LLM-driven automated workflows
  • AI Agent development and deployment

Notes:

  • Must change SECRET_KEY, generate with openssl rand -base64 42
  • Configure LLM API keys (e.g., OpenAI API Key)
  • Docker networks need access to PostgreSQL (the template configures a 172.16.0.0/12 HBA rule)
  • Recommend configuring proxy to accelerate Python package downloads

7.29 - app/electric

Deploy Electric real-time sync service using Pigsty-managed PostgreSQL

The app/electric configuration template provides a reference configuration for deploying Electric SQL real-time sync service, enabling real-time data synchronization from PostgreSQL to clients.


Overview

  • Config Name: app/electric
  • Node Count: Single node
  • Description: Deploy Electric real-time sync using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/electric [-i <primary_ip>]

Content

Source: pigsty/conf/app/electric.yml

---
#==============================================================#
# File      :   electric.yml
# Desc      :   pigsty config for running 1-node electric app
# Ctime     :   2025-03-29
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/app/electric
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://pigsty.io/docs/app/electric
# quick start: https://electric-sql.com/docs/quickstart
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap                 # prepare local repo & ansible
# ./configure -c app/electric # use this electric config template
# vi pigsty.yml               # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml                # install pigsty & pgsql & minio
# ./docker.yml                # install docker & docker-compose
# ./app.yml                   # install electric with docker-compose

all:
  children:
    # infra cluster for proxy, monitor, alert, etc..
    infra:
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:

        app: electric
        apps:       # define all applications
          electric: # app name, should have corresponding ~/pigsty/app/electric folder
            conf:   # override /opt/electric/.env config file : https://electric-sql.com/docs/api/config
              DATABASE_URL: 'postgresql://electric:[email protected]:5432/electric?sslmode=require'
              ELECTRIC_PORT: 8002
              ELECTRIC_PROMETHEUS_PORT: 8003
              ELECTRIC_INSECURE: true
              #ELECTRIC_SECRET: 1U6ItbhoQb4kGUU5wXBLbxvNf

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # postgres example cluster: pg-meta
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: electric ,password: DBUser.Electric ,pgbouncer: true , replication: true ,roles: [dbrole_admin] ,comment: electric main user }
        pg_databases: [{ name: electric , owner: electric }]
        pg_hba_rules:
          - { user: electric , db: replication ,addr: infra ,auth: ssl ,title: 'allow electric intranet/docker ssl access' }

  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:

    #----------------------------------#
    # Meta Data
    #----------------------------------#
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # domain names and upstream servers
      home : { domain: i.pigsty }
      electric:
        domain: elec.pigsty
        endpoint: "${admin_ip}:8002"
        websocket: true               # apply free ssl cert with certbot: make cert
        certbot: odoo.pigsty          # <----- replace with your own domain name!

    #----------------------------------#
    # Safe Guard
    #----------------------------------#
    # you can enable these flags after bootstrap, to prevent purging running etcd / pgsql instances
    etcd_safeguard: false             # prevent purging running etcd instance?
    pg_safeguard: false               # prevent purging running postgres instance? false by default

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/electric template provides a one-click deployment solution for Electric SQL real-time sync service.

What is Electric:

  • PostgreSQL to client real-time data sync service
  • Supports Local-first application architecture
  • Real-time syncs data changes via logical replication
  • Provides HTTP API for frontend application consumption

Key Features:

  • Uses Pigsty-managed PostgreSQL as data source
  • Captures data changes via Logical Replication
  • Supports SSL encrypted connections
  • Built-in Prometheus metrics endpoint

Access:

# Electric API endpoint
http://elec.pigsty:8002

# Prometheus metrics
http://elec.pigsty:8003/metrics

Use Cases:

  • Building Local-first applications
  • Real-time data sync to clients
  • Mobile and PWA data synchronization
  • Real-time updates for collaborative applications

Notes:

  • Electric user needs replication permission
  • PostgreSQL logical replication must be enabled
  • Production environments should use SSL connection (configured with sslmode=require)

7.30 - app/maybe

Deploy Maybe personal finance management system using Pigsty-managed PostgreSQL

The app/maybe configuration template provides a reference configuration for deploying Maybe open-source personal finance management system, using Pigsty-managed PostgreSQL as the database.


Overview

  • Config Name: app/maybe
  • Node Count: Single node
  • Description: Deploy Maybe finance management using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/maybe [-i <primary_ip>]

Content

Source: pigsty/conf/app/maybe.yml

---
#==============================================================#
# File      :   maybe.yml
# Desc      :   pigsty config for running 1-node maybe app
# Ctime     :   2025-09-08
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/maybe
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Maybe: self-hosted personal finance app
# GitHub: https://github.com/maybe-finance/maybe
# Last Verified Maybe Version: stable image / v0.6.0 release on 2026-07-09

# tutorial: https://pigsty.io/docs/app/maybe
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/maybe  # use this maybe config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install maybe
#
# To replace domain name:
#   sed -ie 's/maybe.pigsty/yourdomain.com/g' pigsty.yml

all:
  children:

    # the maybe application (personal finance management)
    maybe:
      hosts: { 10.10.10.10: {} }
      vars:
        app: maybe   # specify app name to be installed (in the apps)
        apps:        # define all applications
          maybe:     # app name, should have corresponding ~/pigsty/app/maybe folder
            file:    # optional directory to be created
              - { path: /data/maybe             ,state: directory ,mode: 0755 }
              - { path: /data/maybe/storage     ,state: directory ,owner: 1000 ,group: 1000 ,mode: 0755 }
              - { path: /data/maybe/redis       ,state: directory ,mode: 0755 }
            conf:    # override /opt/<app>/.env config file
              # Core Configuration
              MAYBE_IMAGE: ghcr.io/maybe-finance/maybe # Maybe image repository
              MAYBE_VERSION: stable                    # Maybe image version: stable = latest release
              MAYBE_PORT: 5002                         # Port to expose Maybe service
              MAYBE_DATA: /data/maybe                  # Data directory for Maybe
              APP_DOMAIN: maybe.pigsty                 # Domain name for Maybe
              
              # REQUIRED: Generate with: openssl rand -hex 64
              SECRET_KEY_BASE: 2f1e4c3d5b6a79808796a5b4c3d2e1f00123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567
              
              # Database Configuration
              DB_HOST: 10.10.10.10                    # PostgreSQL host
              DB_PORT: 5432                           # PostgreSQL port
              POSTGRES_USER: maybe                    # PostgreSQL username
              POSTGRES_PASSWORD: MaybeFinance2026     # PostgreSQL password (CHANGE THIS!)
              POSTGRES_DB: maybe_production           # PostgreSQL database name

              # Local Redis queue/cache
              REDIS_VERSION: 7-alpine

              # Optional: API Integration
              #SYNTH_API_KEY:                         # Get from synthfinance.com

    # the maybe database
    pg-maybe:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-maybe
        pg_users:
          - { name: maybe ,password: MaybeFinance2026 ,pgbouncer: true ,roles: [ dbrole_admin ] ,comment: admin user for maybe service }
        pg_databases:
          - { name: maybe_production ,owner: maybe ,revokeconn: true ,comment: maybe main database  }
        pg_hba_rules:
          - { user: maybe ,db: maybe_production ,addr: 172.16.0.0/12 ,auth: pwd ,title: 'allow maybe access from local docker network' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # infra services exposed via portal
      home  : { domain: i.pigsty }    # default domain name
      maybe:                          # nginx server config for maybe
        domain: maybe.pigsty          # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5002"  # maybe service endpoint: IP:PORT
        websocket: true               # add websocket support

    repo_enabled: false
    node_repo_modules: node,infra,pgsql

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root

...

Explanation

The app/maybe template provides a one-click deployment solution for Maybe open-source personal finance management system.

What is Maybe:

  • Open-source personal and family finance management system
  • Supports multi-account, multi-currency asset tracking
  • Provides investment portfolio analysis and net worth calculation
  • Beautiful modern web interface

Key Features:

  • Uses Pigsty-managed PostgreSQL instead of Maybe’s built-in database
  • Data persisted to independent directory /data/maybe
  • Supports HTTPS and custom domain names
  • Multi-user permission management

Access:

# Maybe Web interface
http://maybe.pigsty:5002

# Or via Nginx proxy
https://maybe.pigsty

Use Cases:

  • Personal or family finance management
  • Investment portfolio tracking and analysis
  • Multi-account asset aggregation
  • Alternative to commercial services like Mint, YNAB

Notes:

  • Must change SECRET_KEY_BASE, generate with openssl rand -hex 64
  • First access requires registering an admin account
  • Optionally configure Synth API for stock price data

7.31 - app/teable

Deploy Teable open-source Airtable alternative using Pigsty-managed PostgreSQL

The app/teable configuration template provides a reference configuration for deploying Teable open-source no-code database, using Pigsty-managed PostgreSQL as the database.


Overview

  • Config Name: app/teable
  • Node Count: Single node
  • Description: Deploy Teable using Pigsty-managed PostgreSQL
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/teable [-i <primary_ip>]

Content

Source: pigsty/conf/app/teable.yml

---
#==============================================================#
# File      :   teable.yml
# Desc      :   pigsty config for running 1-node teable app
# Ctime     :   2025-02-24
# Mtime     :   2026-07-10
# Docs      :   https://pigsty.io/docs/app/teable
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://pigsty.io/docs/app/teable
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/teable # use this teable config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml              # install pigsty & pgsql & minio
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install teable with docker-compose
#
# To replace domain name:
#   sed -ie 's/teable.pigsty/teable.pigsty.cc/g' pigsty.yml

all:
  children:

    # the teable application
    teable:
      hosts: { 10.10.10.10: {} }
      vars:
        app: teable   # specify app name to be installed (in the apps)
        apps:         # define all applications
          teable:     # app name, ~/pigsty/app/teable folder
            conf:     # override /opt/teable/.env config file
              # https://github.com/teableio/teable/blob/develop/dockers/examples/standalone/.env
              # https://help.teable.io/en/deploy/env
              POSTGRES_HOST: "10.10.10.10"
              POSTGRES_PORT: "5432"
              POSTGRES_DB: "teable"
              POSTGRES_USER: "dbuser_teable"
              POSTGRES_PASSWORD: "DBUser.Teable"
              PRISMA_DATABASE_URL: "postgresql://dbuser_teable:[email protected]:5432/teable"
              PUBLIC_ORIGIN: "http://tea.pigsty"
              PUBLIC_DATABASE_PROXY: "10.10.10.10:5432"
              TIMEZONE: "UTC"

              # Need to support sending emails to enable the following configurations
              #BACKEND_MAIL_HOST: smtp.teable.io
              #BACKEND_MAIL_PORT: 465
              #BACKEND_MAIL_SECURE: true
              #BACKEND_MAIL_SENDER: noreply.teable.io
              #BACKEND_MAIL_SENDER_NAME: Teable
              #BACKEND_MAIL_AUTH_USER: username
              #BACKEND_MAIL_AUTH_PASS: password


    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_teable ,password: DBUser.Teable ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: teable superuser }
        pg_databases:
          - { name: teable ,owner: dbuser_teable ,comment: teable database }
        pg_hba_rules:
          - { user: dbuser_teable ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow teable access from local docker network' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345
    infra_portal:                        # domain names and upstream servers
      home   : { domain: i.pigsty }
      #minio : { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }

      teable:                            # nginx server config for teable
        domain: tea.pigsty               # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8890"     # teable service endpoint: IP:PORT
        websocket: true                  # add websocket support
        certbot: tea.pigsty              # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    node_etc_hosts: [ '${admin_ip} i.pigsty sss.pigsty' ]
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/teable template provides a one-click deployment solution for Teable open-source no-code database.

What is Teable:

  • Open-source Airtable alternative
  • No-code database built on PostgreSQL
  • Supports table, kanban, calendar, form, and other views
  • Provides API and automation workflows

Key Features:

  • Uses Pigsty-managed PostgreSQL as underlying storage
  • Data is stored in real PostgreSQL tables
  • Supports direct SQL queries
  • Can integrate with other PostgreSQL tools and extensions

Access:

# Teable Web interface
http://tea.pigsty:8890

# Or via Nginx proxy
https://tea.pigsty

# Direct SQL access to underlying data
psql postgresql://dbuser_teable:[email protected]:5432/teable

Use Cases:

  • Need Airtable-like functionality but want to self-host
  • Team collaboration data management
  • Need both API and SQL access
  • Want data stored in real PostgreSQL

Notes:

  • Teable user needs superuser privileges
  • Must configure PUBLIC_ORIGIN to external access address
  • Supports email notifications (optional SMTP configuration)

7.32 - app/mattermost

Mattermost template for one-click team collaboration deployment with Pigsty PostgreSQL and Docker.

The app/mattermost configuration template deploys Mattermost with Pigsty-managed PostgreSQL, Nginx, and monitoring. By default, the app and database run on the same node.

For application usage details, see Mattermost: Open-Source IM.


Overview

  • Config Name: app/mattermost
  • Node Count: Single node (default)
  • Description: Out-of-the-box Mattermost + PostgreSQL + Docker template
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: app/odoo, app/registry, supabase

Usage:

./configure -c app/mattermost
./deploy.yml
./docker.yml
./app.yml

Content

Source: pigsty/conf/app/mattermost.yml

---
#==============================================================#
# File      :   mattermost.yml
# Desc      :   pigsty config for running 1-node mattermost app
# Ctime     :   2026-02-04
# Mtime     :   2026-02-04
# Docs      :   https://pigsty.io/docs/app/mattermost
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://pigsty.io/docs/app/mattermost
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap                    # prepare local repo & ansible
# ./configure -c app/mattermost  # use this mattermost config template
# vi pigsty.yml                  # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml                   # install pigsty & pgsql
# ./docker.yml                   # install docker & docker-compose
# ./app.yml                      # install mattermost
#
# Design Notes:
# - Mattermost data/config/logs/plugins/bleve-indexes are persisted under /data/mattermost (host paths).
# - If you enable JuiceFS (PGFS), /data/mattermost becomes a mountpoint backed by PostgreSQL.
#   This is optional and must be prepared with ./juice.yml before ./app.yml.
# - Storing file data in PostgreSQL increases DB size, WAL, and IO load; monitor bloat and backup cost.

all:
  children:

    # the mattermost application
    mattermost:
      hosts: { 10.10.10.10: {} }
      vars:
        app: mattermost   # specify app name to be installed (in the apps)
        apps:             # define all applications
          mattermost:     # app name, should have corresponding ~/pigsty/app/mattermost folder
            file:         # data directory to be created
              - { path: /data/mattermost                ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
              - { path: /data/mattermost/config         ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
              - { path: /data/mattermost/data           ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
              - { path: /data/mattermost/logs           ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
              - { path: /data/mattermost/plugins        ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
              - { path: /data/mattermost/client/plugins ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
              - { path: /data/mattermost/bleve-indexes  ,state: directory ,owner: 2000 ,group: 2000 ,mode: 0755 }
            conf:         # override /opt/mattermost/.env config file
              DOMAIN: mm.pigsty
              APP_PORT: 8065
              TZ: UTC

              # postgres connection string
              POSTGRES_URL: 'postgres://dbuser_mattermost:[email protected]:5432/mattermost?sslmode=disable&connect_timeout=10'

              # image version
              MATTERMOST_IMAGE: mattermost-team-edition
              MATTERMOST_IMAGE_TAG: latest

              # data directories
              MATTERMOST_CONFIG_PATH: /data/mattermost/config
              MATTERMOST_DATA_PATH: /data/mattermost/data
              MATTERMOST_LOGS_PATH: /data/mattermost/logs
              MATTERMOST_PLUGINS_PATH: /data/mattermost/plugins
              MATTERMOST_CLIENT_PLUGINS_PATH: /data/mattermost/client/plugins
              MATTERMOST_BLEVE_INDEXES_PATH: /data/mattermost/bleve-indexes
              MM_BLEVESETTINGS_INDEXDIR: /data/mattermost/bleve-indexes

    # the mattermost database
    pg-mattermost:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-mattermost
        pg_users:
          - { name: dbuser_mattermost ,password: DBUser.Mattermost ,pgbouncer: true ,roles: [ dbrole_admin ] ,createdb: true ,comment: admin user for mattermost }
        pg_databases:
          - { name: mattermost ,owner: dbuser_mattermost ,revokeconn: true ,comment: mattermost main database }
        pg_hba_rules:
          - { user: dbuser_mattermost ,db: all ,addr: 172.17.0.0/16  ,auth: pwd ,title: 'allow mattermost access from local docker network' }
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    # Optional: PGFS with JuiceFS (store Mattermost file data in PostgreSQL)
    # 1) Uncomment and adjust the block below
    # 2) Run: ./juice.yml -l <host>
    # 3) Ensure /data/mattermost is mounted before ./app.yml
    #
    #juice_cache: /data/juice
    #juice_instances:
    #  pgfs:
    #    path  : /data/mattermost
    #    meta  : postgres://dbuser_mattermost:[email protected]:5432/mattermost
    #    data  : --storage postgres --bucket 10.10.10.10:5432/mattermost --access-key dbuser_mattermost --secret-key DBUser.Mattermost
    #    port  : 9567
    #    owner : 2000
    #    group : 2000
    #    mode  : '0755'

    infra_portal:                     # infra services exposed via portal
      home       : { domain: i.pigsty }
      mattermost:                      # nginx server config for mattermost
        domain: mm.pigsty              # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "${admin_ip}:8065"   # mattermost service endpoint: IP:PORT
        websocket: true                # add websocket support
        certbot: mm.pigsty             # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/mattermost template defines three key groups:

  • mattermost: app host and apps.mattermost settings, including .env overrides and data directory definition
  • pg-mattermost: dedicated PostgreSQL cluster, database, and application account
  • infra / etcd: shared Pigsty infrastructure dependencies

Key Features:

  • Enables Docker runtime by default (docker_enabled: true) and prepares it through ./docker.yml
  • Exposes mm.pigsty in the Nginx portal (infra_portal.mattermost) with WebSocket support
  • Includes local Docker subnet HBA rule (172.17.0.0/16) for app-to-database access
  • Provides optional JuiceFS settings (commented) to mount /data/mattermost on PostgreSQL-backed storage

Notes:

  • Change database credentials, domain names, and application secrets before deployment
  • If exposed to public networks, enable HTTPS and enforce ACL and firewall policies

7.33 - app/registry

Deploy Docker Registry image proxy and private registry using Pigsty

The app/registry configuration template provides a reference configuration for deploying Docker Registry as an image proxy, usable as Docker Hub mirror acceleration or private image registry.


Overview

  • Config Name: app/registry
  • Node Count: Single node
  • Description: Deploy Docker Registry image proxy and private registry
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/registry [-i <primary_ip>]

Content

Source: pigsty/conf/app/registry.yml

---
#==============================================================#
# File      :   registry.yml
# Desc      :   pigsty config for running Docker Registry Mirror
# Ctime     :   2025-07-01
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/registry
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# tutorial: https://pigsty.io/docs/app/registry
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./configure -c app/registry   # use this registry config template
# vi pigsty.yml                 # IMPORTANT: CHANGE DOMAIN & CREDENTIALS!
# ./deploy.yml                  # install pigsty
# ./docker.yml                  # install docker & docker-compose
# ./app.yml                     # install registry with docker-compose
#
# To replace domain name:
#   sed -ie 's/registry.pigsty/registry.your-domain.com/g' pigsty.yml

#==============================================================#
# Usage Instructions:
#==============================================================#
#
# 1. Deploy the registry:
#    ./configure -c app/registry && ./deploy.yml && ./docker.yml && ./app.yml
#
# 2. Configure Docker clients to use the mirror:
#    Edit /etc/docker/daemon.json:
#    {
#      "registry-mirrors": ["https://registry.your-domain.com"],
#      "insecure-registries": ["registry.your-domain.com"]
#    }
#
# 3. Restart Docker daemon:
#    sudo systemctl restart docker
#
# 4. Test the registry:
#    docker pull nginx:latest  # This will now use your mirror
#
# 5. Access the web UI (optional):
#    https://registry-ui.your-domain.com
#
# 6. Monitor the registry:
#    curl https://registry.your-domain.com/v2/_catalog
#    curl https://registry.your-domain.com/v2/nginx/tags/list
#
#==============================================================#


all:
  children:

    # the docker registry mirror application
    registry:
      hosts: { 10.10.10.10: {} }
      vars:
        app: registry                    # specify app name to be installed
        apps:                            # define all applications
          registry:
            file:                        # create data directory for registry
              - { path: /data/registry ,state: directory ,mode: 0755 }
            conf:                        # environment variables for registry
              REGISTRY_IMAGE: registry:3.1.1
              REGISTRY_UI_IMAGE: joxit/docker-registry-ui:2.6.0
              REGISTRY_DATA: /data/registry
              REGISTRY_PORT: 5000
              REGISTRY_UI_PORT: 5080
              REGISTRY_STORAGE_DELETE_ENABLED: true
              REGISTRY_LOG_LEVEL: info
              REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
              REGISTRY_PROXY_TTL: 168h

    # basic infrastructure
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

  vars:
    #----------------------------------------------#
    # INFRA : https://pigsty.io/docs/infra/param
    #----------------------------------------------#
    version: v4.5.0                      # pigsty version string
    admin_ip: 10.10.10.10                # admin node ip address
    region: default                      # upstream mirror region: default,china,europe
    infra_portal:                        # infra services exposed via portal
      home : { domain: i.pigsty }        # default domain name

      # Docker Registry Mirror service configuration
      registry:                          # nginx server config for registry
        domain: d.pigsty                 # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5000"     # registry service endpoint: IP:PORT
        websocket: false                 # registry doesn't need websocket
        certbot: d.pigsty                # certbot cert name, apply with `make cert`

      # Optional: Registry Web UI
      registry-ui:                       # nginx server config for registry UI
        domain: dui.pigsty               # REPLACE IT WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:5080"     # registry UI endpoint: IP:PORT
        websocket: false                 # UI doesn't need websocket
        certbot: d.pigsty                # certbot cert name for UI

    #----------------------------------------------#
    # NODE : https://pigsty.io/docs/node/param
    #----------------------------------------------#
    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    node_tune: oltp                     # node tuning specs: oltp,olap,tiny,crit

    #----------------------------------------------#
    # PGSQL : https://pigsty.io/docs/pgsql/param
    #----------------------------------------------#
    pg_version: 18                      # Default PostgreSQL Major Version is 18
    pg_conf: oltp.yml                   # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_packages: [ pgsql-main, pgsql-common ]   # pg kernel and common utils
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/registry template provides a one-click deployment solution for Docker Registry image proxy.

What is Registry:

  • Docker’s official image registry implementation
  • Can serve as Docker Hub pull-through cache
  • Can also serve as private image registry
  • Supports image caching and local storage

Key Features:

  • Pins registry:3.1.1 and joxit/docker-registry-ui:2.6.0 by default
  • Acts as proxy cache for Docker Hub to accelerate image pulls
  • Caches images to local storage /data/registry
  • Provides Web UI to view cached images
  • Supports custom cache expiration time

Configure Docker Client:

Edit /etc/docker/daemon.json:

{
  "registry-mirrors": ["http://d.pigsty"],
  "insecure-registries": ["d.pigsty:5000"]
}

Restart Docker:

sudo systemctl restart docker

Access:

# Registry API
http://d.pigsty/v2/_catalog

# Web UI
http://dui.pigsty:5080

# Pull images (automatically uses proxy)
docker pull nginx:latest

Use Cases:

  • Accelerate Docker image pulls (especially in mainland China)
  • Reduce external network dependency
  • Enterprise internal private image registry
  • Offline environment image distribution

Notes:

  • Requires sufficient disk space to store cached images
  • Default cache TTL is 7 days (REGISTRY_PROXY_TTL: 168h)
  • Can configure HTTPS certificates (via certbot)

7.34 - app/insforge

Deploy the InsForge Backend-as-a-Service platform with Pigsty-managed PostgreSQL

The app/insforge configuration template deploys InsForge OSS and uses Pigsty-managed PostgreSQL as the external database.

For details, see: InsForge Deployment Tutorial


Overview

  • Config Name: app/insforge
  • Node Count: Single node
  • Description: Deploy InsForge App, PostgREST, and Deno Runtime, and create the required PostgreSQL users, roles, databases, and extensions
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta, supabase

Usage:

./configure -c app/insforge [-i <primary_ip>]

Content

Source: pigsty/conf/app/insforge.yml

---
#==============================================================#
# File      :   insforge.yml
# Desc      :   pigsty config for running 1-node insforge app
# Ctime     :   2026-03-10
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/insforge
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# InsForge: Open-source Backend-as-a-Service for AI coding agents
# GitHub: https://github.com/InsForge/InsForge
# Last Verified InsForge Version: v2.2.6 on 2026-07-09
#
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap                  # prepare local repo & ansible
# ./configure -c app/insforge  # use this insforge config template
# vi pigsty.yml                # IMPORTANT: CHANGE CREDENTIALS!!
# ./deploy.yml                 # install pigsty & pgsql
# ./docker.yml                 # install docker & docker-compose
# ./app.yml                    # install insforge with docker-compose
#
# To replace domain name:
#   sed -ie 's/isf.pigsty/isf.yourdomain.com/g' pigsty.yml


all:
  children:

    # the insforge application
    insforge:
      hosts: { 10.10.10.10: {} }
      vars:
        app: insforge   # specify app name to be installed (in the apps)
        apps:           # define all applications
          insforge:     # app name, should have corresponding ~/pigsty/app/insforge folder
            conf:       # override /opt/insforge/.env config file

              # secrets (CHANGE THESE!)
              JWT_SECRET: your-secret-key-here-must-be-32-char-or-above
              ENCRYPTION_KEY: your-encryption-key-here-must-be-32-char-or-above
              ROOT_ADMIN_USERNAME: [email protected]
              ROOT_ADMIN_PASSWORD: pigsty
              # legacy aliases for older InsForge images
              ADMIN_EMAIL: [email protected]
              ADMIN_PASSWORD: pigsty

              # database credentials (must match pg_users below)
              POSTGRES_HOST: 10.10.10.10
              POSTGRES_PORT: 5432
              POSTGRES_DB: insforge
              POSTGRES_USER: dbuser_insforge
              POSTGRES_PASSWORD: DBUser.Insforge

              # optional: image overrides, useful when ghcr.io is slow or blocked
              #INSFORGE_IMAGE: ghcr.io/insforge/insforge-oss:v2.2.6
              #DENO_RUNTIME_IMAGE: ghcr.io/insforge/deno-runtime:latest

              # optional: LLM model gateway via OpenRouter
              #OPENROUTER_API_KEY: sk-or-xxxxx
              #MAX_COMPLETION_TOKENS: 16384

              # optional: MCP / Cloud API access
              #ACCESS_API_KEY: ik_xxxxx
              #ACCESS_ANON_KEY: anon_xxxxx
              #CLOUD_API_HOST: https://api.insforge.dev

              # optional: object storage / CDN
              #AWS_ACCESS_KEY_ID:
              #AWS_SECRET_ACCESS_KEY:
              #AWS_REGION:
              #AWS_S3_BUCKET:
              #S3_ACCESS_KEY_ID:
              #S3_SECRET_ACCESS_KEY:
              #S3_ENDPOINT_URL:
              #S3_FORCE_PATH_STYLE: true
              #AWS_CONFIG_BUCKET:
              #AWS_CONFIG_REGION:
              #AWS_CLOUDFRONT_URL:
              #AWS_CLOUDFRONT_KEY_PAIR_ID:
              #AWS_CLOUDFRONT_PRIVATE_KEY:
              #MAX_FILE_SIZE:
              #MAX_JSON_BODY_SIZE: 100mb
              #MAX_URLENCODED_BODY_SIZE: 10mb

              # optional: Deno edge functions
              #DENO_DEPLOY_TOKEN:
              #DENO_DEPLOY_ORG_ID:
              #FUNCTIONS_DOMAIN:
              # legacy aliases for older InsForge images
              #DENO_SUBHOSTING_TOKEN:
              #DENO_SUBHOSTING_ORG_ID:

              # optional: site deployment / compute
              #VERCEL_TOKEN:
              #VERCEL_TEAM_ID:
              #VERCEL_PROJECT_ID:
              #FLY_API_TOKEN:
              #FLY_ORG:
              #COMPUTE_DOMAIN:

              # optional: payments
              #STRIPE_TEST_SECRET_KEY:
              #STRIPE_LIVE_SECRET_KEY:
              #RAZORPAY_TEST_KEY_ID:
              #RAZORPAY_TEST_KEY_SECRET:
              #RAZORPAY_LIVE_KEY_ID:
              #RAZORPAY_LIVE_KEY_SECRET:

              # optional: managed / hybrid cloud metadata
              #DEPLOYMENT_ID:
              #PROJECT_ID:
              #APP_KEY:
              #INSFORGE_TELEMETRY_DISABLED: 1

              # optional: OAuth providers
              #GOOGLE_CLIENT_ID:
              #GOOGLE_CLIENT_SECRET:
              #GITHUB_CLIENT_ID:
              #GITHUB_CLIENT_SECRET:

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: dbuser_insforge ,password: DBUser.Insforge ,pgbouncer: true ,roles: [dbrole_admin] ,superuser: true ,comment: 'insforge superuser' }
          - { name: anon            ,login: false ,comment: 'insforge anonymous role for PostgREST' }
          - { name: authenticated   ,login: false ,comment: 'insforge authenticated role' }
          - { name: project_admin   ,login: false ,bypassrls: true ,comment: 'insforge project admin with RLS bypass' }
        pg_databases:
          - name: insforge
            owner: dbuser_insforge
            baseline: insforge.sql
            extensions: [pgcrypto, http, pg_cron]
            comment: InsForge BaaS database
        pg_libs: 'pg_cron, pg_stat_statements, auto_explain'
        pg_parameters:
          cron.database_name: insforge
          app.encryption_key: your-encryption-key-here-must-be-32-char-or-above
          insforge.policy_grant_role: project_admin
          insforge.policy_grant_tables: 'storage.objects,realtime.channels,realtime.messages,payments.stripe_checkout_sessions,payments.stripe_customer_portal_sessions,payments.razorpay_orders,payments.razorpay_subscriptions'
          insforge.internal_schemas: 'ai,auth,compute,deployments,email,functions,memory,payments,realtime,schedules,storage,system'
        pg_extensions: [ pg_cron, pg_http ]
        pg_hba_rules:
          - { user: dbuser_insforge ,db: all ,addr: 172.16.0.0/12 ,auth: pwd ,title: 'allow insforge access from local docker networks' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home    :  { domain: i.pigsty }
      insforge:                       # nginx server config for insforge
        domain: isf.pigsty            # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:7130"  # insforge API+dashboard endpoint: IP:PORT
        websocket: true               # add websocket support
        certbot: isf.pigsty           # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/insforge template deploys by default:

  • InsForge main service: ghcr.io/insforge/insforge-oss:v2.2.6, port 7130
  • PostgREST: postgrest/postgrest:v12.2.12, port 5430
  • Deno Runtime: port 7133
  • PostgreSQL database: insforge
  • Extensions: pgcrypto, http, pg_cron
  • PostgreSQL 18 with BYPASSRLS enabled for project_admin
  • Local Docker-network HBA range: 172.16.0.0/12
  • Nginx entrypoint: isf.pigsty -> 10.10.10.10:7130

Access:

http://<IP>:7130
http://isf.pigsty

The default admin account is [email protected] / pigsty. For production, change JWT_SECRET, ENCRYPTION_KEY, ROOT_ADMIN_PASSWORD, and the database password, keeping encryption and grant settings aligned with pg_parameters.

7.35 - app/hindsight

Deploy the Hindsight AI long-term memory service with Pigsty-managed PostgreSQL

The app/hindsight configuration template deploys Hindsight and replaces its built-in development database with Pigsty-managed external PostgreSQL.

For details, see: Hindsight Deployment Tutorial


Overview

  • Config Name: app/hindsight
  • Node Count: Single node
  • Description: Deploy the Hindsight all-in-one container, create an external PostgreSQL database, and configure UI/API entrypoints
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c app/hindsight [-i <primary_ip>]

Content

Source: pigsty/conf/app/hindsight.yml

---
#==============================================================#
# File      :   hindsight.yml
# Desc      :   pigsty config for running 1-node hindsight app
# Ctime     :   2026-04-09
# Mtime     :   2026-04-09
# Docs      :   https://pigsty.io/docs/app/hindsight
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Hindsight: Agent memory that learns, backed by PostgreSQL
# GitHub: https://github.com/vectorize-io/hindsight
# Last Verified upstream deployment files: main branch on 2026-04-09
#
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap                  # prepare local repo & ansible
# ./configure -c app/hindsight # use this hindsight config template
# vi pigsty.yml                # IMPORTANT: CHANGE CREDENTIALS / LLM SETTINGS!!
# ./deploy.yml                 # install pigsty & pgsql
# ./docker.yml                 # install docker & docker-compose
# ./app.yml                    # install hindsight with docker-compose
#
# To replace domain names:
#   sed -ie 's/hs.pigsty/hs.yourdomain.com/g; s/hs-api.pigsty/hs-api.yourdomain.com/g' pigsty.yml


all:
  children:

    # the hindsight application
    hindsight:
      hosts: { 10.10.10.10: {} }
      vars:
        app: hindsight   # specify app name to be installed (in the apps)
        apps:            # define all applications
          hindsight:     # app name, should have corresponding ~/pigsty/app/hindsight folder
            file:
              - { path: /data/hindsight ,state: directory ,mode: 0755 }
            conf:
              # image / published ports
              HINDSIGHT_VERSION: latest
              HINDSIGHT_API_PUBLISH_PORT: 8888
              HINDSIGHT_UI_PUBLISH_PORT: 9999
              HINDSIGHT_MODEL_CACHE: /data/hindsight

              # database credentials (must match pg_users below)
              HINDSIGHT_DB_HOST: 10.10.10.10
              HINDSIGHT_DB_PORT: 5432
              HINDSIGHT_DB_NAME: hindsight
              HINDSIGHT_DB_USER: hindsight
              HINDSIGHT_DB_PASSWORD: DBUser.Hindsight
              HINDSIGHT_DB_SCHEMA: public

              # default search backend: safest first deployment
              HINDSIGHT_API_VECTOR_EXTENSION: pgvector
              HINDSIGHT_API_TEXT_SEARCH_EXTENSION: native

              # default to `none` so the stack boots without an external LLM
              HINDSIGHT_API_LLM_PROVIDER: none
              HINDSIGHT_API_LLM_MODEL: gpt-5-mini
              HINDSIGHT_API_LLM_API_KEY: ''

              # optional: local Ollama on the same host
              #HINDSIGHT_API_LLM_PROVIDER: ollama
              #HINDSIGHT_API_LLM_BASE_URL: http://host.docker.internal:11434/v1
              #HINDSIGHT_API_LLM_MODEL: qwen3:8b

              # optional: multilingual / Chinese retrieval
              # requires Pigsty extensions vchord + vchord_bm25
              #HINDSIGHT_API_VECTOR_EXTENSION: vchord
              #HINDSIGHT_API_TEXT_SEARCH_EXTENSION: vchord

    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_extensions: [ pgvector ]
        pg_users:
          - { name: hindsight ,password: DBUser.Hindsight ,pgbouncer: true ,pool_mode: session ,roles: [ dbrole_readwrite ] ,comment: hindsight service user }
        pg_databases:
          - { name: hindsight ,owner: hindsight ,extensions: [ vector ] ,comment: Hindsight agent memory database }
        pg_hba_rules:
          - { user: hindsight ,db: all ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow hindsight access from local docker network' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home         : { domain: i.pigsty }
      hindsight:
        domain: hs.pigsty
        endpoint: "10.10.10.10:9999"
        websocket: false
        certbot: hs.pigsty
      hindsight-api:
        domain: hs-api.pigsty
        endpoint: "10.10.10.10:8888"
        websocket: false
        certbot: hs-api.pigsty

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The app/hindsight template deploys by default:

  • Hindsight container: ghcr.io/vectorize-io/hindsight:latest
  • UI port: 9999
  • API port: 8888
  • PostgreSQL database: hindsight
  • Default vector extension: vector
  • Nginx entrypoints: hs.pigsty -> 9999, hs-api.pigsty -> 8888

Access:

http://hs.pigsty
http://hs-api.pigsty
http://<IP>:9999
http://<IP>:8888

The template sets HINDSIGHT_API_LLM_PROVIDER=none by default, so the service can start first. Fact extraction and reflection require configuring a real LLM backend later.

7.36 - app/immich

Deploy Immich photo and video management with Pigsty-managed PostgreSQL and VectorChord

The app/immich template deploys Immich with Pigsty-managed PostgreSQL 18 for metadata and vector indexes. The current template is validated with Immich v3.0.1.


Overview

  • Config Name: app/immich
  • Node Count: Single node
  • Application Port: 2283
  • Data Directory: /data/immich/library
  • Related: meta, app/registry

Usage:

./configure -c app/immich [-i <primary_ip>]

Content

Source: pigsty/conf/app/immich.yml

---
#==============================================================#
# File      :   immich.yml
# Desc      :   pigsty config for running 1-node immich app
# Ctime     :   2026-07-04
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/immich
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# Immich: high performance self-hosted photo and video management
# GitHub: https://github.com/immich-app/immich
# Last Verified Immich Version: v3.0.1 on 2026-07-04
#
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap               # prepare local repo & ansible
# ./configure -c app/immich # use this immich config template
# vi pigsty.yml             # IMPORTANT: CHANGE CREDENTIALS / DOMAIN / STORAGE PATH!
# ./deploy.yml              # install pigsty & pgsql
# ./docker.yml              # install docker & docker-compose
# ./app.yml                 # install immich with docker-compose
#
# To replace domain name:
#   sed -ie 's/photo.pigsty/yourdomain.com/g' pigsty.yml


all:
  children:

    # the immich application
    immich:
      hosts: { 10.10.10.10: {} }
      vars:
        app: immich   # specify app name to be installed (in the apps)
        apps:         # define all applications
          immich:     # app name, should have corresponding ~/pigsty/app/immich folder
            file:     # media directory to be created
              - { path: /data/immich         ,state: directory ,mode: 0755 }
              - { path: /data/immich/library ,state: directory ,mode: 0755 }
            conf:     # override /opt/immich/.env config file

              # image / published port
              IMMICH_VERSION: v3
              IMMICH_HOST_PORT: 2283
              TZ: Asia/Shanghai

              # media files: photos, videos, thumbnails, encoded video, avatars
              UPLOAD_LOCATION: /data/immich/library

              # database credentials (must match pg_users below)
              DB_URL: 'postgresql://dbuser_immich:[email protected]:5432/immich'
              DB_VECTOR_EXTENSION: vectorchord

              # local Valkey service in app/immich/docker-compose.yml
              REDIS_HOSTNAME: redis
              REDIS_PORT: 6379

    # the immich database
    pg-immich:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-immich
        pg_extensions: [ pgvector, vchord ]
        pg_libs: 'vchord.so, pg_stat_statements, auto_explain'
        pg_users:
          - { name: dbuser_immich ,password: DBUser.Immich ,pgbouncer: true ,pool_mode: session ,roles: [ dbrole_admin ] ,comment: immich service user }
        pg_databases:
          - { name: immich ,owner: dbuser_immich ,revokeconn: true ,extensions: [ vchord, earthdistance ] ,comment: immich metadata database }
        pg_hba_rules:
          - { user: dbuser_immich ,db: immich ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow immich access from local docker network' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home  : { domain: i.pigsty }
      immich:                          # nginx server config for immich
        domain: photo.pigsty           # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:2283"   # immich service endpoint: IP:PORT
        websocket: true                # add websocket support
        certbot: photo.pigsty          # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql
    pg_version: 18

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

  • Persists application media under /data/immich/library
  • Creates the pg-immich PostgreSQL cluster and matching database/service account
  • Installs pgvector and vchord, then creates vchord and earthdistance in the database
  • Preloads vchord.so and sets DB_VECTOR_EXTENSION: vectorchord
  • Uses the local Valkey service from the application Compose stack rather than a Pigsty Redis cluster
  • Proxies photo.pigsty to 10.10.10.10:2283

Change the database password, domain, and media path before deployment. The target platform must also provide a vchord package matching PostgreSQL 18.

7.37 - app/jumpserver

Deploy the JumpServer open-source bastion host with Pigsty-managed PostgreSQL

The app/jumpserver template deploys JumpServer Community Edition with Pigsty-managed PostgreSQL 18 as its external database. The current template is validated with JumpServer v4.10.16-ce.


Overview

  • Config Name: app/jumpserver
  • Node Count: Single node
  • Web Port: 8080
  • SSH Port: 2222
  • Related: meta

Usage:

./configure -c app/jumpserver [-i <primary_ip>]

Content

Source: pigsty/conf/app/jumpserver.yml

---
#==============================================================#
# File      :   jumpserver.yml
# Desc      :   pigsty config for running 1-node jumpserver app
# Ctime     :   2026-07-09
# Mtime     :   2026-07-09
# Docs      :   https://pigsty.io/docs/app/jumpserver
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#
# JumpServer: open-source PAM / bastion host
# GitHub: https://github.com/jumpserver/jumpserver
# Last Verified JumpServer Version: v4.10.16-ce on 2026-07-09
#
# how to use this template:
#
#  curl -fsSL https://repo.pigsty.io/get | bash; cd ~/pigsty
# ./bootstrap                  # prepare local repo & ansible
# ./configure -c app/jumpserver # use this jumpserver config template
# vi pigsty.yml                # IMPORTANT: CHANGE CREDENTIALS / DOMAIN / SECRETS!
# ./deploy.yml                 # install pigsty & pgsql
# ./docker.yml                 # install docker & docker-compose
# ./app.yml                    # install jumpserver with docker-compose
#
# To replace domain name:
#   sed -ie 's/jump.pigsty/yourdomain.com/g' pigsty.yml
#
# Default Credential:
#   admin / ChangeMe

all:
  children:

    # the jumpserver application
    jumpserver:
      hosts: { 10.10.10.10: {} }
      vars:
        app: jumpserver   # specify app name to be installed (in the apps)
        apps:             # define all applications
          jumpserver:     # app name, should have corresponding ~/pigsty/app/jumpserver folder
            file:         # persistent directories to be created
              - { path: /data/jumpserver                 ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/core            ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/core/data       ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/core/data/logs  ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/certs           ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/koko            ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/koko/data       ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/lion            ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/lion/data       ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/chen            ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/chen/data       ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/nginx           ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/nginx/data      ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/nginx/data/logs ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/redis           ,state: directory ,mode: 0755 }
              - { path: /data/jumpserver/redis/data      ,state: directory ,mode: 0755 }
            conf:         # override /opt/jumpserver/.env config file

              # replace with your domain
              DOMAINS: '10.10.10.10:8080,10.10.10.10,jump.pigsty'

              # image / version
              REGISTRY: docker.io
              JUMPSERVER_VERSION: v4.10.16-ce
              REDIS_VERSION: 7.4.6-bookworm

              # fixed Docker bridge; containers reach host PG through host IP/VIP
              JUMPSERVER_DATA: /data/jumpserver
              VOLUME_DIR: /data/jumpserver
              DOCKER_SUBNET: 192.168.250.0/24
              REDIS_IP: 192.168.250.2
              CELERY_IP: 192.168.250.3
              CORE_IP: 192.168.250.4
              LION_IP: 192.168.250.5
              CHEN_IP: 192.168.250.6
              KOKO_IP: 192.168.250.7
              WEB_IP: 192.168.250.8

              # IMPORTANT: generate once and never change after production data exists
              SECRET_KEY: ChangeMeSecretKeyMustBeKeptForever0123456789ABCDEF
              BOOTSTRAP_TOKEN: ChangeMeBootstrapToken2026

              # database credentials; DB_PASSWORD must not contain single or double quotes
              DB_ENGINE: postgresql
              DB_HOST: 10.10.10.10
              DB_PORT: 5432
              DB_USER: jumpserver
              DB_PASSWORD: DBUser.JumpServer
              DB_NAME: jumpserver

              # local Redis container in app/jumpserver/docker-compose.yml
              # use a fixed bridge IP to avoid Docker DNS resolution races in JumpServer workers
              REDIS_HOST: 192.168.250.2
              REDIS_PORT: 6379
              REDIS_PASSWORD: Redis.JumpServer

              # access and component settings
              HTTP_PORT: 8080
              SSH_PORT: 2222
              CLIENT_MAX_BODY_SIZE: 4096m
              CORE_HOST: http://192.168.250.4:8080
              PERIOD_TASK_ENABLED: true
              SESSION_EXPIRE_AT_BROWSER_CLOSE: false

              USE_LB: 1
              USE_IPV6: 0
              USE_XPACK: 0
              LOG_LEVEL: ERROR
              TZ: Asia/Shanghai
              CURRENT_VERSION: v4.10.16-ce
              CORE_WORKER: 2
              CELERY_WORKER_COUNT: 2

    # the jumpserver database: single-node starter
    pg-jumpserver:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-jumpserver
        pg_extensions: []  # JumpServer itself requires no PostgreSQL extension
        pg_users:
          - { name: jumpserver ,password: DBUser.JumpServer ,pgbouncer: true ,pool_mode: session ,roles: [ dbrole_admin ] ,comment: admin user for jumpserver service }
        pg_databases:
          - { name: jumpserver ,owner: jumpserver ,comment: jumpserver main database }
        pg_hba_rules:
          - { user: jumpserver ,db: jumpserver ,addr: 192.168.250.0/24 ,auth: pwd ,order: 560 ,title: 'allow jumpserver access from docker bridge' }
        pgb_hba_rules:
          - { user: jumpserver ,db: jumpserver ,addr: 192.168.250.0/24 ,auth: pwd ,order: 390 ,title: 'allow jumpserver pgbouncer access from docker bridge' }
        pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ] # make a full backup every 1am

    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    #minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    pg_version: 18                    # JumpServer 4.x requires PostgreSQL >= 16
    pg_packages: [ pgsql-main, pgsql-common ]

    docker_enabled: true              # enable docker on app group
    #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:[email protected]
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home: { domain: i.pigsty }
      jumpserver:                     # nginx server config for jumpserver
        domain: jump.pigsty           # REPLACE WITH YOUR OWN DOMAIN!
        endpoint: "10.10.10.10:8080"  # jumpserver web endpoint: IP:PORT
        websocket: true               # add websocket support
        certbot: jump.pigsty          # certbot cert name, apply with `make cert`

    repo_enabled: false
    node_repo_modules: node,infra,pgsql

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

  • Creates persistent directories under /data/jumpserver for Core, Koko, Lion, Chen, Nginx, and Redis
  • Uses the fixed Docker subnet 192.168.250.0/24 with matching PostgreSQL and PgBouncer HBA rules
  • Creates the pg-jumpserver cluster and matching jumpserver database/service account
  • Runs Redis inside the application Compose stack
  • Proxies jump.pigsty to 10.10.10.10:8080

Replace SECRET_KEY, BOOTSTRAP_TOKEN, Redis/database passwords, and the domain before deployment. Once production data exists, SECRET_KEY must remain stable.

7.38 - demo/bare

Minimal readable configuration declaring only INFRA, ETCD, and single-node PostgreSQL

demo/bare is Pigsty’s smallest configuration example. It keeps only three core groups and three global parameters to show a working inventory skeleton.


Overview

  • Config Name: demo/bare
  • Node Count: Single node
  • Modules: INFRA, ETCD, PGSQL
  • Related: meta, slim
./configure -c demo/bare [-i <primary_ip>]

Content

Source: pigsty/conf/demo/bare.yml

---
all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }
  vars:
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default
...

Explanation

This template relies on Pigsty defaults and defines no business users, databases, extensions, backup policy, or security hardening. Use it to learn configuration hierarchy or as a minimal customization base; explicitly add passwords, HBA rules, backup, and safeguards for a real environment.

7.39 - demo/el

Configuration template optimized for Enterprise Linux (RHEL/Rocky/Alma)

The demo/el configuration template is optimized for Enterprise Linux family distributions (RHEL, Rocky Linux, Alma Linux, Oracle Linux).


Overview

  • Config Name: demo/el
  • Node Count: Single node
  • Description: Enterprise Linux optimized configuration template
  • OS Distro: el8, el9, el10
  • OS Arch: x86_64, aarch64
  • Related: meta, demo/debian

Usage:

./configure -c demo/el [-i <primary_ip>]

Content

Source: pigsty/conf/demo/el.yml

---
#==============================================================#
# File      :   el.yml
# Desc      :   Default parameters for EL System in Pigsty
# Ctime     :   2020-05-22
# Mtime     :   2026-08-02
# Docs      :   https://pigsty.io/docs/conf/el
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


#==============================================================#
#                        Sandbox (4-node)                      #
#==============================================================#
# admin user : vagrant  (nopass ssh & sudo already set)        #
# 1.  meta    :    10.10.10.10     (2 Core | 4GB)    pg-meta   #
# 2.  node-1  :    10.10.10.11     (1 Core | 1GB)    pg-test-1 #
# 3.  node-2  :    10.10.10.12     (1 Core | 1GB)    pg-test-2 #
# 4.  node-3  :    10.10.10.13     (1 Core | 1GB)    pg-test-3 #
# (replace these ip if your 4-node env have different ip addr) #
# VIP 2: (l2 vip is available inside same LAN )                #
#     pg-meta --->  10.10.10.2 ---> 10.10.10.10                #
#     pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}          #
#==============================================================#


all:

  ##################################################################
  #                            CLUSTERS                            #
  ##################################################################
  # meta nodes, nodes, pgsql, redis, pgsql clusters are defined as
  # k:v pair inside `all.children`. Where the key is cluster name
  # and value is cluster definition consist of two parts:
  # `hosts`: cluster members ip and instance level variables
  # `vars` : cluster level variables
  ##################################################################
  children:                                 # groups definition

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    #----------------------------------#
    # pgsql cluster: pg-meta (CMDB)    #
    #----------------------------------#
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
      vars:
        pg_cluster: pg-meta

        # define business databases here: https://pigsty.io/docs/pgsql/config/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g: files/)
            schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - { name: vector }            # install pgvector extension on this database by default
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_reserve: 32               # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_connlimit: 100            # optional, max database connections at database level, default 100
          #- { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
          #- { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          #- { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
          #- { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          #- { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }

        # define business users here: https://pigsty.io/docs/pgsql/config/user
        pg_users:                           # define business users/roles on this cluster, array of user definition
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
            pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
            comment: pigsty admin user      # optional, comment string for this user/role
            roles: [ dbrole_admin ]         # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
            #login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create database? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database}
          #- {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database   }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database  }
          #- {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service      }
          #- {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service    }

        # define business service here: https://pigsty.io/docs/pgsql/service
        pg_services:                        # extra services in addition to pg_default_services, array of service definition
          # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
          - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
            port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
            ip: "*"                         # optional, service bind ip address, `*` for all ip by default
            selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
            dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
            check: /sync                    # optional, health check url path, / by default
            backup: "[? pg_role == `primary`]"  # backup server selector
            maxconn: 3000                   # optional, max allowed front-end connection
            balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
            #options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

        # define pg extensions: https://pigsty.io/docs/pgsql/ext/
        pg_libs: 'pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
        #pg_extensions: [] # extensions to be installed on this cluster

        # define HBA rules here: https://pigsty.io/docs/pgsql/config/hba
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}

        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24

        pg_crontab:  # make a full backup 1 am everyday
          - '00 01 * * * /pg/bin/pg-backup full'

    #----------------------------------#
    # pgsql cluster: pg-test (3 nodes) #
    #----------------------------------#
    # pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}
    pg-test:                          # define the new 3-node cluster pg-test
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
        10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
        10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
      vars:
        pg_cluster: pg-test           # define pgsql cluster name
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: test }] # create a database and user named 'test'
        node_tune: tiny
        pg_conf: tiny.yml
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'

    #----------------------------------#
    # redis ms, sentinel, native cluster
    #----------------------------------#
    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  ####################################################################
  #                             VARS                                 #
  ####################################################################
  vars:                               # global variables


    #================================================================#
    #                         VARS: INFRA                            #
    #================================================================#

    #-----------------------------------------------------------------
    # META
    #-----------------------------------------------------------------
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    language: en                      # default language: en, zh
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    #-----------------------------------------------------------------
    # CA
    #-----------------------------------------------------------------
    ca_create: true                   # create ca if not exists? or just abort
    ca_cn: pigsty-ca                  # ca common name, fixed as pigsty-ca
    cert_validity: 7300d              # cert validity, 20 years by default

    #-----------------------------------------------------------------
    # INFRA_IDENTITY
    #-----------------------------------------------------------------
    #infra_seq: 1                     # infra node identity, explicitly required
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
    infra_data: /data/infra           # default data path for infrastructure data
    infra_services:                   # home page navigation entries
      - { name: Metrics            ,url: '/vmetrics/vmui/'         ,desc: 'VictoriaMetrics Query UI'    ,icon: metrics  ,name_cn: '指标查询' ,desc_cn: 'VictoriaMetrics 指标查询界面' }
      - { name: Logs               ,url: '/vlogs/select/vmui/'     ,desc: 'VictoriaLogs Query UI'       ,icon: logs     ,name_cn: '日志查询' ,desc_cn: 'VictoriaLogs 日志查询界面' }
      - { name: Traces             ,url: '/vtraces/select/vmui/'   ,desc: 'VictoriaTraces Query UI'     ,icon: traces   ,name_cn: '链路追踪' ,desc_cn: 'VictoriaTraces 链路查询界面' }
      - { name: Monitor Targets    ,url: '/vmetrics/targets'       ,desc: 'Prometheus Scrape Targets'   ,icon: target   ,name_cn: '监控目标' ,desc_cn: 'VictoriaMetrics 监控对象列表' }
      - { name: Alert Rules        ,url: '/vmalert/vmalert/groups' ,desc: 'VMAlert alert/record Rules'  ,icon: alert    ,name_cn: '告警规则' ,desc_cn: 'VMAlert 告警规则管理' }
      - { name: Alert Manager      ,url: '/alertmgr/#/alerts'      ,desc: 'Alert Manage & Silence'      ,icon: alertmgr ,name_cn: '告警管理' ,desc_cn: 'AlertManager 告警管理与屏蔽' }
      - { name: CA Certificate     ,url: '/ca.crt'                 ,desc: 'Self-Signed CA Certificate'  ,icon: lock     ,name_cn: 'CA 证书'  ,desc_cn: 'Pigsty 自签CA根证书' }
      - { name: Software Repo      ,url: '/pigsty'                 ,desc: 'Local YUM/APT Repository'    ,icon: package  ,name_cn: '软件仓库' ,desc_cn: '本地 YUM/APT 软件源' }
      - { name: Explain Visualizer ,url: '/pev'                    ,desc: 'Postgres EXPLAIN Visualizer' ,icon: search   ,name_cn: '执行计划' ,desc_cn: 'PG 执行计划可视化工具' }
    infra_extra_services: []          # extra services to be added on infra home page

    #-----------------------------------------------------------------
    # REPO
    #-----------------------------------------------------------------
    repo_enabled: true                # create a yum repo on this infra node?
    repo_home: /www                   # repo home dir, `/www` by default
    repo_name: pigsty                 # repo name, pigsty by default
    repo_endpoint: http://${admin_ip}:80 # access point to this repo by domain or ip:port
    repo_remove: true                 # remove existing upstream repo
    repo_modules: infra,node,pgsql    # which repo modules are installed in repo_upstream
    repo_upstream:                    # where to download
      - { name: pigsty-local   ,description: 'Pigsty Local'       ,module: local   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://${admin_ip}/pigsty'  } ,meta: { module_hotfixes: 1 }} # used by intranet nodes
      - { name: pigsty-infra   ,description: 'Pigsty INFRA'       ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/infra/$basearch' ,china: 'https://repo.pigsty.cc/yum/infra/$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pigsty-pgsql   ,description: 'Pigsty PGSQL'       ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch' ,china: 'https://repo.pigsty.cc/yum/pgsql/el$releasever.$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: nginx          ,description: 'Nginx Repo'         ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://nginx.org/packages/rhel/$releasever/$basearch/' } ,meta: { module_hotfixes: 1 }}
      - { name: docker-ce      ,description: 'Docker CE'          ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/centos/$releasever/$basearch/stable'    ,china: 'https://mirrors.cloud.tencent.com/docker-ce/linux/centos/$releasever/$basearch/stable https://repo.huaweicloud.com/docker-ce/linux/centos/$releasever/$basearch/stable https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable' ,europe: 'https://mirrors.xtom.de/docker-ce/linux/centos/$releasever/$basearch/stable' }}
      - { name: baseos         ,description: 'EL 8+ BaseOS'       ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/BaseOS/$basearch/os/'     ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/BaseOS/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/BaseOS/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/BaseOS/$basearch/os/'         ,europe: 'https://mirrors.xtom.de/rocky/$releasever/BaseOS/$basearch/os/'     }}
      - { name: appstream      ,description: 'EL 8+ AppStream'    ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/AppStream/$basearch/os/'  ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/AppStream/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/AppStream/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/AppStream/$basearch/os/'      ,europe: 'https://mirrors.xtom.de/rocky/$releasever/AppStream/$basearch/os/'  }}
      - { name: extras         ,description: 'EL 8+ Extras'       ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/extras/$basearch/os/'     ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/extras/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/extras/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/extras/$basearch/os/'         ,europe: 'https://mirrors.xtom.de/rocky/$releasever/extras/$basearch/os/'     }}
      - { name: powertools     ,description: 'EL 8 PowerTools'    ,module: node    ,releases: [8     ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/PowerTools/$basearch/os/' ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/PowerTools/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/PowerTools/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/PowerTools/$basearch/os/'     ,europe: 'https://mirrors.xtom.de/rocky/$releasever/PowerTools/$basearch/os/' }}
      - { name: crb            ,description: 'EL 9 CRB'           ,module: node    ,releases: [  9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/CRB/$basearch/os/'        ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/CRB/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/CRB/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/CRB/$basearch/os/'            ,europe: 'https://mirrors.xtom.de/rocky/$releasever/CRB/$basearch/os/'        }}
      - { name: epel           ,description: 'EL 8+ EPEL'         ,module: node    ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://mirrors.edge.kernel.org/fedora-epel/$releasever/Everything/$basearch/' ,china: 'https://mirrors.cloud.tencent.com/epel/$releasever/Everything/$basearch/ https://repo.huaweicloud.com/epel/$releasever/Everything/$basearch/ https://mirrors.aliyun.com/epel/$releasever/Everything/$basearch/'         ,europe: 'https://mirrors.xtom.de/epel/$releasever/Everything/$basearch/'     }}
      - { name: epel           ,description: 'EL 10 EPEL'         ,module: node    ,releases: [    10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://mirrors.edge.kernel.org/fedora-epel/$releasever/Everything/$basearch/'   ,china: 'https://mirrors.cloud.tencent.com/epel/$releasever/Everything/$basearch/ https://repo.huaweicloud.com/epel/$releasever/Everything/$basearch/ https://mirrors.aliyun.com/epel/$releasever/Everything/$basearch/'       ,europe: 'https://mirrors.xtom.de/epel/$releasever/Everything/$basearch/'     }}
      - { name: pgdg-common    ,description: 'PostgreSQL Common'  ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/common/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg14         ,description: 'PostgreSQL 14'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/14/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/14/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg15         ,description: 'PostgreSQL 15'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/15/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/15/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg16         ,description: 'PostgreSQL 16'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/16/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/16/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg17         ,description: 'PostgreSQL 17'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/17/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg18         ,description: 'PostgreSQL 18'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/18/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/18/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg-beta      ,description: 'PostgreSQL Testing' ,module: beta    ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/testing/19/redhat/rhel-$releasever-$basearch'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg-beta      ,description: 'PostgreSQL Testing' ,module: beta    ,releases: [  9,10] ,arch: [        aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/testing/19/redhat/rhel-$releasever-$basearch'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg-extras    ,description: 'PostgreSQL Extra'   ,module: extra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/extras/redhat/rhel-$releasever-$basearch'      ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/extras/redhat/rhel-$releasever-$basearch'      ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch'      } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg14-nonfree ,description: 'PostgreSQL 14+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/non-free/14/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg15-nonfree ,description: 'PostgreSQL 15+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/non-free/15/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg16-nonfree ,description: 'PostgreSQL 16+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/non-free/16/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg17-nonfree ,description: 'PostgreSQL 17+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/non-free/17/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg18-nonfree ,description: 'PostgreSQL 18+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch https://repo.pigsty.cc/yum/pgdg/non-free/18/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: timescaledb    ,description: 'TimescaleDB'        ,module: extra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/timescale/timescaledb/el/$releasever/$basearch'  }}
      - { name: percona        ,description: 'Percona TDE'        ,module: percona ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/percona/el$releasever.$basearch' ,china: 'https://repo.pigsty.cc/yum/percona/el$releasever.$basearch' ,origin: 'http://repo.percona.com/ppg-18.4/yum/release/$releasever/RPMS/$basearch'  } ,meta: { module_hotfixes: 1 }}
      - { name: wiltondb       ,description: 'WiltonDB'           ,module: mssql   ,releases: [8,9   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/mssql/el$releasever.$basearch', china: 'https://repo.pigsty.cc/yum/mssql/el$releasever.$basearch' , origin: 'https://download.copr.fedorainfracloud.org/results/wiltondb/wiltondb/epel-$releasever-$basearch/' }}
      - { name: groonga        ,description: 'Groonga'            ,module: groonga ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.groonga.org/almalinux/$releasever/$basearch/' }}
      - { name: mysql          ,description: 'MySQL 8.4 LTS'      ,module: mysql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mysql.com/yum/mysql-8.4-community/el/$releasever/$basearch/' } ,meta: { module_hotfixes: 1 }}
      - { name: mongo          ,description: 'MongoDB'            ,module: mongo   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/8.0/$basearch/' }}
      - { name: redis          ,description: 'Redis'              ,module: redis   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://rpmfind.net/linux/remi/enterprise/$releasever/redis72/$basearch/' } ,meta: { module_hotfixes: 1 }}
      - { name: grafana        ,description: 'Grafana'            ,module: grafana ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://rpm.grafana.com', china: 'https://mirrors.cloud.tencent.com/grafana/yum/rpm/' }}
      - { name: kubernetes     ,description: 'Kubernetes'         ,module: kube    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://pkgs.k8s.io/core:/stable:/v1.36/rpm/', china: 'https://mirrors.ustc.edu.cn/kubernetes/core:/stable:/v1.36/rpm/' }}
      - { name: gitlab-ee      ,description: 'Gitlab EE'          ,module: gitlab  ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ee/el/$releasever/$basearch' }}
      - { name: gitlab-ce      ,description: 'Gitlab CE'          ,module: gitlab  ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ce/el/$releasever/$basearch' }}
      - { name: clickhouse     ,description: 'ClickHouse'         ,module: click   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.clickhouse.com/rpm/stable/', china: 'https://repo.huaweicloud.com/clickhouse/rpm/stable/' }}

    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, node-package3, pgsql-utility, extra-modules ]
    repo_extra_packages: [ pgsql-main ]
    repo_url_packages: []

    #-----------------------------------------------------------------
    # INFRA_PACKAGE
    #-----------------------------------------------------------------
    infra_packages:                   # packages to be installed on infra nodes
      - grafana,grafana-plugins,grafana-victorialogs-ds,grafana-victoriametrics-ds,victoria-metrics,victoria-logs,victoria-traces,vmutils,vlogscli,alertmanager
      - node-exporter,blackbox-exporter,nginx-exporter,pg-exporter,pev2,nginx,dnsmasq,ansible,etcd,python3-requests,redis,mcli,restic,certbot,python3-certbot-nginx

    #-----------------------------------------------------------------
    # NGINX
    #-----------------------------------------------------------------
    nginx_enabled: true               # enable nginx on this infra node?
    nginx_clean: false                # clean existing nginx config during init?
    nginx_exporter_enabled: true      # enable nginx_exporter on this infra node?
    nginx_exporter_port: 9113         # nginx_exporter listen port, 9113 by default
    nginx_sslmode: enable             # nginx ssl mode? disable,enable,enforce
    nginx_cert_validity: 397d         # nginx self-signed cert validity, 397d by default
    nginx_home: /www                  # nginx content dir, `/www` by default (soft link to nginx_data)
    nginx_data: /data/nginx           # nginx actual data dir, /data/nginx by default
    nginx_users: { admin : pigsty }   # nginx basic auth users: name and pass dict
    nginx_port: 80                    # nginx listen port, 80 by default
    nginx_ssl_port: 443               # nginx ssl listen port, 443 by default
    certbot_sign: false               # sign nginx cert with certbot during setup?
    certbot_email: [email protected]     # certbot email address, used for free ssl
    certbot_options: ''               # certbot extra options

    #-----------------------------------------------------------------
    # DNS
    #-----------------------------------------------------------------
    dns_enabled: true                 # setup dnsmasq on this infra node?
    dns_port: 53                      # dns server listen port, 53 by default
    dns_records:                      # dynamic dns records resolved by dnsmasq
      - "${admin_ip} i.pigsty"
      - "${admin_ip} m.pigsty supa.pigsty api.pigsty adm.pigsty cli.pigsty ddl.pigsty"

    #-----------------------------------------------------------------
    # VICTORIA
    #-----------------------------------------------------------------
    vmetrics_enabled: true            # enable victoria-metrics on this infra node?
    vmetrics_clean: false             # whether clean existing victoria metrics data during init?
    vmetrics_port: 8428               # victoria-metrics listen port, 8428 by default
    vmetrics_scrape_interval: 10s     # victoria global scrape interval, 10s by default
    vmetrics_scrape_timeout: 8s       # victoria global scrape timeout, 8s by default
    vmetrics_options: >-
      -retentionPeriod=15d
      -promscrape.fileSDCheckInterval=5s
    vlogs_enabled: true               # enable victoria-logs on this infra node?
    vlogs_clean: false                # clean victoria-logs data during init?
    vlogs_port: 9428                  # victoria-logs listen port, 9428 by default
    vlogs_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
      -insert.maxLineSizeBytes=1MB
      -search.maxQueryDuration=120s
    vtraces_enabled: true             # enable victoria-traces on this infra node?
    vtraces_clean: false                # clean victoria-trace data during inti?
    vtraces_port: 10428               # victoria-traces listen port, 10428 by default
    vtraces_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
    vmalert_enabled: true             # enable vmalert on this infra node?
    vmalert_port: 8880                # vmalert listen port, 8880 by default
    vmalert_options: ''              # vmalert extra server options

    #-----------------------------------------------------------------
    # PROMETHEUS
    #-----------------------------------------------------------------
    blackbox_enabled: true            # setup blackbox_exporter on this infra node?
    blackbox_port: 9115               # blackbox_exporter listen port, 9115 by default
    blackbox_options: ''              # blackbox_exporter extra server options
    alertmanager_enabled: true        # setup alertmanager on this infra node?
    alertmanager_port: 9059           # alertmanager listen port, 9059 by default
    alertmanager_options: ''          # alertmanager extra server options
    exporter_metrics_path: /metrics   # exporter metric path, `/metrics` by default

    #-----------------------------------------------------------------
    # GRAFANA
    #-----------------------------------------------------------------
    grafana_enabled: true             # enable grafana on this infra node?
    grafana_port: 3000                # default listen port for grafana
    grafana_clean: false              # clean grafana data during init?
    grafana_admin_username: admin     # grafana admin username, `admin` by default
    grafana_admin_password: pigsty    # grafana admin password, `pigsty` by default
    grafana_auth_proxy: false         # enable grafana auth proxy?
    grafana_pgurl: ''                 # external postgres database url for grafana if given
    grafana_view_password: DBUser.Viewer # password for grafana meta pg datasource


    #================================================================#
    #                         VARS: NODE                             #
    #================================================================#

    #-----------------------------------------------------------------
    # NODE_IDENTITY
    #-----------------------------------------------------------------
    #nodename:           # [INSTANCE] # node instance identity, use hostname if missing, optional
    node_cluster: nodes   # [CLUSTER] # node cluster identity, use 'nodes' if missing, optional
    nodename_overwrite: true          # overwrite node's hostname with nodename?
    nodename_exchange: false          # exchange nodename among play hosts?
    node_id_from_pg: true             # use postgres identity as node identity if applicable?

    #-----------------------------------------------------------------
    # NODE_DNS
    #-----------------------------------------------------------------
    node_write_etc_hosts: true        # modify `/etc/hosts` on target node?
    node_default_etc_hosts:           # static dns records in `/etc/hosts`
      - "${admin_ip} i.pigsty"
    node_etc_hosts: []                # extra static dns records in `/etc/hosts`
    node_dns_method: add              # how to handle dns servers: add,none,overwrite
    node_dns_servers: ['${admin_ip}'] # dynamic nameserver in `/etc/resolv.conf`
    node_dns_options:                 # dns resolv options in `/etc/resolv.conf`
      - options single-request-reopen timeout:1

    #-----------------------------------------------------------------
    # NODE_PACKAGE
    #-----------------------------------------------------------------
    node_repo_modules: local          # upstream repo to be added on node, local by default
    node_repo_remove: true            # remove existing repo on node?
    node_packages: [openssh-server]   # packages to be installed current nodes with latest version
    node_default_packages:            # default packages to be installed on all nodes
      - lz4,unzip,bzip2,pv,jq,git,ncdu,make,patch,bash,lsof,wget,uuid,tuned,nvme-cli,numactl,sysstat,iotop,htop,rsync,tcpdump
      - python3,python3-pip,socat,lrzsz,net-tools,ipvsadm,telnet,ca-certificates,openssl,keepalived,etcd,haproxy,chrony,pig
      - zlib,yum,audit,bind-utils,readline,vim-minimal,node-exporter,grubby,openssh-server,openssh-clients,chkconfig,vector
    node_uv_env: /data/venv           # uv venv path, empty string to skip
    node_pip_packages: ''             # pip packages to install in uv venv

    #-----------------------------------------------------------------
    # NODE_SEC
    #-----------------------------------------------------------------
    node_selinux_mode: permissive     # set selinux mode: enforcing,permissive,disabled
    node_firewall_mode: zone          # firewall mode: zone (default), off (disable), none (skip & self-managed)
    node_firewall_intranet:           # which intranet cidr considered as internal network
      - 10.0.0.0/8
      - 192.168.0.0/16
      - 172.16.0.0/12
    node_firewall_public_port:        # expose these ports to public network in (zone, strict) mode
      - 22                            # enable ssh access
      - 80                            # enable http access
      - 443                           # enable https access
      - 5432                          # enable postgres access

    #-----------------------------------------------------------------
    # NODE_TUNE
    #-----------------------------------------------------------------
    node_disable_numa: false          # disable node numa, reboot required
    node_disable_swap: false          # disable node swap, use with caution
    node_static_network: true         # preserve dns resolver settings after reboot
    node_disk_prefetch: false         # setup disk prefetch on HDD to increase performance
    node_kernel_modules: [ softdog, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]
    node_hugepage_count: 0            # number of 2MB hugepage, take precedence over ratio
    node_hugepage_ratio: 0            # node mem hugepage ratio, 0 disable it by default
    node_overcommit_ratio: 0          # node mem overcommit ratio, 0 disable it by default
    node_tune: oltp                   # node tuned profile: none,oltp,olap,crit,tiny
    node_sysctl_params:              # sysctl parameters in k:v format in addition to tuned
      fs.nr_open: 8388608

    #-----------------------------------------------------------------
    # NODE_ADMIN
    #-----------------------------------------------------------------
    node_data: /data                  # node main data directory, `/data` by default
    node_admin_enabled: true          # create a admin user on target node?
    node_admin_uid: 88                # uid and gid for node admin user
    node_admin_username: dba          # name of node admin user, `dba` by default
    node_admin_sudo: nopass           # admin sudo privilege, all,nopass. nopass by default
    node_admin_ssh_exchange: true     # exchange admin ssh key among node cluster
    node_admin_pk_current: true       # add current user's ssh pk to admin authorized_keys
    node_admin_pk_list: []            # ssh public keys to be added to admin user
    node_aliases: {}                  # extra shell aliases to be added, k:v dict

    #-----------------------------------------------------------------
    # NODE_TIME
    #-----------------------------------------------------------------
    node_timezone: ''                 # setup node timezone, empty string to skip
    node_ntp_enabled: true            # enable chronyd time sync service?
    node_ntp_servers:                 # ntp servers in `/etc/chrony.conf`
      - pool pool.ntp.org iburst
    node_crontab_overwrite: true      # overwrite or append to `/etc/crontab`?
    node_crontab: [ ]                 # crontab entries in `/etc/crontab`

    #-----------------------------------------------------------------
    # NODE_VIP
    #-----------------------------------------------------------------
    vip_enabled: false                # enable vip on this node cluster?
    # vip_address:         [IDENTITY] # node vip address in ipv4 format, required if vip is enabled
    # vip_vrid:            [IDENTITY] # required, integer, 1-254, should be unique among same VLAN
    vip_role: backup                  # optional, `master|backup`, backup by default, use as init role
    vip_preempt: false                # optional, `true/false`, false by default, enable vip preemption
    vip_interface: auto               # node vip network interface to listen, `auto` by default
    vip_dns_suffix: ''                # node vip dns name suffix, empty string by default
    vip_auth_pass: ''                 # empty to use '<cls>-<vrid>' as the default
    vip_exporter_port: 9650           # keepalived exporter listen port, 9650 by default

    #-----------------------------------------------------------------
    # HAPROXY
    #-----------------------------------------------------------------
    haproxy_enabled: true             # enable haproxy on this node?
    haproxy_clean: false              # cleanup all existing haproxy config?
    haproxy_reload: true              # reload haproxy after config?
    haproxy_auth_enabled: true        # enable authentication for haproxy admin page
    haproxy_admin_username: admin     # haproxy admin username, `admin` by default
    haproxy_admin_password: pigsty    # haproxy admin password, `pigsty` by default
    haproxy_exporter_port: 9101       # haproxy admin/exporter port, 9101 by default
    haproxy_client_timeout: 24h       # client side connection timeout, 24h by default
    haproxy_server_timeout: 24h       # server side connection timeout, 24h by default
    haproxy_services: []              # list of haproxy service to be exposed on node

    #-----------------------------------------------------------------
    # NODE_EXPORTER
    #-----------------------------------------------------------------
    node_exporter_enabled: true       # setup node_exporter on this node?
    node_exporter_port: 9100          # node exporter listen port, 9100 by default
    node_exporter_options: '--no-collector.softnet --no-collector.nvme --collector.tcpstat --collector.processes'

    #-----------------------------------------------------------------
    # VECTOR
    #-----------------------------------------------------------------
    vector_enabled: true              # enable vector log collector?
    vector_clean: false               # purge vector data dir during init?
    vector_data: /data/vector         # vector data dir, /data/vector by default
    vector_port: 9598                 # vector metrics port, 9598 by default
    vector_read_from: beginning       # vector read from beginning or end
    vector_log_endpoint: [ infra ]    # if defined, sending vector log to this endpoint.


    #================================================================#
    #                        VARS: DOCKER                            #
    #================================================================#
    docker_enabled: false             # enable docker on this node?
    docker_data: /data/docker         # docker data directory, /data/docker by default
    docker_storage_driver: overlay2   # docker storage driver, can be zfs, btrfs
    docker_cgroups_driver: systemd    # docker cgroup fs driver: cgroupfs,systemd
    docker_registry_mirrors: []       # docker registry mirror list
    docker_exporter_port: 9323        # docker metrics exporter port, 9323 by default
    docker_image: []                  # docker image to be pulled after bootstrap
    docker_image_cache: /tmp/docker/*.tgz # docker image cache glob pattern

    #================================================================#
    #                         VARS: ETCD                             #
    #================================================================#
    #etcd_seq: 1                      # etcd instance identifier, explicitly required
    etcd_cluster: etcd                # etcd cluster & group name, etcd by default
    etcd_safeguard: false             # prevent purging running etcd instance?
    etcd_data: /data/etcd             # etcd data directory, /data/etcd by default
    etcd_port: 2379                   # etcd client port, 2379 by default
    etcd_peer_port: 2380              # etcd peer port, 2380 by default
    etcd_init: new                    # etcd initial cluster state, new or existing
    etcd_election_timeout: 1000       # etcd election timeout, 1000ms by default
    etcd_heartbeat_interval: 100      # etcd heartbeat interval, 100ms by default
    etcd_root_password: Etcd.Root     # etcd root password for RBAC, change it!


    #================================================================#
    #                         VARS: MINIO                            #
    #================================================================#
    #minio_seq: 1                     # minio instance identifier, REQUIRED
    #minio_cluster:                   # minio cluster identifier, REQUIRED (define in cluster vars)
    minio_user: minio                 # minio os user, `minio` by default
    minio_https: true                 # use https for minio, true by default
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
    minio_data: '/data/minio'         # minio data dir(s), use {x...y} to specify multi drivers
    #minio_volumes:                   # minio data volumes, override defaults if specified
    minio_domain: sss.pigsty          # minio external domain name, `sss.pigsty` by default
    minio_port: 9000                  # minio service port, 9000 by default
    minio_admin_port: 9001            # minio console port, 9001 by default
    minio_access_key: minioadmin      # root access key, `minioadmin` by default
    minio_secret_key: S3User.MinIO    # root secret key, `S3User.MinIO` by default
    minio_extra_vars: ''              # extra environment variables
    minio_provision: true             # run minio provisioning tasks?
    minio_alias: sss                  # alias name for local minio deployment
    #minio_endpoint: https://sss.pigsty:9000 # if not specified, overwritten by defaults
    minio_buckets:                    # list of minio bucket to be created
      - { name: pgsql }
      - { name: meta ,versioning: true }
      - { name: data }
    minio_users:                      # list of minio user to be created
      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }
    minio_safeguard: false            # prevent purging running minio instance?
    minio_rm_data: true               # purging minio data and config?
    minio_rm_pkg: false               # uninstall minio packages?


    #================================================================#
    #                         VARS: REDIS                            #
    #================================================================#
    #redis_cluster:        <CLUSTER> # redis cluster name, required identity parameter
    #redis_node: 1            <NODE> # redis node sequence number, node int id required
    #redis_instances: {}      <NODE> # redis instances definition on this redis node
    redis_fs_main: /data/redis        # redis main data directory, `/data/redis` by default
    redis_exporter_enabled: true      # install redis exporter on redis nodes?
    redis_exporter_port: 9121         # redis exporter listen port, 9121 by default
    redis_exporter_options: ''        # cli args and extra options for redis exporter
    redis_type: redis                 # redis implementation: redis or valkey
    redis_mode: standalone            # redis mode: standalone,cluster,sentinel
    redis_conf: redis.conf            # redis config template path, except sentinel
    redis_bind_address: '0.0.0.0'     # redis bind address, empty string will use host ip
    redis_max_memory: 1GB             # max memory used by each redis instance
    redis_mem_policy: allkeys-lru     # redis memory eviction policy
    redis_password: ''                # redis password, empty string will disable password
    redis_rdb_save: ['1200 1']        # redis rdb save directives, disable with empty list
    redis_aof_enabled: false          # enable redis append only file?
    redis_rename_commands: {}         # rename redis dangerous commands
    redis_cluster_replicas: 1         # replica number for one master in redis cluster
    redis_sentinel_monitor: []        # sentinel master list, works on sentinel cluster only
    redis_safeguard: false            # prevent purging running redis instance?
    redis_rm_data: true               # remove redis data dir?
    redis_rm_pkg: false               # uninstall selected engine & redis-exporter packages?


    #================================================================#
    #                         VARS: PGSQL                            #
    #================================================================#

    #-----------------------------------------------------------------
    # PG_IDENTITY
    #-----------------------------------------------------------------
    pg_mode: pgsql          #CLUSTER  # pgsql cluster mode: pgsql,citus,mssql,mysql,ivory,pgtde,polar,gpsql,agens,oriole,pgedge
    # pg_cluster:           #CLUSTER  # pgsql cluster name, required identity parameter
    # pg_seq: 0             #INSTANCE # pgsql instance seq number, required identity parameter
    # pg_role: replica      #INSTANCE # pgsql role, required, could be primary,replica,offline
    # pg_instances: {}      #INSTANCE # define multiple pg instances on node in `{port:ins_vars}` format
    # pg_upstream:          #INSTANCE # repl upstream ip addr for standby cluster or cascade replica
    # pg_shard:             #CLUSTER  # pgsql shard name, optional identity for sharding clusters
    # pg_group: 0           #CLUSTER  # pgsql shard index number, optional identity for sharding clusters
    # gp_role: master       #CLUSTER  # greenplum role of this cluster, could be master or segment
    pg_offline_query: false #INSTANCE # set to true to enable offline queries on this instance

    #-----------------------------------------------------------------
    # PG_BUSINESS
    #-----------------------------------------------------------------
    # postgres business object definition, overwrite in group vars
    pg_users: []                      # postgres business users
    pg_databases: []                  # postgres business databases
    pg_services: []                   # postgres business services
    pg_hba_rules: []                  # business hba rules for postgres
    pgb_hba_rules: []                 # business hba rules for pgbouncer
    pg_crontab: []                    # postgres crontab entries for dbsu
    # global credentials, overwrite in global vars
    pg_dbsu_password: ''              # dbsu password, empty string means no dbsu password by default
    pg_replication_username: replicator
    pg_replication_password: DBUser.Replicator
    pg_admin_username: dbuser_dba
    pg_admin_password: DBUser.DBA
    pg_monitor_username: dbuser_monitor
    pg_monitor_password: DBUser.Monitor

    #-----------------------------------------------------------------
    # PG_INSTALL
    #-----------------------------------------------------------------
    pg_dbsu: postgres                 # os dbsu name, postgres by default, better not change it
    pg_dbsu_uid: 26                   # os dbsu uid and gid, 26 for default postgres users and groups
    pg_dbsu_sudo: limit               # dbsu sudo privilege, none,limit,all,nopass. limit by default
    pg_dbsu_home: /var/lib/pgsql      # postgresql home directory, `/var/lib/pgsql` by default
    pg_dbsu_ssh_exchange: true        # exchange postgres dbsu ssh key among same pgsql cluster
    pg_version: 18                    # postgres major version to be installed, 18 by default
    pg_bin_dir: /usr/pgsql/bin        # postgres binary dir, `/usr/pgsql/bin` by default
    pg_log_dir: /pg/log/postgres      # postgres log dir, `/pg/log/postgres` by default
    pg_packages:                      # pg packages to be installed, alias can be used
      - pgsql-main pgsql-common
    pg_extensions: []                 # pg extensions to be installed, alias can be used

    #-----------------------------------------------------------------
    # PG_BOOTSTRAP
    #-----------------------------------------------------------------
    pg_data: /pg/data                 # postgres data directory, `/pg/data` by default
    pg_fs_main: /data/postgres        # postgres main data directory, `/data/postgres` by default
    pg_fs_backup: /data/backups       # postgres backup data directory, `/data/backups` by default
    pg_storage_type: SSD              # storage type for pg main data, SSD,HDD, SSD by default
    pg_dummy_filesize: 64MiB          # size of `/pg/dummy`, hold 64MB disk space for emergency use
    pg_listen: '0.0.0.0'              # postgres/pgbouncer listen addresses, comma separated list
    pg_port: 5432                     # postgres listen port, 5432 by default
    pg_localhost: /var/run/postgresql # postgres unix socket dir for localhost connection
    patroni_enabled: true             # if disabled, no postgres cluster will be created during init
    patroni_mode: default             # patroni working mode: default,pause,remove
    pg_namespace: /pg                 # top level key namespace in etcd, used by patroni & vip
    patroni_port: 8008                # patroni listen port, 8008 by default
    patroni_log_dir: /pg/log/patroni  # patroni log dir, `/pg/log/patroni` by default
    patroni_ssl_enabled: false        # secure patroni RestAPI communications with SSL?
    patroni_watchdog_mode: 'off'      # patroni watchdog mode: automatic,required,off. off by default
    patroni_username: postgres        # patroni restapi username, `postgres` by default
    patroni_password: Patroni.API     # patroni restapi password, `Patroni.API` by default
    pg_etcd_password: ''              # etcd password for this pg cluster, '' to use pg_cluster
    pg_primary_db: postgres           # primary database name, used by citus,etc... ,postgres by default
    pg_parameters: {}                 # extra parameters in postgresql.auto.conf
    pg_files: []                      # extra files to be copied to postgres data directory (e.g. license)
    pg_conf: oltp.yml                 # config template: oltp,olap,crit,tiny. `oltp.yml` by default
    pg_max_conn: auto                 # postgres max connections, `auto` will use recommended value
    pg_shared_buffer_ratio: 0.25      # postgres shared buffers ratio, 0.25 by default, 0.1~0.4
    pg_io_method: worker              # io method for postgres, auto,fsync,worker,io_uring, worker by default
    pg_rto: norm                      # shared rto mode for patroni & haproxy: fast,norm,safe,wide
    pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
      fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]
      norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]
      safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]
      wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]
    pg_rpo: 1048576                   # recovery point objective in bytes, `1MiB` at most by default
    pg_libs: 'pg_stat_statements, auto_explain'  # preloaded libraries, `pg_stat_statements,auto_explain` by default
    pg_delay: 0                       # replication apply delay for standby cluster leader
    pg_checksum: true                 # enable data checksum for postgres cluster?
    pg_pwd_enc: scram-sha-256         # password encryption algorithm
    pg_encoding: UTF8                 # database cluster encoding, `UTF8` by default
    pg_locale: C                      # database cluster local, `C` by default
    pg_lc_collate: C                  # database cluster collate, `C` by default
    pg_lc_ctype: C                    # database character type, `C` by default
    #pgsodium_key: ""                 # pgsodium key, 64 hex digit, default to sha256(pg_cluster)
    #pgsodium_getkey_script: ""       # pgsodium getkey script path, pgsodium_getkey by default

    #-----------------------------------------------------------------
    # PG_PROVISION
    #-----------------------------------------------------------------
    pg_provision: true                # provision postgres cluster after bootstrap
    pg_init: pg-init                  # provision init script for cluster template, `pg-init` by default
    pg_default_roles:                 # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,comment: system superuser }
      - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_privileges:            # default privileges when created by admin user
      - GRANT USAGE      ON SCHEMAS    TO  dbrole_readonly
      - GRANT SELECT     ON TABLES     TO  dbrole_readonly
      - GRANT SELECT     ON SEQUENCES  TO  dbrole_readonly
      - GRANT EXECUTE    ON FUNCTIONS  TO  dbrole_readonly
      - GRANT USAGE      ON SCHEMAS    TO  dbrole_offline
      - GRANT SELECT     ON TABLES     TO  dbrole_offline
      - GRANT SELECT     ON SEQUENCES  TO  dbrole_offline
      - GRANT EXECUTE    ON FUNCTIONS  TO  dbrole_offline
      - GRANT INSERT     ON TABLES     TO  dbrole_readwrite
      - GRANT UPDATE     ON TABLES     TO  dbrole_readwrite
      - GRANT DELETE     ON TABLES     TO  dbrole_readwrite
      - GRANT USAGE      ON SEQUENCES  TO  dbrole_readwrite
      - GRANT UPDATE     ON SEQUENCES  TO  dbrole_readwrite
      - GRANT TRUNCATE   ON TABLES     TO  dbrole_admin
      - GRANT REFERENCES ON TABLES     TO  dbrole_admin
      - GRANT TRIGGER    ON TABLES     TO  dbrole_admin
      - GRANT CREATE     ON SCHEMAS    TO  dbrole_admin
    pg_default_schemas: [ monitor ]   # default schemas to be created
    pg_default_extensions:            # default extensions to be created
      - { name: pg_stat_statements ,schema: monitor }
      - { name: pgstattuple        ,schema: monitor }
      - { name: pg_buffercache     ,schema: monitor }
      - { name: pageinspect        ,schema: monitor }
      - { name: pg_prewarm         ,schema: monitor }
      - { name: pg_visibility      ,schema: monitor }
      - { name: pg_freespacemap    ,schema: monitor }
      - { name: postgres_fdw       ,schema: public  }
      - { name: file_fdw           ,schema: public  }
      - { name: btree_gist         ,schema: public  }
      - { name: btree_gin          ,schema: public  }
      - { name: pg_trgm            ,schema: public  }
      - { name: intagg             ,schema: public  }
      - { name: intarray           ,schema: public  }
      - { name: pg_repack }
    pg_reload: true                   # reload postgres after hba changes
    pg_default_hba_rules:             # postgres default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
      - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
      - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
      - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
      - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
      - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
      - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin @ intranet nodes with pwd'      ,order: 450}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
      - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
      - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
      - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}
    pgb_default_hba_rules:            # pgbouncer default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
      - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
      - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
      - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
      - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

    #-----------------------------------------------------------------
    # PG_BACKUP
    #-----------------------------------------------------------------
    pgbackrest_enabled: true          # enable pgbackrest on pgsql host?
    pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log dir, `/pg/log/pgbackrest` by default
    pgbackrest_method: local          # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_init_backup: true      # take a full backup after pgbackrest is initialized?
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the the last 14 days

    #-----------------------------------------------------------------
    # PG_ACCESS
    #-----------------------------------------------------------------
    pgbouncer_enabled: true           # if disabled, pgbouncer will not be launched on pgsql host
    pgbouncer_port: 6432              # pgbouncer listen port, 6432 by default
    pgbouncer_log_dir: /pg/log/pgbouncer  # pgbouncer log dir, `/pg/log/pgbouncer` by default
    pgbouncer_auth_query: false       # query postgres to retrieve unlisted business users?
    pgbouncer_poolmode: transaction   # pooling mode: transaction,session,statement, transaction by default
    pgbouncer_sslmode: disable        # pgbouncer client ssl mode, disable by default
    pgbouncer_ignore_param: [ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]
    pg_weight: 100          #INSTANCE # relative load balance weight in service, 100 by default, 0-255
    pg_service_provider: ''           # dedicate haproxy node group name, or empty string for local nodes by default
    pg_default_service_dest: pgbouncer # default service destination if svc.dest='default'
    pg_default_services:              # postgres default service definitions
      - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
      - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
      - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
      - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
    pg_vip_enabled: false             # enable a l2 vip for pgsql primary? false by default
    pg_vip_address: 127.0.0.1/24      # vip address in `<ipv4>/<mask>` format, require if vip is enabled
    pg_vip_interface: auto            # vip network interface to listen, auto by default
    pg_dns_suffix: ''                 # pgsql dns suffix, '' by default
    pg_dns_target: auto               # auto, primary, vip, none, or ad hoc ip

    #-----------------------------------------------------------------
    # PG_MONITOR
    #-----------------------------------------------------------------
    pg_exporter_enabled: true              # enable pg_exporter on pgsql hosts?
    pg_exporter_config: pg_exporter.yml    # pg_exporter configuration file name
    pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter collector ttl stage in seconds, '1,10,60,300' by default
    pg_exporter_port: 9630                 # pg_exporter listen port, 9630 by default
    pg_exporter_params: 'sslmode=disable'  # extra url parameters for pg_exporter dsn
    pg_exporter_url: ''                    # overwrite auto-generate pg dsn if specified
    pg_exporter_auto_discovery: true       # enable auto database discovery? enabled by default
    pg_exporter_exclude_database: 'template0,template1,postgres' # csv of database that WILL NOT be monitored during auto-discovery
    pg_exporter_include_database: ''       # csv of database that WILL BE monitored during auto-discovery
    pg_exporter_connect_timeout: 200       # pg_exporter connect timeout in ms, 200 by default
    pg_exporter_options: ''                # overwrite extra options for pg_exporter
    pgbouncer_exporter_enabled: true       # enable pgbouncer_exporter on pgsql hosts?
    pgbouncer_exporter_port: 9631          # pgbouncer_exporter listen port, 9631 by default
    pgbouncer_exporter_url: ''             # overwrite auto-generate pgbouncer dsn if specified
    pgbouncer_exporter_options: ''         # overwrite extra options for pgbouncer_exporter
    pgbackrest_exporter_enabled: true      # enable pgbackrest_exporter on pgsql hosts?
    pgbackrest_exporter_port: 9854         # pgbackrest_exporter listen port, 9854 by default
    pgbackrest_exporter_options: >-
      --collect.interval=120
      --log.level=info

    #-----------------------------------------------------------------
    # PG_REMOVE
    #-----------------------------------------------------------------
    pg_safeguard: false               # stop pg_remove running if pg_safeguard is enabled, false by default
    pg_rm_data: true                  # remove postgres data during remove? true by default
    pg_rm_backup: true                # remove pgbackrest backup during primary remove? true by default
    pg_rm_pkg: true                   # uninstall postgres packages during remove? true by default

...

Explanation

The demo/el template is optimized for Enterprise Linux family distributions.

Supported Distributions:

  • RHEL 8/9/10
  • Rocky Linux 8/9/10
  • Alma Linux 8/9/10
  • Oracle Linux 8/9

Key Features:

  • Uses EPEL and PGDG repositories
  • Optimized for YUM/DNF package manager
  • Supports EL-specific package names

Use Cases:

  • Enterprise production environments (RHEL/Rocky/Alma recommended)
  • Long-term support and stability requirements
  • Environments using Red Hat ecosystem

7.40 - demo/debian

Configuration template optimized for Debian/Ubuntu

The demo/debian configuration template is optimized for Debian and Ubuntu distributions.


Overview

  • Config Name: demo/debian
  • Node Count: Single node
  • Description: Debian/Ubuntu optimized configuration template
  • OS Distro: d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta, demo/el

Usage:

./configure -c demo/debian [-i <primary_ip>]

Content

Source: pigsty/conf/demo/debian.yml

---
#==============================================================#
# File      :   debian.yml
# Desc      :   Default parameters for Debian/Ubuntu in Pigsty
# Ctime     :   2020-05-22
# Mtime     :   2026-08-02
# Docs      :   https://pigsty.io/docs/conf/debian
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


#==============================================================#
#                        Sandbox (4-node)                      #
#==============================================================#
# admin user : vagrant  (nopass ssh & sudo already set)        #
# 1.  meta    :    10.10.10.10     (2 Core | 4GB)    pg-meta   #
# 2.  node-1  :    10.10.10.11     (1 Core | 1GB)    pg-test-1 #
# 3.  node-2  :    10.10.10.12     (1 Core | 1GB)    pg-test-2 #
# 4.  node-3  :    10.10.10.13     (1 Core | 1GB)    pg-test-3 #
# (replace these ip if your 4-node env have different ip addr) #
# VIP 2: (l2 vip is available inside same LAN )                #
#     pg-meta --->  10.10.10.2 ---> 10.10.10.10                #
#     pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}          #
#==============================================================#


all:

  ##################################################################
  #                            CLUSTERS                            #
  ##################################################################
  # meta nodes, nodes, pgsql, redis, pgsql clusters are defined as
  # k:v pair inside `all.children`. Where the key is cluster name
  # and value is cluster definition consist of two parts:
  # `hosts`: cluster members ip and instance level variables
  # `vars` : cluster level variables
  ##################################################################
  children:                                 # groups definition

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    #----------------------------------#
    # pgsql cluster: pg-meta (CMDB)    #
    #----------------------------------#
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
      vars:
        pg_cluster: pg-meta

        # define business databases here: https://pigsty.io/docs/pgsql/config/db
        pg_databases:                       # define business databases on this cluster, array of database definition
          - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
            #state: create                  # optional, create|absent|recreate, create by default
            baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g: files/)
            schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
            extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
              - { name: vector }            # install pgvector extension on this database by default
            comment: pigsty meta database   # optional, comment string for this database
            #pgbouncer: true                # optional, add this database to pgbouncer database list? true by default
            #owner: postgres                # optional, database owner, current user if not specified
            #template: template1            # optional, which template to use, template1 by default
            #strategy: FILE_COPY            # optional, clone strategy: FILE_COPY or WAL_LOG (PG15+), default to PG's default
            #encoding: UTF8                 # optional, inherited from template / cluster if not defined (UTF8)
            #locale: C                      # optional, inherited from template / cluster if not defined (C)
            #lc_collate: C                  # optional, inherited from template / cluster if not defined (C)
            #lc_ctype: C                    # optional, inherited from template / cluster if not defined (C)
            #locale_provider: libc          # optional, locale provider: libc, icu, builtin (PG15+)
            #icu_locale: en-US              # optional, icu locale for icu locale provider (PG15+)
            #icu_rules: ''                  # optional, icu rules for icu locale provider (PG16+)
            #builtin_locale: C.UTF-8        # optional, builtin locale for builtin locale provider (PG17+)
            #tablespace: pg_default         # optional, default tablespace, pg_default by default
            #is_template: false             # optional, mark database as template, allowing clone by any user with CREATEDB privilege
            #allowconn: true                # optional, allow connection, true by default. false will disable connect at all
            #revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
            #register_datasource: true      # optional, register this database to grafana datasources? true by default
            #connlimit: -1                  # optional, database connection limit, default -1 disable limit
            #pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
            #pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
            #pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
            #pool_reserve: 32               # optional, pgbouncer pool size reserve at database level, default 32
            #pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
            #pool_connlimit: 100            # optional, max database connections at database level, default 100
          #- { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
          #- { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          #- { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
          #- { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          #- { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }

        # define business users here: https://pigsty.io/docs/pgsql/config/user
        pg_users:                           # define business users/roles on this cluster, array of user definition
          - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
            password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
            pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
            comment: pigsty admin user      # optional, comment string for this user/role
            roles: [ dbrole_admin ]         # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
            #login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
            #superuser: false                # optional, is superuser? false by default
            #createdb: false                 # optional, can create database? false by default
            #createrole: false               # optional, can create role? false by default
            #inherit: true                   # optional, can this role use inherited privileges? true by default
            #replication: false              # optional, can this role do replication? false by default
            #bypassrls: false                # optional, can this role bypass row level security? false by default
            #connlimit: -1                   # optional, user connection limit, default -1 disable limit
            #expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
            #expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
            #parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
            #pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
            #pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly], comment: read-only viewer for meta database}
          #- {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database   }
          #- {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database  }
          #- {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service      }
          #- {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service    }

        # define business service here: https://pigsty.io/docs/pgsql/service
        pg_services:                        # extra services in addition to pg_default_services, array of service definition
          # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
          - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
            port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
            ip: "*"                         # optional, service bind ip address, `*` for all ip by default
            selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
            dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
            check: /sync                    # optional, health check url path, / by default
            backup: "[? pg_role == `primary`]"  # backup server selector
            maxconn: 3000                   # optional, max allowed front-end connection
            balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: leastconn)
            #options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

        # define pg extensions: https://pigsty.io/docs/pgsql/ext/
        pg_libs: 'pg_stat_statements, auto_explain' # add timescaledb to shared_preload_libraries
        #pg_extensions: [] # extensions to be installed on this cluster

        # define HBA rules here: https://pigsty.io/docs/pgsql/config/hba
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}

        pg_vip_enabled: true
        pg_vip_address: 10.10.10.2/24

        pg_crontab:  # make a full backup 1 am everyday
          - '00 01 * * * /pg/bin/pg-backup full'

    #----------------------------------#
    # pgsql cluster: pg-test (3 nodes) #
    #----------------------------------#
    # pg-test --->  10.10.10.3 ---> 10.10.10.1{1,2,3}
    pg-test:                          # define the new 3-node cluster pg-test
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }   # primary instance, leader of cluster
        10.10.10.12: { pg_seq: 2, pg_role: replica }   # replica instance, follower of leader
        10.10.10.13: { pg_seq: 3, pg_role: replica, pg_offline_query: true } # replica with offline access
      vars:
        pg_cluster: pg-test           # define pgsql cluster name
        pg_users:  [{ name: test , password: test , pgbouncer: true , roles: [ dbrole_admin ] }]
        pg_databases: [{ name: test }] # create a database and user named 'test'
        node_tune: tiny
        pg_conf: tiny.yml
        pg_vip_enabled: true
        pg_vip_address: 10.10.10.3/24
        pg_crontab:  # make a full backup on monday 1am, and an incremental backup during weekdays
          - '00 01 * * 1 /pg/bin/pg-backup full'
          - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'

    #----------------------------------#
    # redis ms, sentinel, native cluster
    #----------------------------------#
    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  ####################################################################
  #                             VARS                                 #
  ####################################################################
  vars:                               # global variables


    #================================================================#
    #                         VARS: INFRA                            #
    #================================================================#

    #-----------------------------------------------------------------
    # META
    #-----------------------------------------------------------------
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe
    language: en                      # default language: en, zh
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]

    #-----------------------------------------------------------------
    # CA
    #-----------------------------------------------------------------
    ca_create: true                   # create ca if not exists? or just abort
    ca_cn: pigsty-ca                  # ca common name, fixed as pigsty-ca
    cert_validity: 7300d              # cert validity, 20 years by default

    #-----------------------------------------------------------------
    # INFRA_IDENTITY
    #-----------------------------------------------------------------
    #infra_seq: 1                     # infra node identity, explicitly required
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name
    infra_data: /data/infra           # default data path for infrastructure data
    infra_services:                   # home page navigation entries
      - { name: Metrics            ,url: '/vmetrics/vmui/'         ,desc: 'VictoriaMetrics Query UI'    ,icon: metrics  ,name_cn: '指标查询' ,desc_cn: 'VictoriaMetrics 指标查询界面' }
      - { name: Logs               ,url: '/vlogs/select/vmui/'     ,desc: 'VictoriaLogs Query UI'       ,icon: logs     ,name_cn: '日志查询' ,desc_cn: 'VictoriaLogs 日志查询界面' }
      - { name: Traces             ,url: '/vtraces/select/vmui/'   ,desc: 'VictoriaTraces Query UI'     ,icon: traces   ,name_cn: '链路追踪' ,desc_cn: 'VictoriaTraces 链路查询界面' }
      - { name: Monitor Targets    ,url: '/vmetrics/targets'       ,desc: 'Prometheus Scrape Targets'   ,icon: target   ,name_cn: '监控目标' ,desc_cn: 'VictoriaMetrics 监控对象列表' }
      - { name: Alert Rules        ,url: '/vmalert/vmalert/groups' ,desc: 'VMAlert alert/record Rules'  ,icon: alert    ,name_cn: '告警规则' ,desc_cn: 'VMAlert 告警规则管理' }
      - { name: Alert Manager      ,url: '/alertmgr/#/alerts'      ,desc: 'Alert Manage & Silence'      ,icon: alertmgr ,name_cn: '告警管理' ,desc_cn: 'AlertManager 告警管理与屏蔽' }
      - { name: CA Certificate     ,url: '/ca.crt'                 ,desc: 'Self-Signed CA Certificate'  ,icon: lock     ,name_cn: 'CA 证书'  ,desc_cn: 'Pigsty 自签CA根证书' }
      - { name: Software Repo      ,url: '/pigsty'                 ,desc: 'Local YUM/APT Repository'    ,icon: package  ,name_cn: '软件仓库' ,desc_cn: '本地 YUM/APT 软件源' }
      - { name: Explain Visualizer ,url: '/pev'                    ,desc: 'Postgres EXPLAIN Visualizer' ,icon: search   ,name_cn: '执行计划' ,desc_cn: 'PG 执行计划可视化工具' }
    infra_extra_services: []          # extra services to be added on infra home page

    #-----------------------------------------------------------------
    # REPO
    #-----------------------------------------------------------------
    repo_enabled: true                # create a yum repo on this infra node?
    repo_home: /www                   # repo home dir, `/www` by default
    repo_name: pigsty                 # repo name, pigsty by default
    repo_endpoint: http://${admin_ip}:80 # access point to this repo by domain or ip:port
    repo_remove: true                 # remove existing upstream repo
    repo_modules: infra,node,pgsql    # which repo modules are installed in repo_upstream
    repo_upstream:                    # where to download
      - { name: pigsty-local   ,description: 'Pigsty Local'       ,module: local   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://${admin_ip}/pigsty ./' }}
      - { name: pigsty-pgsql   ,description: 'Pigsty PgSQL'       ,module: pgsql   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main', china: 'https://repo.pigsty.cc/apt/pgsql/${distro_codename} ${distro_codename} main' }}
      - { name: pigsty-infra   ,description: 'Pigsty Infra'       ,module: infra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/infra/ generic main' ,china: 'https://repo.pigsty.cc/apt/infra/ generic main' }}
      - { name: nginx          ,description: 'Nginx'              ,module: infra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://nginx.org/packages/${distro_name} ${distro_codename} nginx' }}
      - { name: docker-ce      ,description: 'Docker'             ,module: infra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/${distro_name} ${distro_codename} stable'                               ,china: 'https://mirrors.cloud.tencent.com/docker-ce/linux/${distro_name} ${distro_codename} stable' }}
      - { name: base           ,description: 'Debian Basic'       ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://deb.debian.org/debian/ ${distro_codename} main non-free-firmware'                                  ,china: 'https://mirrors.cloud.tencent.com/debian/ ${distro_codename} main non-free-firmware' }}
      - { name: updates        ,description: 'Debian Updates'     ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://deb.debian.org/debian/ ${distro_codename}-updates main non-free-firmware'                          ,china: 'https://mirrors.cloud.tencent.com/debian/ ${distro_codename}-updates main non-free-firmware' }}
      - { name: security       ,description: 'Debian Security'    ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://security.debian.org/debian-security ${distro_codename}-security main non-free-firmware'            ,china: 'https://mirrors.cloud.tencent.com/debian-security/ ${distro_codename}-security main non-free-firmware' }}
      - { name: base           ,description: 'Ubuntu Basic'       ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}           main universe multiverse restricted' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}           main restricted universe multiverse' }}
      - { name: updates        ,description: 'Ubuntu Updates'     ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-updates   main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}-updates   main restricted universe multiverse' }}
      - { name: backports      ,description: 'Ubuntu Backports'   ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-backports main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}-backports main restricted universe multiverse' }}
      - { name: security       ,description: 'Ubuntu Security'    ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-security  main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}-security  main restricted universe multiverse' }}
      - { name: base           ,description: 'Ubuntu Basic'       ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}             main universe multiverse restricted' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}           main restricted universe multiverse' }}
      - { name: updates        ,description: 'Ubuntu Updates'     ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-updates     main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}-updates   main restricted universe multiverse' }}
      - { name: backports      ,description: 'Ubuntu Backports'   ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-backports   main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}-backports main restricted universe multiverse' }}
      - { name: security       ,description: 'Ubuntu Security'    ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-security    main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}-security  main restricted universe multiverse' }}
      - { name: pgdg           ,description: 'PGDG'               ,module: pgsql   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg main' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/apt/ ${distro_codename}-pgdg main' }}
      - { name: pgdg-beta      ,description: 'PGDG Beta'          ,module: beta    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg-testing main 19' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/apt/ ${distro_codename}-pgdg-testing main 19' }}
      - { name: timescaledb    ,description: 'TimescaleDB'        ,module: extra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/timescale/timescaledb/${distro_name}/ ${distro_codename} main' }}
      - { name: citus          ,description: 'Citus'              ,module: extra   ,releases: [11,12,   22      ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/citusdata/community/${distro_name}/ ${distro_codename} main' } }
      - { name: percona        ,description: 'Percona TDE'        ,module: percona ,releases: [   12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/percona ${distro_codename} main' ,china: 'https://repo.pigsty.cc/apt/percona ${distro_codename} main' ,origin: 'http://repo.percona.com/ppg-18.4/apt ${distro_codename} main' }}
      - { name: groonga        ,description: 'Groonga Debian'     ,module: groonga ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.groonga.org/debian/ ${distro_codename} main' }}
      - { name: groonga        ,description: 'Groonga Ubuntu'     ,module: groonga ,releases: [         22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://ppa.launchpadcontent.net/groonga/ppa/ubuntu/ ${distro_codename} main' }}
      - { name: mysql          ,description: 'MySQL 8.4 LTS'      ,module: mysql   ,releases: [   12,13,22,24   ] ,arch: [x86_64         ] ,baseurl: { default: 'https://repo.mysql.com/apt/${distro_name} ${distro_codename} mysql-8.4-lts', china: 'https://mirrors.ustc.edu.cn/mysql-repo/apt/${distro_name} ${distro_codename} mysql-8.4-lts' }}
      - { name: mongo          ,description: 'MongoDB'            ,module: mongo   ,releases: [   12,   22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mongodb.org/apt/${distro_name} ${distro_codename}/mongodb-org/8.0 multiverse', china: 'https://mirrors.cloud.tencent.com/mongodb/apt/${distro_name} ${distro_codename}/mongodb-org/8.0 multiverse' }}
      - { name: redis          ,description: 'Redis'              ,module: redis   ,releases: [11,12,   22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.redis.io/deb ${distro_codename} main' }}
      - { name: llvm           ,description: 'LLVM'               ,module: llvm    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.llvm.org/${distro_codename}/ llvm-toolchain-${distro_codename} main' ,china: 'https://mirrors.tuna.tsinghua.edu.cn/llvm-apt/${distro_codename}/ llvm-toolchain-${distro_codename} main' }}
      - { name: haproxyd       ,description: 'Haproxy Debian'     ,module: haproxy ,releases: [   12            ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://haproxy.debian.net/ ${distro_codename}-backports-3.2 main' }}
      - { name: haproxyu       ,description: 'Haproxy Ubuntu'     ,module: haproxy ,releases: [            24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://ppa.launchpadcontent.net/vbernat/haproxy-3.2/ubuntu/ ${distro_codename} main' }}
      - { name: grafana        ,description: 'Grafana'            ,module: grafana ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://apt.grafana.com stable main' ,china: 'https://mirrors.cloud.tencent.com/grafana/apt/ stable main' }}
      - { name: kubernetes     ,description: 'Kubernetes'         ,module: kube    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /', china: 'https://mirrors.ustc.edu.cn/kubernetes/core:/stable:/v1.36/deb/ /' }}
      - { name: gitlab-ee      ,description: 'Gitlab EE'          ,module: gitlab  ,releases: [11,12,13,22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ee/${distro_name}/ ${distro_codename} main' }}
      - { name: gitlab-ce      ,description: 'Gitlab CE'          ,module: gitlab  ,releases: [11,12,13,22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ce/${distro_name}/ ${distro_codename} main' }}
      - { name: clickhouse     ,description: 'ClickHouse'         ,module: click   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.clickhouse.com/deb/ stable main', china: 'https://repo.huaweicloud.com/clickhouse/deb/ stable main' }}

    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, node-package3, pgsql-utility, extra-modules ]
    repo_extra_packages: [ pgsql-main ]
    repo_url_packages: []

    #-----------------------------------------------------------------
    # INFRA_PACKAGE
    #-----------------------------------------------------------------
    infra_packages:                   # packages to be installed on infra nodes
      - grafana,grafana-plugins,grafana-victorialogs-ds,grafana-victoriametrics-ds,victoria-metrics,victoria-logs,victoria-traces,vmutils,vlogscli,alertmanager
      - node-exporter,blackbox-exporter,nginx-exporter,pg-exporter,pev2,nginx,dnsmasq,ansible,etcd,python3-requests,redis,mcli,restic,certbot,python3-certbot-nginx

    #-----------------------------------------------------------------
    # NGINX
    #-----------------------------------------------------------------
    nginx_enabled: true               # enable nginx on this infra node?
    nginx_clean: false                # clean existing nginx config during init?
    nginx_exporter_enabled: true      # enable nginx_exporter on this infra node?
    nginx_exporter_port: 9113         # nginx_exporter listen port, 9113 by default
    nginx_sslmode: enable             # nginx ssl mode? disable,enable,enforce
    nginx_cert_validity: 397d         # nginx self-signed cert validity, 397d by default
    nginx_home: /www                  # nginx content dir, `/www` by default (soft link to nginx_data)
    nginx_data: /data/nginx           # nginx actual data dir, /data/nginx by default
    nginx_users: { admin : pigsty }   # nginx basic auth users: name and pass dict
    nginx_port: 80                    # nginx listen port, 80 by default
    nginx_ssl_port: 443               # nginx ssl listen port, 443 by default
    certbot_sign: false               # sign nginx cert with certbot during setup?
    certbot_email: [email protected]     # certbot email address, used for free ssl
    certbot_options: ''               # certbot extra options

    #-----------------------------------------------------------------
    # DNS
    #-----------------------------------------------------------------
    dns_enabled: true                 # setup dnsmasq on this infra node?
    dns_port: 53                      # dns server listen port, 53 by default
    dns_records:                      # dynamic dns records resolved by dnsmasq
      - "${admin_ip} i.pigsty"
      - "${admin_ip} m.pigsty supa.pigsty api.pigsty adm.pigsty cli.pigsty ddl.pigsty"

    #-----------------------------------------------------------------
    # VICTORIA
    #-----------------------------------------------------------------
    vmetrics_enabled: true            # enable victoria-metrics on this infra node?
    vmetrics_clean: false             # whether clean existing victoria metrics data during init?
    vmetrics_port: 8428               # victoria-metrics listen port, 8428 by default
    vmetrics_scrape_interval: 10s     # victoria global scrape interval, 10s by default
    vmetrics_scrape_timeout: 8s       # victoria global scrape timeout, 8s by default
    vmetrics_options: >-
      -retentionPeriod=15d
      -promscrape.fileSDCheckInterval=5s
    vlogs_enabled: true               # enable victoria-logs on this infra node?
    vlogs_clean: false                # clean victoria-logs data during init?
    vlogs_port: 9428                  # victoria-logs listen port, 9428 by default
    vlogs_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
      -insert.maxLineSizeBytes=1MB
      -search.maxQueryDuration=120s
    vtraces_enabled: true             # enable victoria-traces on this infra node?
    vtraces_clean: false                # clean victoria-trace data during inti?
    vtraces_port: 10428               # victoria-traces listen port, 10428 by default
    vtraces_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=50GiB
    vmalert_enabled: true             # enable vmalert on this infra node?
    vmalert_port: 8880                # vmalert listen port, 8880 by default
    vmalert_options: ''              # vmalert extra server options

    #-----------------------------------------------------------------
    # PROMETHEUS
    #-----------------------------------------------------------------
    blackbox_enabled: true            # setup blackbox_exporter on this infra node?
    blackbox_port: 9115               # blackbox_exporter listen port, 9115 by default
    blackbox_options: ''              # blackbox_exporter extra server options
    alertmanager_enabled: true        # setup alertmanager on this infra node?
    alertmanager_port: 9059           # alertmanager listen port, 9059 by default
    alertmanager_options: ''          # alertmanager extra server options
    exporter_metrics_path: /metrics   # exporter metric path, `/metrics` by default

    #-----------------------------------------------------------------
    # GRAFANA
    #-----------------------------------------------------------------
    grafana_enabled: true             # enable grafana on this infra node?
    grafana_port: 3000                # default listen port for grafana
    grafana_clean: false              # clean grafana data during init?
    grafana_admin_username: admin     # grafana admin username, `admin` by default
    grafana_admin_password: pigsty    # grafana admin password, `pigsty` by default
    grafana_auth_proxy: false         # enable grafana auth proxy?
    grafana_pgurl: ''                 # external postgres database url for grafana if given
    grafana_view_password: DBUser.Viewer # password for grafana meta pg datasource


    #================================================================#
    #                         VARS: NODE                             #
    #================================================================#

    #-----------------------------------------------------------------
    # NODE_IDENTITY
    #-----------------------------------------------------------------
    #nodename:           # [INSTANCE] # node instance identity, use hostname if missing, optional
    node_cluster: nodes   # [CLUSTER] # node cluster identity, use 'nodes' if missing, optional
    nodename_overwrite: true          # overwrite node's hostname with nodename?
    nodename_exchange: false          # exchange nodename among play hosts?
    node_id_from_pg: true             # use postgres identity as node identity if applicable?

    #-----------------------------------------------------------------
    # NODE_DNS
    #-----------------------------------------------------------------
    node_write_etc_hosts: true        # modify `/etc/hosts` on target node?
    node_default_etc_hosts:           # static dns records in `/etc/hosts`
      - "${admin_ip} i.pigsty"
    node_etc_hosts: []                # extra static dns records in `/etc/hosts`
    node_dns_method: add              # how to handle dns servers: add,none,overwrite
    node_dns_servers: ['${admin_ip}'] # dynamic nameserver in `/etc/resolv.conf`
    node_dns_options:                 # dns resolv options in `/etc/resolv.conf`
      - options single-request-reopen timeout:1

    #-----------------------------------------------------------------
    # NODE_PACKAGE
    #-----------------------------------------------------------------
    node_repo_modules: local          # upstream repo to be added on node, local by default
    node_repo_remove: true            # remove existing repo on node?
    node_packages: [openssh-server]   # packages to be installed current nodes with latest version
    node_default_packages:            # default packages to be installed on all nodes
      - lz4,unzip,bzip2,pv,jq,git,ncdu,make,patch,bash,lsof,wget,uuid,tuned,nvme-cli,numactl,sysstat,iotop,htop,rsync,tcpdump
      - python3,python3-pip,socat,lrzsz,net-tools,ipvsadm,telnet,ca-certificates,openssl,keepalived,etcd,haproxy,chrony,pig
      - zlib1g,acl,dnsutils,libreadline-dev,vim-tiny,node-exporter,openssh-server,openssh-client,vector
    node_uv_env: /data/venv           # uv venv path, empty string to skip
    node_pip_packages: ''             # pip packages to install in uv venv

    #-----------------------------------------------------------------
    # NODE_SEC
    #-----------------------------------------------------------------
    node_selinux_mode: permissive     # set selinux mode: enforcing,permissive,disabled
    node_firewall_mode: zone          # firewall mode: zone (default), off (disable), none (skip & self-managed)
    node_firewall_intranet:           # which intranet cidr considered as internal network
      - 10.0.0.0/8
      - 192.168.0.0/16
      - 172.16.0.0/12
    node_firewall_public_port:        # expose these ports to public network in (zone, strict) mode
      - 22                            # enable ssh access
      - 80                            # enable http access
      - 443                           # enable https access
      - 5432                          # enable postgres access

    #-----------------------------------------------------------------
    # NODE_TUNE
    #-----------------------------------------------------------------
    node_disable_numa: false          # disable node numa, reboot required
    node_disable_swap: false          # disable node swap, use with caution
    node_static_network: true         # preserve dns resolver settings after reboot
    node_disk_prefetch: false         # setup disk prefetch on HDD to increase performance
    node_kernel_modules: [ softdog, ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh ]
    node_hugepage_count: 0            # number of 2MB hugepage, take precedence over ratio
    node_hugepage_ratio: 0            # node mem hugepage ratio, 0 disable it by default
    node_overcommit_ratio: 0          # node mem overcommit ratio, 0 disable it by default
    node_tune: oltp                   # node tuned profile: none,oltp,olap,crit,tiny
    node_sysctl_params:              # sysctl parameters in k:v format in addition to tuned
      fs.nr_open: 8388608

    #-----------------------------------------------------------------
    # NODE_ADMIN
    #-----------------------------------------------------------------
    node_data: /data                  # node main data directory, `/data` by default
    node_admin_enabled: true          # create a admin user on target node?
    node_admin_uid: 88                # uid and gid for node admin user
    node_admin_username: dba          # name of node admin user, `dba` by default
    node_admin_sudo: nopass           # admin sudo privilege, all,nopass. nopass by default
    node_admin_ssh_exchange: true     # exchange admin ssh key among node cluster
    node_admin_pk_current: true       # add current user's ssh pk to admin authorized_keys
    node_admin_pk_list: []            # ssh public keys to be added to admin user
    node_aliases: {}                  # extra shell aliases to be added, k:v dict

    #-----------------------------------------------------------------
    # NODE_TIME
    #-----------------------------------------------------------------
    node_timezone: ''                 # setup node timezone, empty string to skip
    node_ntp_enabled: true            # enable chronyd time sync service?
    node_ntp_servers:                 # ntp servers in `/etc/chrony.conf`
      - pool pool.ntp.org iburst
    node_crontab_overwrite: true      # overwrite or append to `/etc/crontab`?
    node_crontab: [ ]                 # crontab entries in `/etc/crontab`

    #-----------------------------------------------------------------
    # NODE_VIP
    #-----------------------------------------------------------------
    vip_enabled: false                # enable vip on this node cluster?
    # vip_address:         [IDENTITY] # node vip address in ipv4 format, required if vip is enabled
    # vip_vrid:            [IDENTITY] # required, integer, 1-254, should be unique among same VLAN
    vip_role: backup                  # optional, `master|backup`, backup by default, use as init role
    vip_preempt: false                # optional, `true/false`, false by default, enable vip preemption
    vip_interface: auto               # node vip network interface to listen, `auto` by default
    vip_dns_suffix: ''                # node vip dns name suffix, empty string by default
    vip_auth_pass: ''                 # empty to use '<cls>-<vrid>' as the default
    vip_exporter_port: 9650           # keepalived exporter listen port, 9650 by default

    #-----------------------------------------------------------------
    # HAPROXY
    #-----------------------------------------------------------------
    haproxy_enabled: true             # enable haproxy on this node?
    haproxy_clean: false              # cleanup all existing haproxy config?
    haproxy_reload: true              # reload haproxy after config?
    haproxy_auth_enabled: true        # enable authentication for haproxy admin page
    haproxy_admin_username: admin     # haproxy admin username, `admin` by default
    haproxy_admin_password: pigsty    # haproxy admin password, `pigsty` by default
    haproxy_exporter_port: 9101       # haproxy admin/exporter port, 9101 by default
    haproxy_client_timeout: 24h       # client side connection timeout, 24h by default
    haproxy_server_timeout: 24h       # server side connection timeout, 24h by default
    haproxy_services: []              # list of haproxy service to be exposed on node

    #-----------------------------------------------------------------
    # NODE_EXPORTER
    #-----------------------------------------------------------------
    node_exporter_enabled: true       # setup node_exporter on this node?
    node_exporter_port: 9100          # node exporter listen port, 9100 by default
    node_exporter_options: '--no-collector.softnet --no-collector.nvme --collector.tcpstat --collector.processes'

    #-----------------------------------------------------------------
    # VECTOR
    #-----------------------------------------------------------------
    vector_enabled: true              # enable vector log collector?
    vector_clean: false               # purge vector data dir during init?
    vector_data: /data/vector         # vector data dir, /data/vector by default
    vector_port: 9598                 # vector metrics port, 9598 by default
    vector_read_from: beginning       # vector read from beginning or end
    vector_log_endpoint: [ infra ]    # if defined, sending vector log to this endpoint.


    #================================================================#
    #                        VARS: DOCKER                            #
    #================================================================#
    docker_enabled: false             # enable docker on this node?
    docker_data: /data/docker         # docker data directory, /data/docker by default
    docker_storage_driver: overlay2   # docker storage driver, can be zfs, btrfs
    docker_cgroups_driver: systemd    # docker cgroup fs driver: cgroupfs,systemd
    docker_registry_mirrors: []       # docker registry mirror list
    docker_exporter_port: 9323        # docker metrics exporter port, 9323 by default
    docker_image: []                  # docker image to be pulled after bootstrap
    docker_image_cache: /tmp/docker/*.tgz # docker image cache glob pattern

    #================================================================#
    #                         VARS: ETCD                             #
    #================================================================#
    #etcd_seq: 1                      # etcd instance identifier, explicitly required
    etcd_cluster: etcd                # etcd cluster & group name, etcd by default
    etcd_safeguard: false             # prevent purging running etcd instance?
    etcd_data: /data/etcd             # etcd data directory, /data/etcd by default
    etcd_port: 2379                   # etcd client port, 2379 by default
    etcd_peer_port: 2380              # etcd peer port, 2380 by default
    etcd_init: new                    # etcd initial cluster state, new or existing
    etcd_election_timeout: 1000       # etcd election timeout, 1000ms by default
    etcd_heartbeat_interval: 100      # etcd heartbeat interval, 100ms by default
    etcd_root_password: Etcd.Root     # etcd root password for RBAC, change it!


    #================================================================#
    #                         VARS: MINIO                            #
    #================================================================#
    #minio_seq: 1                     # minio instance identifier, REQUIRED
    #minio_cluster:                   # minio cluster identifier, REQUIRED (define in cluster vars)
    minio_user: minio                 # minio os user, `minio` by default
    minio_https: true                 # use https for minio, true by default
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
    minio_data: '/data/minio'         # minio data dir(s), use {x...y} to specify multi drivers
    #minio_volumes:                   # minio data volumes, override defaults if specified
    minio_domain: sss.pigsty          # minio external domain name, `sss.pigsty` by default
    minio_port: 9000                  # minio service port, 9000 by default
    minio_admin_port: 9001            # minio console port, 9001 by default
    minio_access_key: minioadmin      # root access key, `minioadmin` by default
    minio_secret_key: S3User.MinIO    # root secret key, `S3User.MinIO` by default
    minio_extra_vars: ''              # extra environment variables
    minio_provision: true             # run minio provisioning tasks?
    minio_alias: sss                  # alias name for local minio deployment
    #minio_endpoint: https://sss.pigsty:9000 # if not specified, overwritten by defaults
    minio_buckets:                    # list of minio bucket to be created
      - { name: pgsql }
      - { name: meta ,versioning: true }
      - { name: data }
    minio_users:                      # list of minio user to be created
      - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
      - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
      - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }
    minio_safeguard: false            # prevent purging running minio instance?
    minio_rm_data: true               # purging minio data and config?
    minio_rm_pkg: false               # uninstall minio packages?


    #================================================================#
    #                         VARS: REDIS                            #
    #================================================================#
    #redis_cluster:        <CLUSTER> # redis cluster name, required identity parameter
    #redis_node: 1            <NODE> # redis node sequence number, node int id required
    #redis_instances: {}      <NODE> # redis instances definition on this redis node
    redis_fs_main: /data/redis        # redis main data directory, `/data/redis` by default
    redis_exporter_enabled: true      # install redis exporter on redis nodes?
    redis_exporter_port: 9121         # redis exporter listen port, 9121 by default
    redis_exporter_options: ''        # cli args and extra options for redis exporter
    redis_type: redis                 # redis implementation: redis or valkey
    redis_mode: standalone            # redis mode: standalone,cluster,sentinel
    redis_conf: redis.conf            # redis config template path, except sentinel
    redis_bind_address: '0.0.0.0'     # redis bind address, empty string will use host ip
    redis_max_memory: 1GB             # max memory used by each redis instance
    redis_mem_policy: allkeys-lru     # redis memory eviction policy
    redis_password: ''                # redis password, empty string will disable password
    redis_rdb_save: ['1200 1']        # redis rdb save directives, disable with empty list
    redis_aof_enabled: false          # enable redis append only file?
    redis_rename_commands: {}         # rename redis dangerous commands
    redis_cluster_replicas: 1         # replica number for one master in redis cluster
    redis_sentinel_monitor: []        # sentinel master list, works on sentinel cluster only
    redis_safeguard: false            # prevent purging running redis instance?
    redis_rm_data: true               # remove redis data dir?
    redis_rm_pkg: false               # uninstall selected engine & redis-exporter packages?


    #================================================================#
    #                         VARS: PGSQL                            #
    #================================================================#

    #-----------------------------------------------------------------
    # PG_IDENTITY
    #-----------------------------------------------------------------
    pg_mode: pgsql          #CLUSTER  # pgsql cluster mode: pgsql,citus,mssql,mysql,ivory,pgtde,polar,gpsql,agens,oriole,pgedge
    # pg_cluster:           #CLUSTER  # pgsql cluster name, required identity parameter
    # pg_seq: 0             #INSTANCE # pgsql instance seq number, required identity parameter
    # pg_role: replica      #INSTANCE # pgsql role, required, could be primary,replica,offline
    # pg_instances: {}      #INSTANCE # define multiple pg instances on node in `{port:ins_vars}` format
    # pg_upstream:          #INSTANCE # repl upstream ip addr for standby cluster or cascade replica
    # pg_shard:             #CLUSTER  # pgsql shard name, optional identity for sharding clusters
    # pg_group: 0           #CLUSTER  # pgsql shard index number, optional identity for sharding clusters
    # gp_role: master       #CLUSTER  # greenplum role of this cluster, could be master or segment
    pg_offline_query: false #INSTANCE # set to true to enable offline queries on this instance

    #-----------------------------------------------------------------
    # PG_BUSINESS
    #-----------------------------------------------------------------
    # postgres business object definition, overwrite in group vars
    pg_users: []                      # postgres business users
    pg_databases: []                  # postgres business databases
    pg_services: []                   # postgres business services
    pg_hba_rules: []                  # business hba rules for postgres
    pgb_hba_rules: []                 # business hba rules for pgbouncer
    pg_crontab: []                    # postgres crontab entries for dbsu
    # global credentials, overwrite in global vars
    pg_dbsu_password: ''              # dbsu password, empty string means no dbsu password by default
    pg_replication_username: replicator
    pg_replication_password: DBUser.Replicator
    pg_admin_username: dbuser_dba
    pg_admin_password: DBUser.DBA
    pg_monitor_username: dbuser_monitor
    pg_monitor_password: DBUser.Monitor

    #-----------------------------------------------------------------
    # PG_INSTALL
    #-----------------------------------------------------------------
    pg_dbsu: postgres                 # os dbsu name, postgres by default, better not change it
    pg_dbsu_uid: 543                  # os dbsu uid and gid, 26 for default postgres users and groups
    pg_dbsu_sudo: limit               # dbsu sudo privilege, none,limit,all,nopass. limit by default
    pg_dbsu_home: /var/lib/pgsql      # postgresql home directory, `/var/lib/pgsql` by default
    pg_dbsu_ssh_exchange: true        # exchange postgres dbsu ssh key among same pgsql cluster
    pg_version: 18                    # postgres major version to be installed, 18 by default
    pg_bin_dir: /usr/pgsql/bin        # postgres binary dir, `/usr/pgsql/bin` by default
    pg_log_dir: /pg/log/postgres      # postgres log dir, `/pg/log/postgres` by default
    pg_packages:                      # pg packages to be installed, alias can be used
      - pgsql-main pgsql-common
    pg_extensions: []                 # pg extensions to be installed, alias can be used

    #-----------------------------------------------------------------
    # PG_BOOTSTRAP
    #-----------------------------------------------------------------
    pg_data: /pg/data                 # postgres data directory, `/pg/data` by default
    pg_fs_main: /data/postgres        # postgres main data directory, `/data/postgres` by default
    pg_fs_backup: /data/backups       # postgres backup data directory, `/data/backups` by default
    pg_storage_type: SSD              # storage type for pg main data, SSD,HDD, SSD by default
    pg_dummy_filesize: 64MiB          # size of `/pg/dummy`, hold 64MB disk space for emergency use
    pg_listen: '0.0.0.0'              # postgres/pgbouncer listen addresses, comma separated list
    pg_port: 5432                     # postgres listen port, 5432 by default
    pg_localhost: /var/run/postgresql # postgres unix socket dir for localhost connection
    patroni_enabled: true             # if disabled, no postgres cluster will be created during init
    patroni_mode: default             # patroni working mode: default,pause,remove
    pg_namespace: /pg                 # top level key namespace in etcd, used by patroni & vip
    patroni_port: 8008                # patroni listen port, 8008 by default
    patroni_log_dir: /pg/log/patroni  # patroni log dir, `/pg/log/patroni` by default
    patroni_ssl_enabled: false        # secure patroni RestAPI communications with SSL?
    patroni_watchdog_mode: 'off'      # patroni watchdog mode: automatic,required,off. off by default
    patroni_username: postgres        # patroni restapi username, `postgres` by default
    patroni_password: Patroni.API     # patroni restapi password, `Patroni.API` by default
    pg_etcd_password: ''              # etcd password for this pg cluster, '' to use pg_cluster
    pg_primary_db: postgres           # primary database name, used by citus,etc... ,postgres by default
    pg_parameters: {}                 # extra parameters in postgresql.auto.conf
    pg_files: []                      # extra files to be copied to postgres data directory (e.g. license)
    pg_conf: oltp.yml                 # config template: oltp,olap,crit,tiny. `oltp.yml` by default
    pg_max_conn: auto                 # postgres max connections, `auto` will use recommended value
    pg_shared_buffer_ratio: 0.25      # postgres shared buffers ratio, 0.25 by default, 0.1~0.4
    pg_io_method: worker              # io method for postgres, auto,fsync,worker,io_uring, worker by default
    pg_rto: norm                      # shared rto mode for patroni & haproxy: fast,norm,safe,wide
    pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
      fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]
      norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]
      safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]
      wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]
    pg_rpo: 1048576                   # recovery point objective in bytes, `1MiB` at most by default
    pg_libs: 'pg_stat_statements, auto_explain'  # preloaded libraries, `pg_stat_statements,auto_explain` by default
    pg_delay: 0                       # replication apply delay for standby cluster leader
    pg_checksum: true                 # enable data checksum for postgres cluster?
    pg_pwd_enc: scram-sha-256         # password encryption algorithm
    pg_encoding: UTF8                 # database cluster encoding, `UTF8` by default
    pg_locale: C                      # database cluster local, `C` by default
    pg_lc_collate: C                  # database cluster collate, `C` by default
    pg_lc_ctype: C                    # database character type, `C` by default
    #pgsodium_key: ""                 # pgsodium key, 64 hex digit, default to sha256(pg_cluster)
    #pgsodium_getkey_script: ""       # pgsodium getkey script path, pgsodium_getkey by default

    #-----------------------------------------------------------------
    # PG_PROVISION
    #-----------------------------------------------------------------
    pg_provision: true                # provision postgres cluster after bootstrap
    pg_init: pg-init                  # provision init script for cluster template, `pg-init` by default
    pg_default_roles:                 # default roles and users in postgres cluster
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,comment: system superuser }
      - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_privileges:            # default privileges when created by admin user
      - GRANT USAGE      ON SCHEMAS    TO  dbrole_readonly
      - GRANT SELECT     ON TABLES     TO  dbrole_readonly
      - GRANT SELECT     ON SEQUENCES  TO  dbrole_readonly
      - GRANT EXECUTE    ON FUNCTIONS  TO  dbrole_readonly
      - GRANT USAGE      ON SCHEMAS    TO  dbrole_offline
      - GRANT SELECT     ON TABLES     TO  dbrole_offline
      - GRANT SELECT     ON SEQUENCES  TO  dbrole_offline
      - GRANT EXECUTE    ON FUNCTIONS  TO  dbrole_offline
      - GRANT INSERT     ON TABLES     TO  dbrole_readwrite
      - GRANT UPDATE     ON TABLES     TO  dbrole_readwrite
      - GRANT DELETE     ON TABLES     TO  dbrole_readwrite
      - GRANT USAGE      ON SEQUENCES  TO  dbrole_readwrite
      - GRANT UPDATE     ON SEQUENCES  TO  dbrole_readwrite
      - GRANT TRUNCATE   ON TABLES     TO  dbrole_admin
      - GRANT REFERENCES ON TABLES     TO  dbrole_admin
      - GRANT TRIGGER    ON TABLES     TO  dbrole_admin
      - GRANT CREATE     ON SCHEMAS    TO  dbrole_admin
    pg_default_schemas: [ monitor ]   # default schemas to be created
    pg_default_extensions:            # default extensions to be created
      - { name: pg_stat_statements ,schema: monitor }
      - { name: pgstattuple        ,schema: monitor }
      - { name: pg_buffercache     ,schema: monitor }
      - { name: pageinspect        ,schema: monitor }
      - { name: pg_prewarm         ,schema: monitor }
      - { name: pg_visibility      ,schema: monitor }
      - { name: pg_freespacemap    ,schema: monitor }
      - { name: postgres_fdw       ,schema: public  }
      - { name: file_fdw           ,schema: public  }
      - { name: btree_gist         ,schema: public  }
      - { name: btree_gin          ,schema: public  }
      - { name: pg_trgm            ,schema: public  }
      - { name: intagg             ,schema: public  }
      - { name: intarray           ,schema: public  }
      - { name: pg_repack }
    pg_reload: true                   # reload postgres after hba changes
    pg_default_hba_rules:             # postgres default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
      - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
      - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
      - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
      - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
      - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
      - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin @ intranet nodes with pwd'      ,order: 450}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
      - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
      - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
      - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}
    pgb_default_hba_rules:            # pgbouncer default host-based authentication rules, order by `order`
      - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident',order: 100}
      - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' ,order: 150}
      - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' ,order: 200}
      - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' ,order: 250}
      - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   ,order: 300}
      - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   ,order: 350}
      - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' ,order: 400}

    #-----------------------------------------------------------------
    # PG_BACKUP
    #-----------------------------------------------------------------
    pgbackrest_enabled: true          # enable pgbackrest on pgsql host?
    pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest log dir, `/pg/log/pgbackrest` by default
    pgbackrest_method: local          # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_init_backup: true      # take a full backup after pgbackrest is initialized?
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backups when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for the the last 14 days

    #-----------------------------------------------------------------
    # PG_ACCESS
    #-----------------------------------------------------------------
    pgbouncer_enabled: true           # if disabled, pgbouncer will not be launched on pgsql host
    pgbouncer_port: 6432              # pgbouncer listen port, 6432 by default
    pgbouncer_log_dir: /pg/log/pgbouncer  # pgbouncer log dir, `/pg/log/pgbouncer` by default
    pgbouncer_auth_query: false       # query postgres to retrieve unlisted business users?
    pgbouncer_poolmode: transaction   # pooling mode: transaction,session,statement, transaction by default
    pgbouncer_sslmode: disable        # pgbouncer client ssl mode, disable by default
    pgbouncer_ignore_param: [ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]
    pg_weight: 100          #INSTANCE # relative load balance weight in service, 100 by default, 0-255
    pg_service_provider: ''           # dedicate haproxy node group name, or empty string for local nodes by default
    pg_default_service_dest: pgbouncer # default service destination if svc.dest='default'
    pg_default_services:              # postgres default service definitions
      - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
      - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
      - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
      - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
    pg_vip_enabled: false             # enable a l2 vip for pgsql primary? false by default
    pg_vip_address: 127.0.0.1/24      # vip address in `<ipv4>/<mask>` format, require if vip is enabled
    pg_vip_interface: auto            # vip network interface to listen, auto by default
    pg_dns_suffix: ''                 # pgsql dns suffix, '' by default
    pg_dns_target: auto               # auto, primary, vip, none, or ad hoc ip

    #-----------------------------------------------------------------
    # PG_MONITOR
    #-----------------------------------------------------------------
    pg_exporter_enabled: true              # enable pg_exporter on pgsql hosts?
    pg_exporter_config: pg_exporter.yml    # pg_exporter configuration file name
    pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter collector ttl stage in seconds, '1,10,60,300' by default
    pg_exporter_port: 9630                 # pg_exporter listen port, 9630 by default
    pg_exporter_params: 'sslmode=disable'  # extra url parameters for pg_exporter dsn
    pg_exporter_url: ''                    # overwrite auto-generate pg dsn if specified
    pg_exporter_auto_discovery: true       # enable auto database discovery? enabled by default
    pg_exporter_exclude_database: 'template0,template1,postgres' # csv of database that WILL NOT be monitored during auto-discovery
    pg_exporter_include_database: ''       # csv of database that WILL BE monitored during auto-discovery
    pg_exporter_connect_timeout: 200       # pg_exporter connect timeout in ms, 200 by default
    pg_exporter_options: ''                # overwrite extra options for pg_exporter
    pgbouncer_exporter_enabled: true       # enable pgbouncer_exporter on pgsql hosts?
    pgbouncer_exporter_port: 9631          # pgbouncer_exporter listen port, 9631 by default
    pgbouncer_exporter_url: ''             # overwrite auto-generate pgbouncer dsn if specified
    pgbouncer_exporter_options: ''         # overwrite extra options for pgbouncer_exporter
    pgbackrest_exporter_enabled: true      # enable pgbackrest_exporter on pgsql hosts?
    pgbackrest_exporter_port: 9854         # pgbackrest_exporter listen port, 9854 by default
    pgbackrest_exporter_options: >-
      --collect.interval=120
      --log.level=info

    #-----------------------------------------------------------------
    # PG_REMOVE
    #-----------------------------------------------------------------
    pg_safeguard: false               # stop pg_remove running if pg_safeguard is enabled, false by default
    pg_rm_data: true                  # remove postgres data during remove? true by default
    pg_rm_backup: true                # remove pgbackrest backup during primary remove? true by default
    pg_rm_pkg: true                   # uninstall postgres packages during remove? true by default

...

Explanation

The demo/debian template is optimized for Debian and Ubuntu distributions.

Supported Distributions:

  • Debian 12 (Bookworm)
  • Debian 13 (Trixie)
  • Ubuntu 22.04 LTS (Jammy)
  • Ubuntu 24.04 LTS (Noble)
  • Ubuntu 26.04 LTS (Resolute)

Key Features:

  • Uses PGDG APT repositories
  • Optimized for APT package manager
  • Supports Debian/Ubuntu-specific package names

Use Cases:

  • Cloud servers (Ubuntu widely used)
  • Container environments (Debian commonly used as base image)
  • Development and testing environments

7.41 - demo/demo

Pigsty public demo site configuration, showcasing SSL certificates, domain exposure, and full extension installation

The demo/demo configuration template is used by Pigsty’s public demo site, demonstrating how to expose services publicly, configure SSL certificates, and install all available extensions.

If you want to set up your own public service on a cloud server, you can use this template as a reference.


Overview

  • Config Name: demo/demo
  • Node Count: Single node
  • Description: Pigsty public demo site configuration
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64
  • Related: meta, rich

Usage:

./configure -c demo/demo [-i <primary_ip>]

Key Features

This template enhances the meta template with:

  • SSL certificate and custom domain configuration (e.g., pigsty.cc)
  • Downloads and installs all available PostgreSQL 18 extensions
  • Enables Docker with image acceleration
  • Deploys Silo object storage
  • Pre-configures multiple business databases and users
  • Adds Redis primary-replica instance examples
  • Adds Kafka sample cluster

Content

Source: pigsty/conf/demo/demo.yml

---
#==============================================================#
# File      :   demo.yml
# Desc      :   Pigsty Public Demo Configuration
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf/demo
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra:
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:
        nodename: pigsty.cc       # overwrite the default hostname
        node_id_from_pg: false    # do not use the pg identity as hostname
        docker_enabled: true      # enable docker on this node
        docker_registry_mirrors: ["https://mirror.ccs.tencentyun.com", "https://docker.1ms.run"]
        # ./pgsql-monitor.yml -l infra     # monitor 'external' PostgreSQL instance
        pg_exporters:             # treat local postgres as RDS for demonstration purpose
          20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 }
          #20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.11 , pg_port: 5432 }
          #20003: { pg_cluster: pg-bar, pg_seq: 2, pg_host: 10.10.10.12 , pg_exporter_url: 'postgres://dbuser_monitor:[email protected]:5432/postgres?sslmode=disable' }
          #20004: { pg_cluster: pg-bar, pg_seq: 3, pg_host: 10.10.10.13 , pg_monitor_username: dbuser_monitor, pg_monitor_password: DBUser.Monitor }

    # etcd cluster for ha postgres
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio cluster, s3 compatible object storage
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # postgres example cluster: pg-meta
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta       ,password: DBUser.Meta       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view       ,password: DBUser.Viewer     ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
          - {name: dbuser_grafana    ,password: DBUser.Grafana    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
          - {name: dbuser_bytebase   ,password: DBUser.Bytebase   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
          - {name: dbuser_kong       ,password: DBUser.Kong       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
          - {name: dbuser_gitea      ,password: DBUser.Gitea      ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
          - {name: dbuser_wiki       ,password: DBUser.Wiki       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
          - {name: dbuser_noco       ,password: DBUser.Noco       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }
          - {name: dbuser_odoo       ,password: DBUser.Odoo       ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for odoo service ,createdb: true } #,superuser: true}
          - {name: dbuser_mattermost ,password: DBUser.MatterMost ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for mattermost ,createdb: true }
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: vector},{name: postgis},{name: timescaledb}]}
          - {name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database  }
          - {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          - {name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong api gateway database }
          - {name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          - {name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database  }
          - {name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database     }
          #- {name: odoo     ,owner: dbuser_odoo     ,revokeconn: true ,comment: odoo main database  }
          - {name: mattermost ,owner: dbuser_mattermost ,revokeconn: true ,comment: mattermost main database }
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        pg_libs: 'timescaledb,pg_stat_statements, auto_explain'  # add timescaledb to shared_preload_libraries
        pg_extensions: # extensions to be installed on this cluster
          - timescaledb timescaledb_toolkit pg_timeseries periods temporal_tables emaj table_version pg_cron pg_task pg_later pg_background
          - postgis pgrouting pointcloud pg_h3 q3c ogr_fdw geoip pg_polyline pg_geohash #mobilitydb
          - pgvector vchord pgvectorscale pg_vectorize pg_similarity smlar pg_summarize pg_tiktoken pg4ml #pgml
          - pg_search pgroonga pg_bigm zhparser pg_bestmatch vchord_bm25 hunspell
          - citus pg_duckdb pg_mooncake duckdb_fdw pg_parquet pg_fkpart pg_partman plproxy #pg_strom #hydra
          - age hll rum pg_graphql pg_jsonschema jsquery pg_hint_plan hypopg index_advisor pg_plan_filter imgsmlr pg_ivm pg_incremental pgmq pgq pg_cardano omnigres #rdkit
          - pg_tle plv8 pllua plprql pldebugger plpgsql_check plprofiler plsh pljava #plr #pgtap #faker #dbt2
          - pg_prefix pg_semver pgunit pgpdf pglite_fusion md5hash asn1oid pg_roaringbitmap pgfaceting pgsphere pg_country pg_xenophile pg_currency pgcollection pgmp numeral pg_rational pguint pg_uint128 hashtypes ip4r pg_uri pg_emailaddr pg_acl timestamp9 chkpass #pg_duration #debversion #pg_rrule
          - pg_gzip pg_bzip pg_zstd pg_http pg_net pg_curl pgjq pgjwt pg_smtp_client pg_html5_email_address url_encode pgsql_tweaks pg_extra_time pgpcre icu_ext pgqr pg_protobuf pg_envvar floatfile pg_readme ddl_historization data_historization pg_schedoc pg_hashlib pg_xxhash shacrypt cryptint pg_ecdsa pgsparql
          - pg_idkit pg_uuidv7 permuteseq pg_hashids sequential_uuids topn quantile lower_quantile count_distinct omnisketch ddsketch vasco pgxicor tdigest first_last_agg extra_window_functions floatvec aggs_for_vecs aggs_for_arrays pg_arraymath pg_math pg_random pg_base36 pg_base62 pg_base58 pg_financial
          - pg_repack pg_squeeze pg_dirtyread pgfincore pg_cooldown pg_ddlx pg_prioritize pg_checksums pg_readonly pg_upless pg_permissions pgautofailover pg_catcheck preprepare pgcozy pg_orphaned pg_crash pg_cheat_funcs pg_fio pg_savior safeupdate pg_drop_events table_log #pgagent #pgpool
          - pg_profile pg_tracing pg_show_plans pg_stat_kcache pg_stat_monitor pg_qualstats pg_store_plans pg_track_settings pg_wait_sampling system_stats pg_meta pgnodemx pg_sqlog bgw_replstatus pgmeminfo toastinfo pg_explain_ui pg_relusage pagevis powa
          - passwordcheck_cracklib supautils pgsodium pg_vault pg_session_jwt pg_anon pgsmcrypto pgaudit pgauditlogtofile pg_auth_mon credcheck pgcryptokey pg_jobmon logerrors login_hook set_user pg_snakeoil pgextwlist pg_auditor sslutils pg_noset #pg_tde
          - wrappers multicorn odbc_fdw jdbc_fdw mysql_fdw tds_fdw sqlite_fdw pgbouncer_fdw mongo_fdw redis_fdw pg_redis_pubsub kafka_fdw hdfs_fdw firebird_fdw aws_s3 log_fdw #oracle_fdw #db2_fdw
          - documentdb orafce pgtt session_variable pg_statement_rollback pg_dbms_metadata pg_dbms_lock pgmemcache #pg_dbms_job
          - pglogical pglogical_ticker pgl_ddl_deploy pg_failover_slots db_migrator wal2json wal2mongo decoderbufs decoder_raw mimeo pg_fact_loader pg_bulkload #repmgr

    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' }, 6381: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    # Kafka 4.x dynamic KRaft: combined broker/controller on the demo node
    kf-main:
      hosts: { 10.10.10.10: { kafka_seq: 1 } }
      vars:
        kafka_cluster: kf-main


  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: china                     # upstream mirror region: default|china|europe

    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      cc           : { domain: pigsty.cc      ,path:     "/www/pigsty.cc"   ,cert: /etc/cert/pigsty.cc.crt ,key: /etc/cert/pigsty.cc.key }
      minio        : { domain: m.pigsty.cc    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      postgrest    : { domain: api.pigsty.cc  ,endpoint: "127.0.0.1:8884"   }
      pgadmin      : { domain: adm.pigsty.cc  ,endpoint: "127.0.0.1:8885"   }
      pgweb        : { domain: cli.pigsty.cc  ,endpoint: "127.0.0.1:8886"   }
      bytebase     : { domain: ddl.pigsty.cc  ,endpoint: "127.0.0.1:8887"   }
      jupyter      : { domain: lab.pigsty.cc  ,endpoint: "127.0.0.1:8888", websocket: true }
      gitea        : { domain: git.pigsty.cc  ,endpoint: "127.0.0.1:8889" }
      wiki         : { domain: wiki.pigsty.cc ,endpoint: "127.0.0.1:9002" }
      noco         : { domain: noco.pigsty.cc ,endpoint: "127.0.0.1:9003" }
      supa         : { domain: supa.pigsty.cc ,endpoint: "10.10.10.10:8000" ,websocket: true }
      dify         : { domain: dify.pigsty.cc ,endpoint: "10.10.10.10:8001" ,websocket: true }
      odoo         : { domain: odoo.pigsty.cc ,endpoint: "127.0.0.1:8069"   ,websocket: true }
      mm           : { domain: mm.pigsty.cc   ,endpoint: "10.10.10.10:8065" ,websocket: true }
    # scp -r ~/pgsty/cc/cert/*       pj:/etc/cert/       # copy https certs
    # scp -r ~/dev/pigsty.cc/public  pj:/www/pigsty.cc   # copy pigsty.cc website


    node_etc_hosts: [ "${admin_ip} i.pigsty sss.pigsty" ]
    node_timezone: Asia/Hong_Kong
    node_ntp_servers:
      - pool cn.pool.ntp.org iburst
      - pool ${admin_ip} iburst       # assume non-admin nodes does not have internet access
    pgbackrest_enabled: false         # do not take backups since this is disposable demo env
    # keep 3GiB metrics data at most on demo env
    vmetrics_options: >-
      -retentionPeriod=15d
      -retention.maxDiskSpaceUsageBytes=3GiB

    # install all postgresql18 extensions
    pg_version: 18                    # default postgres version
    repo_extra_packages: [ pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl ,kafka-stack ,java-runtime]
    pg_extensions: [pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl ] #,pg18-olap]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The demo/demo template is Pigsty’s public demo configuration, showcasing a complete production-grade deployment example.

Key Features:

  • HTTPS certificate and custom domain configuration
  • All available PostgreSQL extensions installed
  • Integration with Redis, Kafka, and other components
  • Docker image acceleration configured

Use Cases:

  • Setting up public demo sites
  • Scenarios requiring complete feature demonstration
  • Learning Pigsty advanced configuration

Notes:

  • SSL certificate files must be prepared
  • DNS resolution must be configured
  • Some extensions are not available on ARM64 architecture

7.42 - demo/kernel

Ten-node PostgreSQL kernel matrix demo configuration

The demo/kernel configuration template demonstrates the major PostgreSQL kernels and compatible branches supported by Pigsty in a single configuration. It is intended for feature validation and kernel difference testing, not production use.


Overview

  • Config Name: demo/kernel
  • Node Count: 10 nodes, with one node also hosting INFRA/ETCD and pg-citus
  • Description: PostgreSQL kernel matrix demo covering Citus, IvorySQL, Babelfish, PolarDB, Percona TDE, OrioleDB, OpenHalo, DocumentDB, AgensGraph, and pgEdge
  • OS Distro: depends on actual package support for each kernel
  • OS Arch: depends on actual package support for each kernel
  • Related: pgsql, mssql, mongo

Usage:

./configure -c demo/kernel

Note: This is a fixed-IP demo template. Adjust node addresses for your actual environment after generation.


Content

Source: pigsty/conf/demo/kernel.yml

---
#==============================================================#
# File      :   kernel.yml
# Desc      :   Pigsty 10-node kernel matrix demo
# Ctime     :   2025-03-25
# Mtime     :   2026-07-23
# Docs      :   https://pigsty.io/docs/conf
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:
  children:
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } }, vars: { repo_enabled: false } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # 1. Vanilla PostgreSQL + Citus in one kernel template
    pg-citus:
      hosts:
        10.10.10.10: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-citus
        pg_version: 18
        pg_packages: [ pgsql-main, pgsql-common, citus ]
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [citus, postgis, vector] }
        pg_extensions: [ citus, postgis, timescaledb, pgvector ]
        pg_libs: 'citus, pg_stat_statements, auto_explain'

    # 2. IvorySQL kernel
    pg-ivory:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: ivory
        pg_cluster: pg-ivory
        pg_version: 18
        pg_packages: [ ivorysql, pgsql-common ]
        pg_libs: 'liboracle_parser, pg_stat_statements, auto_explain'
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] }

    # 3. Babelfish (MSSQL compatible) kernel
    pg-mssql:
      hosts:
        10.10.10.12: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: mssql
        pg_cluster: pg-mssql
        pg_version: 17
        pg_packages: [ babelfish, pgsql-common, sqlcmd ]
        pg_users:
          - { name: dbuser_mssql ,password: DBUser.MSSQL ,superuser: true ,pgbouncer: true ,roles: [dbrole_admin] ,comment: superuser & owner for babelfish }
        pg_databases:
          - name: mssql
            baseline: mssql.sql
            extensions: [ uuid-ossp, babelfishpg_common, babelfishpg_tsql, babelfishpg_tds, babelfishpg_money ]
            owner: dbuser_mssql
            parameters: { 'babelfishpg_tsql.migration_mode' : 'multi-db' }
            comment: babelfish cluster, a MSSQL compatible pg cluster
        pg_libs: 'babelfishpg_tds, pg_stat_statements, auto_explain'
        pg_hba_rules:
          - { user: dbuser_mssql ,db: mssql ,addr: intra ,auth: md5 ,title: 'allow mssql dbsu intranet access'      ,order: 525 }
          - { user: all          ,db: all   ,addr: intra ,auth: md5 ,title: 'everyone intranet access with md5 pwd' ,order: 800 }
        pg_default_services:
          - { name: primary ,port: 5433 ,dest: 1433     ,check: /primary   ,selector: "[]" }
          - { name: replica ,port: 5434 ,dest: 1433     ,check: /read-only ,selector: "[]" ,backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
          - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
          - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" ,backup: "[? pg_role == `replica` && !pg_offline_query]" }

    # 4. PolarDB kernel
    pg-polar:
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: polar
        pg_cluster: pg-polar
        pg_version: 17
        pg_packages: [ polardb, pgsql-common ]
        pg_exporter_exclude_database: 'template0,template1,postgres,polardb_admin'
        pg_default_roles:
          - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
          - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
          - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
          - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
          - { name: postgres     ,superuser: true  ,comment: system superuser }
          - { name: replicator   ,superuser: true  ,replication: true ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
          - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session ,pool_connlimit: 16 ,comment: pgsql admin user }
          - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: { log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

    # 5. Percona pg_tde kernel
    pg-tde:
      hosts:
        10.10.10.14: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: pgtde
        pg_cluster: pg-tde
        pg_version: 18
        pg_packages: [ pgtde, pgsql-common ]
        pg_libs: 'pg_tde, pgaudit, pg_stat_statements, pg_stat_monitor, auto_explain'
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - name: meta
            baseline: cmdb.sql
            comment: pigsty tde database
            schemas: [pigsty]
            extensions: [ vector, postgis, pg_tde ,pgaudit, { name: pg_stat_monitor, schema: monitor } ]

    # 6. OrioleDB kernel
    pg-oriole:
      hosts:
        10.10.10.15: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: oriole
        pg_cluster: pg-oriole
        pg_version: 18
        pg_packages: [ orioledb, pgsql-common ]
        pg_libs: 'orioledb, pg_stat_statements, auto_explain'
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [orioledb] }

    # 7. OpenHaloDB (MySQL compatible) kernel
    pg-mysql:
      hosts:
        10.10.10.16: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: mysql
        pg_cluster: pg-mysql
        pg_version: 14
        pg_packages: [ openhalo, pgsql-common ]
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: postgres ,extensions: [aux_mysql] }
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] }

    # 8. PostgreSQL Mongo mode with DocumentDB
    pg-mongo:
      hosts:
        10.10.10.17: { pg_seq: 1, pg_role: primary }
      vars:
        pg_cluster: pg-mongo
        pg_version: 18
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: postgres ,extensions: [documentdb, postgis, vector, pg_cron, rum] }
        pg_hba_rules:
          - { user: dbuser_view ,db: all ,addr: infra     ,auth: pwd   ,title: 'allow grafana dashboard access cmdb from infra nodes' }
          - { user: postgres    ,db: all ,addr: world     ,auth: pwd   ,title: 'dbsu password access everywhere (demo only)' }
          - { user: all         ,db: all ,addr: localhost ,order: 1    ,auth: trust ,title: 'documentdb localhost trust access' }
          - { user: all         ,db: all ,addr: local     ,order: 1    ,auth: trust ,title: 'documentdb local trust access' }
          - { user: all         ,db: all ,addr: intra     ,auth: pwd   ,order: 800  ,title: 'everyone intranet access with password' }
        pg_parameters: { cron.database_name: postgres }
        pg_extensions: [ documentdb, postgis, pgvector, pg_cron, rum ]
        pg_libs: 'pg_documentdb, pg_documentdb_core, pg_documentdb_extended_rum, pg_cron, pg_stat_statements, auto_explain'

    # 9. AgensGraph kernel
    pg-agens:
      hosts:
        10.10.10.18: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: agens
        pg_cluster: pg-agens
        pg_version: 17
        pg_packages: [ agensgraph, pgsql-common ]
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] }

    # 10. pgedge kernel (stock pigsty pgsql repo path)
    pg-edge:
      hosts:
        10.10.10.19: { pg_seq: 1, pg_role: primary }
      vars:
        pg_mode: pgedge
        pg_cluster: pg-edge
        pg_version: 18
        pg_packages: [ pgedge, pgsql-common ]
        pg_libs: 'spock, lolor, pg_stat_statements, auto_explain'
        pg_users:
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [spock, snowflake, lolor] }

  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    node_repo_modules: node,infra,pgsql
    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
    infra_portal:
      home : { domain: i.pigsty }

    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

This template uses single-node clusters to show the minimum viable configuration for different kernels:

  • pg-citus: PostgreSQL 18 + Citus
  • pg-ivory: IvorySQL, compatible with PostgreSQL 18
  • pg-mssql: Babelfish, compatible with PostgreSQL 17
  • pg-polar: PolarDB for PostgreSQL, compatible with PostgreSQL 17
  • pg-tde: Percona PostgreSQL 18 + pg_tde
  • pg-oriole: OrioleDB, supports PostgreSQL 16, 17, and 18; the current demo config defaults to PG18
  • pg-mysql: OpenHalo, compatible with PostgreSQL 14
  • pg-mongo: DocumentDB backend for PostgreSQL Mongo mode, default PostgreSQL 18
  • pg-agens: AgensGraph, compatible with PostgreSQL 17
  • pg-edge: pgEdge, compatible with PostgreSQL 18

Notes:

  • Package support varies by kernel, OS, and architecture. Confirm the target repository is available before deployment.
  • This template includes permissive access rules for demo use. For production, use a dedicated kernel template and tighten HBA and password policies.

7.43 - demo/minio

Four-node x four-drive HA S3 object-storage cluster demo; current source defaults to Silo.

demo/minio demonstrates a highly available S3 object-storage cluster with four nodes and four drives per node, for 16 drives total. The template retains MINIO module compatibility naming and explicitly sets minio_type: silo; the current v4.5.0 source accepts only this value, and both deployment and removal roles default to silo. Still verify it together with the exact target, cluster identity, and data paths before removal.

For more tutorials, see the MINIO module documentation.


Overview

  • Config Name: demo/minio
  • Node Count: Four nodes
  • Description: High-availability multi-node multi-drive S3 object-storage demo (currently defaults to Silo)
  • OS Distro: el8, el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64, aarch64
  • Related: meta

Usage:

./configure -c demo/minio

Note: This is a four-node template. You need to modify the IP addresses of the other three nodes after generating the configuration.


Content

Source: pigsty/conf/demo/minio.yml

---
#==============================================================#
# File      :   minio.yml
# Desc      :   pigsty: 4 node x 4 disk MNMD minio clusters
# Ctime     :   2023-01-07
# Mtime     :   2026-08-09
# Docs      :   https://pigsty.io/docs/minio
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# One pass installation with:
# ./deploy.yml
#==============================================================#
# 1.  minio-1 @ 10.10.10.10:9000 -  - (9002) svc <-x  10.10.10.9:9002
# 2.  minio-2 @ 10.10.10.11:9000 -xx- (9002) svc <-x <----------------
# 3.  minio-3 @ 10.10.10.12:9000 -xx- (9002) svc <-x  sss.pigsty:9002
# 4.  minio-4 @ 10.10.10.13:9000 -  - (9002) svc <-x  (intranet dns)
#==============================================================#
# use minio load balancer service (9002) instead of direct access (9000)
# mcli alias set sss https://sss.pigsty:9002 minioadmin S3User.MinIO
#==============================================================#
# https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-multi-node-multi-drive.html
# MINIO_VOLUMES="https://minio-{1...4}.pigsty:9000/data{1...4}/minio"


all:
  children:

    # infra cluster for proxy, monitor, alert, etc...
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # minio cluster with 4 nodes and 4 drivers per node
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
        10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
        10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
        10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
      vars:
        minio_type: silo
        minio_cluster: minio
        minio_data: '/data{1...4}'
        minio_buckets:                    # list of minio bucket to be created
          - { name: pgsql }
          - { name: meta ,versioning: true }
          - { name: data }
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

        # bind a node l2 vip (10.10.10.9) to minio cluster (optional)
        node_cluster: minio
        vip_enabled: true
        vip_vrid: 128
        vip_address: 10.10.10.9

        # expose minio service with haproxy on all nodes
        haproxy_services:
          - name: minio                    # [REQUIRED] service name, unique
            port: 9002                     # [REQUIRED] service port, unique
            balance: leastconn             # [OPTIONAL] load balancer algorithm
            options:                       # [OPTIONAL] minio health check
              - option httpchk
              - option http-keep-alive
              - http-check send meth OPTIONS uri /minio/health/live
              - http-check expect status 200
            servers:
              - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
              - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

    #etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } } }
    #pgsql:
    #  hosts:
    #    10.10.10.10: { pg_seq: 1 , pg_role: primary }
    #    10.10.10.11: { pg_seq: 2 , pg_role: replica }
    #    10.10.10.12: { pg_seq: 3 , pg_role: replica }
    #    10.10.10.13: { pg_seq: 4 , pg_role: replica }
    #  vars:
    #    pg_cluster: pgsql
    #    pgbackrest_method: minio

  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe

    # build a local repo without PostgreSQL packages
    repo_modules: infra,node
    repo_packages: "{{ repo_packages_default | reject('equalto', 'pgsql-utility') | list }}"
    repo_extra_packages: []

    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

      # domain names to access minio web console via nginx web portal (optional)
      minio        : { domain: m.pigsty     ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
      minio10      : { domain: m10.pigsty   ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
      minio11      : { domain: m11.pigsty   ,endpoint: "10.10.10.11:9001" ,scheme: https ,websocket: true }
      minio12      : { domain: m12.pigsty   ,endpoint: "10.10.10.12:9001" ,scheme: https ,websocket: true }
      minio13      : { domain: m13.pigsty   ,endpoint: "10.10.10.13:9001" ,scheme: https ,websocket: true }

    minio_endpoint: https://sss.pigsty:9002   # explicit overwrite minio endpoint with haproxy port
    node_etc_hosts: ["10.10.10.9 sss.pigsty"] # domain name to access minio from all nodes (required)

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
...

Explanation

demo/minio is a reference configuration for production object storage using the Multi-Node Multi-Drive (MNMD) architecture. Its volume layout, HAProxy health checks, and clients retain MinIO-compatible interfaces.

Key Features:

  • Multi-Node Multi-Drive Architecture: 4 nodes × 4 drives = 16-drive erasure coding group
  • L2 VIP High Availability: Virtual IP binding via Keepalived
  • HAProxy Load Balancing: Unified access endpoint on port 9002
  • Fine-grained Permissions: Separate users and buckets for different applications

Access:

# Configure the S3 alias with mcli (via HAProxy load balancing)
mcli alias set sss https://sss.pigsty:9002 minioadmin S3User.MinIO

# List buckets
mcli ls sss/

# Use console
# Visit https://m.pigsty or https://m10-m13.pigsty

Use Cases:

  • Environments requiring S3-compatible object storage
  • PostgreSQL backup storage (pgBackRest remote repository)
  • Data lake for big data and AI workloads
  • Production environments requiring high-availability object storage

Notes:

  • Each node requires 4 independent disks mounted at /data1 - /data4
  • Production environments recommend at least 4 nodes for erasure coding redundancy
  • VIP requires proper network interface configuration (vip_interface)

7.44 - demo/redis

Four-node demo of Redis replica, Sentinel, and native Cluster modes

demo/redis demonstrates standalone/replica, Sentinel, and native Cluster modes supported by Pigsty’s Redis module in one configuration.


Overview

  • Config Name: demo/redis
  • Node Count: 4
  • Clusters: redis-ms, redis-meta, redis-test
  • Related: demo/demo
./configure -c demo/redis -s

Content

Source: pigsty/conf/demo/redis.yml

---
#==============================================================#
# File      :   redis.yml
# Desc      :   pigsty config for redis clusters
# Ctime     :   2022-11-09
# Mtime     :   2026-08-02
# Docs      :   https://pigsty.io/docs/redis
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

    redis-meta: # redis sentinel x 3
      hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
      vars:
        redis_cluster: redis-meta
        redis_password: 'redis.meta'
        redis_mode: sentinel
        redis_max_memory: 16MB
        redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
          - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

    redis-test: # redis native cluster: 3m x 3s
      hosts:
        10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
        10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
      vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }


  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe

    #================================================================#
    #                         VARS: REDIS                            #
    #================================================================#
    # redis identity
    #redis_cluster:         <CLUSTER> # redis cluster name, required identity parameter
    #redis_node: 1             <NODE> # redis node sequence number, node int id required
    #redis_instances: {}       <NODE> # redis instances definition on this redis node

    # redis node
    redis_fs_main: /data/redis        # redis main data directory, `/data/redis` by default
    redis_exporter_enabled: true      # install redis exporter on redis nodes?
    redis_exporter_port: 9121         # redis exporter listen port, 9121 by default
    redis_exporter_options: ''        # cli args and extra options for redis exporter
    redis_type: redis                 # redis implementation: redis or valkey

    # redis instance
    redis_mode: standalone            # redis mode: standalone,cluster,sentinel
    redis_conf: redis.conf            # redis config template path, except sentinel
    redis_bind_address: '0.0.0.0'     # redis bind address, empty string will use host ip
    redis_max_memory: 32MB            # max memory used by each redis instance
    redis_mem_policy: allkeys-lru     # redis memory eviction policy
    redis_password: ''                # redis password, empty string will disable password
    redis_rdb_save: [ '1200 1' ]      # redis rdb save directives, disable with empty list
    redis_aof_enabled: false          # enable redis append only file?
    redis_rename_commands: { }        # rename redis dangerous commands
    redis_cluster_replicas: 1         # replica number for one master in redis cluster
    redis_sentinel_monitor: []        # sentinel master list, works on sentinel cluster only


    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    haproxy_admin_password: pigsty
...

Explanation

  • redis-ms: a 6379 primary and 6380 replica on one node
  • redis-meta: three Sentinel instances monitoring the redis-ms primary
  • redis-test: a native Redis Cluster across two nodes with three instances per node
  • Small per-instance memory limits keep the topology suitable for demonstrations

The IP addresses, passwords, and memory limits are demonstration values. Adjust them to the real topology, then install the Redis module with the redis.yml playbook.

7.45 - demo/kafka

Four-node dynamic KRaft example with a plaintext single-node dev cluster and a three-node TLS/SCRAM HA baseline

demo/kafka declares two Kafka 4.x dynamic KRaft clusters across four nodes: the plaintext single-node development cluster kf-meta, and the three-node TLS/SCRAM/ACL demonstration cluster kf-test.


Overview

  • Config Name: demo/kafka
  • Node Count: 4
  • kf-meta: Single combined Broker/Controller node in plaintext mode
  • kf-test: Three combined nodes with TLS/SCRAM/ACL, topic replication factor 3, and min.insync.replicas=2
  • Module Status: KAFKA BETA
./configure -c demo/kafka -s
./deploy.yml
./kafka.yml -l kf-meta
./kafka.yml -l kf-test

deploy.yml only deploys the core path and does not run the KAFKA playbook automatically. Each kafka.yml run must select one complete Kafka cluster; the role rejects convergence against only part of a cluster.


Content

Source: pigsty/conf/demo/kafka.yml

---
#==============================================================#
# File      :   kafka.yml
# Desc      :   pigsty: 4 node kafka demo (dynamic KRaft)
# Ctime     :   2026-07-17
# Mtime     :   2026-07-17
# Docs      :   https://pigsty.io/docs/kafka
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# One pass installation with:
# ./deploy.yml
# ./kafka.yml -l kf-main
# ./kafka.yml -l kf-test
#==============================================================#
# 1.  kf-meta-1 @ 10.10.10.10:9092   single-node dev cluster (plaintext)
# 2.  kf-test-1 @ 10.10.10.11:9092 \
# 3.  kf-test-2 @ 10.10.10.12:9092 --- 3-node secure HA demo baseline (scram)
# 4.  kf-test-3 @ 10.10.10.13:9092 /   dynamic KRaft, TLS/SCRAM/ACL, RF=3/minISR=2
#==============================================================#
# kafka clients are cluster-aware and connect to every broker directly:
# bootstrap with e.g. 10.10.10.11:9092,10.10.10.12:9092,10.10.10.13:9092


all:
  children:

    # infra cluster for proxy, monitor, alert, etc..
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # single-node kafka dev cluster: combined broker/controller, plaintext
    kf-meta:
      hosts:
        10.10.10.10: { kafka_seq: 1 }
      vars:
        kafka_cluster: kf-meta
        kafka_topics:
          - { name: quickstart.events ,partitions: 1 ,replication_factor: 1 ,config: { retention.ms: 86400000 } }

    # 3-node secure HA demo baseline: dynamic KRaft, TLS/SCRAM/ACL, RF=3/minISR=2
    kf-test:
      hosts:
        10.10.10.11: { kafka_seq: 1 }
        10.10.10.12: { kafka_seq: 2 }
        10.10.10.13: { kafka_seq: 3 }
      vars:
        kafka_cluster: kf-test
        kafka_security: scram
        kafka_heap_opts: '-Xms512M -Xmx512M' # 2GiB demo nodes cannot safely spare the 1GiB production default
        kafka_users:               # app principal with prefixed topic/group acls
          - name: test-app
            password: KafkaApp.Test
            acls:
              - { resource: topic   ,name: 'test.'       ,pattern: prefixed ,operations: [ Read, Write, Describe ] }
              - { resource: group   ,name: 'test.'       ,pattern: prefixed ,operations: [ Read ] }
              - { resource: cluster ,name: kafka-cluster ,operations: [ Describe, IdempotentWrite ] }
        kafka_topics:
          - name: test.events
            partitions: 3
            replication_factor: 3
            config: { min.insync.replicas: 2 ,cleanup.policy: delete ,retention.ms: 604800000 }

  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    infra_portal:                     # infra services exposed via portal
      home : { domain: i.pigsty }     # default domain name

    # kafka & java packages are required in the local repo for the kafka module (if using local repo)
    repo_extra_packages: [ kafka-stack ,java-runtime ]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
...

Explanation

  • kf-meta creates quickstart.events for single-node development and connectivity tests.
  • kf-test creates the test-app SCRAM user, prefix ACLs, and the three-replica test.events topic.
  • Online installation maps the platform packages kafka-stack and java-runtime; when using only a local repository, cache both complete package groups first.
  • Addresses and passwords in the template are demonstration values. Replace them for your topology and security requirements before deployment.

See the KAFKA module for operations, security, and scaling constraints.

7.46 - demo/mysql

Native MySQL 8.4 pilot template with a standalone instance and a three-node InnoDB Cluster

demo/mysql is the four-node example for the native MySQL 8.4 LTS pilot module. It is distinct from conf/mysql.yml, which provides MySQL protocol compatibility through the OpenHalo PostgreSQL kernel.


Overview

  • Config Name: demo/mysql
  • Node Count: 4
  • my-meta: Standalone MySQL 8.4 instance
  • my-test: Three-node, single-primary InnoDB Cluster with MySQL Router on every member
  • Module Status: MYSQL PILOT; not included in the stable module count
  • Platform Boundary: Supported declared x86_64 RPM/DEB platforms and EL9/EL10 aarch64. Oracle APT currently has no arm64 component, so preflight rejects Debian/Ubuntu ARM.

Replace every CHANGE_ME value in the template. Real deployment also requires explicit approval. Start with read-only preflight checks:

ansible-playbook -i conf/demo/mysql.yml mysql.yml -l my-meta --check
ansible-playbook -i conf/demo/mysql.yml mysql.yml -l my-test --check

After explicitly approving an active-inventory update, run ./configure -c demo/mysql, then run both node.yml and mysql.yml with --check and real convergence against the same complete cluster scope. The three-node cluster does not accept a partial-member scope.


Content

Source: pigsty/conf/demo/mysql.yml

---
#==============================================================#
# File      :   mysql.yml
# Desc      :   MySQL 8.4 LTS standalone and three-node HA template
# Ctime     :   2026-07-16
# Mtime     :   2026-07-19
# Docs      :   https://pigsty.io/docs/mysql
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

# Canonical four-node MySQL platform example:
#   my-meta: one standalone member
#   my-test: three-member InnoDB Cluster in single-primary mode
#
# This file is a template, not the active deployment inventory. Replace every
# CHANGE_ME value and review the target addresses before configure or playbooks;
# MySQL preflight rejects any canonical CHANGE_ME credential left in place.
# Native Oracle 8.4 packages are admitted on x86_64 and EL9/EL10 aarch64. Oracle's
# APT repository currently has no arm64 component, so Ubuntu/Debian ARM is rejected.
#
# Read-only template preview (does not rewrite active pigsty.yml):
#   ansible-playbook -i conf/demo/mysql.yml mysql.yml -l my-meta --check
#   ansible-playbook -i conf/demo/mysql.yml mysql.yml -l my-test --check
# Each limit must include every declared member of the selected cluster group;
# partial HA member limits are rejected before any package or service change.
# After explicit approval to update active inventory, run ./configure -c demo/mysql,
# then repeat node.yml/mysql.yml --check with the same explicit limits.
# node.yml owns the shared trusted CA at /etc/pki/ca.crt; mysql.yml installs
# only MySQL/Router leaf certificates and requires node_ca to be complete.
#
# Real playbooks install/start services and require explicit approval.

all:
  children:
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }

    my-meta:
      hosts:
        10.10.10.10: { mysql_seq: 1 }
      vars: { mysql_cluster: my-meta, node_cluster: my-meta }

    my-test:
      hosts:
        10.10.10.11: { mysql_seq: 1 }
        10.10.10.12: { mysql_seq: 2 }
        10.10.10.13: { mysql_seq: 3 }
      vars: { mysql_cluster: my-test, node_cluster: my-test }

  vars:
    version: v4.5.0
    admin_ip: 10.10.10.10
    region: default                    # default | china; china uses USTC for MySQL

    repo_enabled: false               # use signed upstream repositories directly
    node_repo_modules: node,infra,mysql
    # For a Pigsty local/offline repository, enable repo and cache the complete
    # atomic platform set before provisioning targets:
    # repo_enabled: true
    # repo_extra_packages: [mysql]

    nodename_overwrite: false
    node_tune: oltp

    mysql_root_password: CHANGE_ME_MYSQL_ROOT
    mysql_monitor_password: CHANGE_ME_MYSQL_MONITOR
    mysql_cluster_password: CHANGE_ME_MYSQL_CLUSTER
    # Fixed MySQL 8.4, auto-tuned memory, daily local backup, and exporter are defaults.

    # Pigsty infrastructure credentials; replace before deployment.
    grafana_admin_password: CHANGE_ME_GRAFANA_ADMIN
    grafana_view_password: CHANGE_ME_GRAFANA_VIEW
    haproxy_admin_password: CHANGE_ME_HAPROXY
...

Explanation

  • MySQL server, client, Shell, Router, and XtraBackup are fixed to the 8.4 platform; this is not an arbitrary-version installer.
  • The standalone instance uses 3306. The three-node cluster also uses Group Replication on 33061, with Router RW on 6446 and RO on 6447 on each member.
  • A daily local full XtraBackup and mysqld_exporter are enabled by default. The current pilot does not provide continuous binlog archiving, PITR, or automatic recovery.
  • node.yml installs the shared trust anchor at /etc/pki/ca.crt; the MySQL role only issues and installs leaf certificates.

See the native MySQL pilot documentation for complete constraints and the confirmed removal workflow.

7.47 - build/oss

Pigsty open-source edition offline package build environment configuration

The build/oss configuration template is the build environment configuration for Pigsty open-source edition offline packages, used to batch-build offline installation packages across multiple operating systems.

This configuration is intended for developers and contributors only.


Overview

  • Config Name: build/oss
  • Node Count: Seven nodes (el9, el10, d12, d13, u22, u24, u26)
  • Description: Pigsty open-source edition offline package build environment
  • OS Distro: el9, el10, d12, d13, u22, u24, u26
  • OS Arch: x86_64

Usage:

cp conf/build/oss.yml pigsty.yml

Note: This is a build template with fixed IP addresses, intended for internal use only.


Content

Source: pigsty/conf/build/oss.yml

---
#==============================================================#
# File      :   oss.yml
# Desc      :   Pigsty 3-node building env (PG18)
# Ctime     :   2024-10-22
# Mtime     :   2026-05-01
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:
  vars:
    version: v4.5.0
    admin_ip: 10.10.10.26
    region: china
    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn,*.pigsty.cc"

    # building spec
    pg_version: 18
    repo_modules: infra,node,pgsql
    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, node-package3, pgsql-utility, extra-modules ]
    pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap, pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    # OSS
    cache_pkg_dir: 'dist/${version}'
    repo_extra_packages: [pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    # PRO
    #cache_pkg_dir: 'dist/${version}/pro'
    #repo_extra_packages: [
    #  pg18-main,pg18-time,pg18-gis,pg18-rag,pg18-fts,pg18-olap,pg18-feat,pg18-lang,pg18-type,pg18-util,pg18-func,pg18-admin,pg18-stat,pg18-sec,pg18-fdw,pg18-sim,pg18-etl,
    #  pg17-main,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-util,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
    #  pg16-main,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-util,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
    #  pg15-main,pg15-time,pg15-gis,pg15-rag,pg15-fts,pg15-olap,pg15-feat,pg15-lang,pg15-type,pg15-util,pg15-func,pg15-admin,pg15-stat,pg15-sec,pg15-fdw,pg15-sim,pg15-etl,
    #  pg14-main,pg14-time,pg14-gis,pg14-rag,pg14-fts,pg14-olap,pg14-feat,pg14-lang,pg14-type,pg14-util,pg14-func,pg14-admin,pg14-stat,pg14-sec,pg14-fdw,pg14-sim,pg14-etl,
    #  infra-extra, kafka-stack, java-runtime
    #]

  children:
    el9:  { hosts: { 10.10.10.9:  { pg_cluster: el9  ,pg_seq: 1 ,pg_role: primary }}}
    el10: { hosts: { 10.10.10.10: { pg_cluster: el10 ,pg_seq: 1 ,pg_role: primary }}}
    d12:  { hosts: { 10.10.10.12: { pg_cluster: d12  ,pg_seq: 1 ,pg_role: primary }}}
    d13:  { hosts: { 10.10.10.13: { pg_cluster: d13  ,pg_seq: 1 ,pg_role: primary }}}
    u22:  { hosts: { 10.10.10.22: { pg_cluster: u22  ,pg_seq: 1 ,pg_role: primary }}}
    u24:  { hosts: { 10.10.10.24: { pg_cluster: u24  ,pg_seq: 1 ,pg_role: primary }}}
    u26:  { hosts: { 10.10.10.26: { pg_cluster: u26  ,pg_seq: 1 ,pg_role: primary }}}
    etcd: { hosts: { 10.10.10.26:  { etcd_seq: 1 }}, vars: { etcd_cluster: etcd    }}
    infra:
      hosts:
        10.10.10.9:  { infra_seq: 1, admin_ip: 10.10.10.9  ,ansible_host: el9  }
        10.10.10.10: { infra_seq: 2, admin_ip: 10.10.10.10 ,ansible_host: el10 }
        10.10.10.12: { infra_seq: 3, admin_ip: 10.10.10.12 ,ansible_host: d12  }
        10.10.10.13: { infra_seq: 4, admin_ip: 10.10.10.13 ,ansible_host: d13  }
        10.10.10.22: { infra_seq: 5, admin_ip: 10.10.10.22 ,ansible_host: u22  }
        10.10.10.24: { infra_seq: 6, admin_ip: 10.10.10.24 ,ansible_host: u24  }
        10.10.10.26: { infra_seq: 7, admin_ip: 10.10.10.26 ,ansible_host: u26  }
      vars: { node_tune: oltp }

...

Explanation

The build/oss template is the build configuration for Pigsty open-source edition offline packages.

Build Contents:

  • PostgreSQL 18 and all categorized extension packages
  • Infrastructure packages (Prometheus, Grafana, Nginx, etc.)
  • Node packages (monitoring agents, tools, etc.)
  • Extra modules

Supported Operating Systems:

  • EL9 (Rocky/Alma/RHEL 9)
  • EL10 (Rocky 10 / RHEL 10)
  • Debian 12 (Bookworm)
  • Debian 13 (Trixie)
  • Ubuntu 22.04 (Jammy)
  • Ubuntu 24.04 (Noble)
  • Ubuntu 26.04 (Resolute)

Build Process:

# 1. Prepare build environment
cp conf/build/oss.yml pigsty.yml

# 2. Download packages on each node
./infra.yml -t repo_build

# 3. Package offline installation files
make cache

Use Cases:

  • Pigsty developers building new versions
  • Contributors testing new extensions
  • Enterprise users customizing offline packages

7.48 - build/dev

Pigsty three-node local build and development configuration

The build/dev configuration template is Pigsty’s three-node local build and development environment. It is used to validate repository build and package download workflows across EL9, Debian 12, and Ubuntu 24 nodes.

This template is intended only for developers and contributors.


Overview

  • Config Name: build/dev
  • Node Count: Three nodes (el9, d12, u24)
  • Description: Local build and development environment, default PostgreSQL 18, builds the infra,node,pgsql modules
  • OS Distro: el9, d12, u24
  • OS Arch: x86_64, aarch64
  • Related: build/oss

Usage:

cp conf/build/dev.yml pigsty.yml

Note: This is a fixed-IP development build template. Adjust host addresses for your local environment before use.


Content

Source: pigsty/conf/build/dev.yml

---
#==============================================================#
# File      :   dev.yml
# Desc      :   Pigsty 3-node local build dev config
# Ctime     :   2025-07-17
# Mtime     :   2026-07-05
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:
  children:
    el9:  { hosts: { 10.10.10.9:  { pg_cluster: el9  ,pg_seq: 1 ,pg_role: primary }}}
    el10: { hosts: { 10.10.10.10: { pg_cluster: el10 ,pg_seq: 1 ,pg_role: primary }}}
    d12:  { hosts: { 10.10.10.12: { pg_cluster: d12  ,pg_seq: 1 ,pg_role: primary }}}
    d13:  { hosts: { 10.10.10.13: { pg_cluster: d13  ,pg_seq: 1 ,pg_role: primary }}}
    u22:  { hosts: { 10.10.10.22: { pg_cluster: u22  ,pg_seq: 1 ,pg_role: primary }}}
    u24:  { hosts: { 10.10.10.24: { pg_cluster: u24  ,pg_seq: 1 ,pg_role: primary }}}
    u26:  { hosts: { 10.10.10.26: { pg_cluster: u26  ,pg_seq: 1 ,pg_role: primary }}}
    etcd: { hosts: { 10.10.10.26:  { etcd_seq: 1 }}, vars: { etcd_cluster: etcd    }}
    infra:
      hosts:
        10.10.10.9:  { infra_seq: 1, admin_ip: 10.10.10.9  ,ansible_host: el9  }
        10.10.10.10: { infra_seq: 2, admin_ip: 10.10.10.10 ,ansible_host: el10 }
        10.10.10.12: { infra_seq: 3, admin_ip: 10.10.10.12 ,ansible_host: d12  }
        10.10.10.13: { infra_seq: 4, admin_ip: 10.10.10.13 ,ansible_host: d13  }
        10.10.10.22: { infra_seq: 5, admin_ip: 10.10.10.22 ,ansible_host: u22  }
        10.10.10.24: { infra_seq: 6, admin_ip: 10.10.10.24 ,ansible_host: u24  }
        10.10.10.26: { infra_seq: 7, admin_ip: 10.10.10.26 ,ansible_host: u26  }
      vars: { node_tune: oltp }

  vars:
    version: v4.5.0
    admin_ip: 10.10.10.26
    region: china
    proxy_env:
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn,*.pigsty.cc"

    # PRO
    #cache_pkg_dir: 'dist/${version}/pro'
    #repo_extra_packages: [
    #  pg18-main,pg18-time,pg18-gis,pg18-rag,pg18-fts,pg18-olap,pg18-feat,pg18-lang,pg18-type,pg18-util,pg18-func,pg18-admin,pg18-stat,pg18-sec,pg18-fdw,pg18-sim,pg18-etl,
    #  pg17-main,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-util,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
    #  pg16-main,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-util,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
    #  pg15-main,pg15-time,pg15-gis,pg15-rag,pg15-fts,pg15-olap,pg15-feat,pg15-lang,pg15-type,pg15-util,pg15-func,pg15-admin,pg15-stat,pg15-sec,pg15-fdw,pg15-sim,pg15-etl,
    #  pg14-main,pg14-time,pg14-gis,pg14-rag,pg14-fts,pg14-olap,pg14-feat,pg14-lang,pg14-type,pg14-util,pg14-func,pg14-admin,pg14-stat,pg14-sec,pg14-fdw,pg14-sim,pg14-etl,
    #  infra-extra, kafka-stack, java-runtime
    #]

    # building spec
    pg_version: 18
    cache_pkg_dir: 'dist/${version}'
    repo_modules: infra,node,pgsql
    repo_packages: [ node-bootstrap, infra-package, infra-addons, node-package1, node-package2, node-package3, pgsql-utility, extra-modules ]
    repo_extra_packages: [pg18-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_extensions:                 [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap, pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    repo_upstream:
      # EL 7/8/9/10 REPOS
      - { name: pigsty-local   ,description: 'Pigsty Local'       ,module: local   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://${admin_ip}/pigsty' } ,meta: { skip_if_unavailable: 1 ,priority: 1 ,module_hotfixes: 1 }} # used by intranet nodes
      - { name: pigsty-infra   ,description: 'Pigsty INFRA'       ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/infra/$basearch'               ,china: 'http://beta.pigsty.cc/yum/infra/$basearch' } ,meta: { priority: 12 ,module_hotfixes: 1 }}
      - { name: pigsty-pgsql   ,description: 'Pigsty PGSQL'       ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch' ,china: 'http://beta.pigsty.cc/yum/pgsql/el$releasever.$basearch' } ,meta: { priority: 11 ,module_hotfixes: 1 }}
      - { name: nginx          ,description: 'Nginx Repo'         ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://nginx.org/packages/rhel/$releasever/$basearch/' } ,meta: { module_hotfixes: 1 }}
      - { name: docker-ce      ,description: 'Docker CE'          ,module: infra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/centos/$releasever/$basearch/stable'                       ,china: 'https://mirrors.cloud.tencent.com/docker-ce/linux/centos/$releasever/$basearch/stable https://repo.huaweicloud.com/docker-ce/linux/centos/$releasever/$basearch/stable https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable'   ,europe: 'https://mirrors.xtom.de/docker-ce/linux/centos/$releasever/$basearch/stable' } ,meta: { skip_if_unavailable: 1 }}
      - { name: baseos         ,description: 'EL 8+ BaseOS'       ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/BaseOS/$basearch/os/'                        ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/BaseOS/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/BaseOS/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/BaseOS/$basearch/os/'             ,europe: 'https://mirrors.xtom.de/rocky/$releasever/BaseOS/$basearch/os/'     }}
      - { name: appstream      ,description: 'EL 8+ AppStream'    ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/AppStream/$basearch/os/'                     ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/AppStream/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/AppStream/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/AppStream/$basearch/os/'    ,europe: 'https://mirrors.xtom.de/rocky/$releasever/AppStream/$basearch/os/'  }}
      - { name: extras         ,description: 'EL 8+ Extras'       ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/extras/$basearch/os/'                        ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/extras/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/extras/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/extras/$basearch/os/'             ,europe: 'https://mirrors.xtom.de/rocky/$releasever/extras/$basearch/os/'     }}
      - { name: powertools     ,description: 'EL 8 PowerTools'    ,module: node    ,releases: [8     ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/PowerTools/$basearch/os/'                    ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/PowerTools/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/PowerTools/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/PowerTools/$basearch/os/' ,europe: 'https://mirrors.xtom.de/rocky/$releasever/PowerTools/$basearch/os/' }}
      - { name: crb            ,description: 'EL 9 CRB'           ,module: node    ,releases: [  9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://dl.rockylinux.org/pub/rocky/$releasever/CRB/$basearch/os/'                           ,china: 'https://mirrors.cloud.tencent.com/rocky/$releasever/CRB/$basearch/os/ https://repo.huaweicloud.com/rockylinux/$releasever/CRB/$basearch/os/ https://mirrors.aliyun.com/rockylinux/$releasever/CRB/$basearch/os/'                      ,europe: 'https://mirrors.xtom.de/rocky/$releasever/CRB/$basearch/os/'        }}
      - { name: epel           ,description: 'EL 8+ EPEL'         ,module: node    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://mirrors.edge.kernel.org/fedora-epel/$releasever/Everything/$basearch/'               ,china: 'https://mirrors.cloud.tencent.com/epel/$releasever/Everything/$basearch/ https://repo.huaweicloud.com/epel/$releasever/Everything/$basearch/ https://mirrors.aliyun.com/epel/$releasever/Everything/$basearch/'                       ,europe: 'https://mirrors.xtom.de/epel/$releasever/Everything/$basearch/'     }}
      - { name: pgdg-common    ,description: 'PostgreSQL Common'  ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-$releasever-$basearch'      ,china: 'http://beta.pigsty.cc/yum/pgdg/common/redhat/rhel-$releasever-$basearch'      ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg14         ,description: 'PostgreSQL 14'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/14/redhat/rhel-$releasever-$basearch'          ,china: 'http://beta.pigsty.cc/yum/pgdg/14/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg15         ,description: 'PostgreSQL 15'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/15/redhat/rhel-$releasever-$basearch'          ,china: 'http://beta.pigsty.cc/yum/pgdg/15/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg16         ,description: 'PostgreSQL 16'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/16/redhat/rhel-$releasever-$basearch'          ,china: 'http://beta.pigsty.cc/yum/pgdg/16/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg17         ,description: 'PostgreSQL 17'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-$releasever-$basearch'          ,china: 'http://beta.pigsty.cc/yum/pgdg/17/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg18         ,description: 'PostgreSQL 18'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/18/redhat/rhel-$releasever-$basearch'          ,china: 'http://beta.pigsty.cc/yum/pgdg/18/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg-beta      ,description: 'PostgreSQL Testing' ,module: beta    ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,china: 'http://beta.pigsty.cc/yum/pgdg/testing/19/redhat/rhel-$releasever-$basearch'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg-beta      ,description: 'PostgreSQL Testing' ,module: beta    ,releases: [  9,10] ,arch: [        aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,china: 'http://beta.pigsty.cc/yum/pgdg/testing/19/redhat/rhel-$releasever-$basearch'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg-extras    ,description: 'PostgreSQL Extra'   ,module: extra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/extras/redhat/rhel-$releasever-$basearch'      ,china: 'http://beta.pigsty.cc/yum/pgdg/extras/redhat/rhel-$releasever-$basearch'      ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch'      } ,meta: { module_hotfixes: 1 }}
      - { name: pgdg14-nonfree ,description: 'PostgreSQL 14+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' ,china: 'http://beta.pigsty.cc/yum/pgdg/non-free/14/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 ,skip_if_unavailable: 1 }}
      - { name: pgdg15-nonfree ,description: 'PostgreSQL 15+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' ,china: 'http://beta.pigsty.cc/yum/pgdg/non-free/15/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 ,skip_if_unavailable: 1 }}
      - { name: pgdg16-nonfree ,description: 'PostgreSQL 16+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' ,china: 'http://beta.pigsty.cc/yum/pgdg/non-free/16/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 ,skip_if_unavailable: 1 }}
      - { name: pgdg17-nonfree ,description: 'PostgreSQL 17+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' ,china: 'http://beta.pigsty.cc/yum/pgdg/non-free/17/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 ,skip_if_unavailable: 1 }}
      - { name: pgdg18-nonfree ,description: 'PostgreSQL 18+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' ,china: 'http://beta.pigsty.cc/yum/pgdg/non-free/18/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' } ,meta: { module_hotfixes: 1 ,skip_if_unavailable: 1 }}
      - { name: timescaledb    ,description: 'TimescaleDB'        ,module: extra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/timescale/timescaledb/el/$releasever/$basearch'  }}
      - { name: percona        ,description: 'Percona TDE'        ,module: percona ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/yum/percona/el$releasever.$basearch' ,china: 'http://beta.pigsty.cc/yum/percona/el$releasever.$basearch' ,origin: 'http://repo.percona.com/ppg-18.4/yum/release/$releasever/RPMS/$basearch'  } ,meta: { module_hotfixes: 1 }}
      - { name: groonga        ,description: 'Groonga'            ,module: groonga ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.groonga.org/almalinux/$releasever/$basearch/' }}
      - { name: mysql          ,description: 'MySQL 8.4 LTS'      ,module: mysql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mysql.com/yum/mysql-8.4-community/el/$releasever/$basearch/' } ,meta: { module_hotfixes: 1 }}
      - { name: mongo          ,description: 'MongoDB'            ,module: mongo   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/8.0/$basearch/' }}
      - { name: redis          ,description: 'Redis'              ,module: redis   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://rpmfind.net/linux/remi/enterprise/$releasever/redis72/$basearch/' } ,meta: { module_hotfixes: 1 }}
      - { name: grafana        ,description: 'Grafana'            ,module: grafana ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://rpm.grafana.com', china: 'https://mirrors.cloud.tencent.com/grafana/yum/rpm/' }}
      - { name: kubernetes     ,description: 'Kubernetes'         ,module: kube    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://pkgs.k8s.io/core:/stable:/v1.36/rpm/', china: 'https://mirrors.ustc.edu.cn/kubernetes/core:/stable:/v1.36/rpm/' }}
      - { name: gitlab-ee      ,description: 'Gitlab EE'          ,module: gitlab  ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ee/el/$releasever/$basearch' }}
      - { name: gitlab-ce      ,description: 'Gitlab CE'          ,module: gitlab  ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ce/el/$releasever/$basearch' }}
      - { name: clickhouse     ,description: 'ClickHouse'         ,module: click   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.clickhouse.com/rpm/stable/', china: 'https://repo.huaweicloud.com/clickhouse/rpm/stable/' }}

      # DEB 12/13 Ubuntu 22/24/26 REPOS
      - { name: pigsty-local   ,description: 'Pigsty Local'       ,module: local   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://${admin_ip}/pigsty ./' }}
      - { name: pigsty-pgsql   ,description: 'Pigsty PgSQL'       ,module: pgsql   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main' ,china: 'http://beta.pigsty.cc/apt/pgsql/${distro_codename} ${distro_codename} main' }}
      - { name: pigsty-infra   ,description: 'Pigsty Infra'       ,module: infra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/infra/ generic main'                              ,china: 'http://beta.pigsty.cc/apt/infra/ generic main' }}
      - { name: nginx          ,description: 'Nginx'              ,module: nginx   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://nginx.org/packages/${distro_name} ${distro_codename} nginx' }}
      - { name: docker-ce      ,description: 'Docker'             ,module: infra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.docker.com/linux/${distro_name} ${distro_codename} stable'                               ,china: 'https://mirrors.cloud.tencent.com/docker-ce/linux/${distro_name} ${distro_codename} stable' }}
      - { name: base           ,description: 'Debian Basic'       ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://deb.debian.org/debian/ ${distro_codename} main non-free-firmware'                                  ,china: 'https://mirrors.cloud.tencent.com/debian/ ${distro_codename} main non-free-firmware' }}
      - { name: updates        ,description: 'Debian Updates'     ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://deb.debian.org/debian/ ${distro_codename}-updates main non-free-firmware'                          ,china: 'https://mirrors.cloud.tencent.com/debian/ ${distro_codename}-updates main non-free-firmware' }}
      - { name: security       ,description: 'Debian Security'    ,module: node    ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://security.debian.org/debian-security ${distro_codename}-security main non-free-firmware'            ,china: 'https://mirrors.cloud.tencent.com/debian-security/ ${distro_codename}-security main non-free-firmware' }}
      - { name: base           ,description: 'Ubuntu Basic'       ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}           main universe multiverse restricted' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}           main restricted universe multiverse' }}
      - { name: updates        ,description: 'Ubuntu Updates'     ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-updates   main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}-updates   main restricted universe multiverse' }}
      - { name: backports      ,description: 'Ubuntu Backports'   ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-backports main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}-backports main restricted universe multiverse' }}
      - { name: security       ,description: 'Ubuntu Security'    ,module: node    ,releases: [         22,24,26] ,arch: [x86_64         ] ,baseurl: { default: 'https://mirrors.edge.kernel.org/ubuntu/ ${distro_codename}-security  main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu/ ${distro_codename}-security  main restricted universe multiverse' }}
      - { name: base           ,description: 'Ubuntu Basic'       ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}             main universe multiverse restricted' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}           main restricted universe multiverse' }}
      - { name: updates        ,description: 'Ubuntu Updates'     ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-updates     main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}-updates   main restricted universe multiverse' }}
      - { name: backports      ,description: 'Ubuntu Backports'   ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-backports   main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}-backports main restricted universe multiverse' }}
      - { name: security       ,description: 'Ubuntu Security'    ,module: node    ,releases: [         22,24,26] ,arch: [        aarch64] ,baseurl: { default: 'http://ports.ubuntu.com/ubuntu-ports/ ${distro_codename}-security    main restricted universe multiverse' ,china: 'https://mirrors.cloud.tencent.com/ubuntu-ports/ ${distro_codename}-security  main restricted universe multiverse' }}
      - { name: pgdg           ,description: 'PGDG'               ,module: pgsql   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://beta.pigsty.cc/apt/pgdg/ ${distro_codename}-pgdg main' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/apt/ ${distro_codename}-pgdg main' }}
      - { name: pgdg-beta      ,description: 'PGDG Beta'          ,module: beta    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://beta.pigsty.cc/apt/pgdg/ ${distro_codename}-pgdg-testing main 19' ,china: 'https://mirrors.cloud.tencent.com/postgresql/repos/apt/ ${distro_codename}-pgdg-testing main 19' }}
      - { name: timescaledb    ,description: 'TimescaleDB'        ,module: extra   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/timescale/timescaledb/${distro_name}/ ${distro_codename} main' }}
      - { name: citus          ,description: 'Citus'              ,module: extra   ,releases: [11,12,   22      ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packagecloud.io/citusdata/community/${distro_name}/ ${distro_codename} main' } }
      - { name: percona        ,description: 'Percona TDE'        ,module: percona ,releases: [   12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.pigsty.io/apt/percona ${distro_codename} main' ,china: 'http://beta.pigsty.cc/apt/percona ${distro_codename} main' }}
      - { name: groonga        ,description: 'Groonga Debian'     ,module: groonga ,releases: [11,12,13         ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.groonga.org/debian/ ${distro_codename} main' }}
      - { name: groonga        ,description: 'Groonga Ubuntu'     ,module: groonga ,releases: [         22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://ppa.launchpadcontent.net/groonga/ppa/ubuntu/ ${distro_codename} main' }}
      - { name: mysql          ,description: 'MySQL 8.4 LTS'      ,module: mysql   ,releases: [   12,13,22,24   ] ,arch: [x86_64         ] ,baseurl: { default: 'https://repo.mysql.com/apt/${distro_name} ${distro_codename} mysql-8.4-lts' ,china: 'https://mirrors.ustc.edu.cn/mysql-repo/apt/${distro_name} ${distro_codename} mysql-8.4-lts' }}
      - { name: mongo          ,description: 'MongoDB'            ,module: mongo   ,releases: [   12,   22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://repo.mongodb.org/apt/${distro_name} ${distro_codename}/mongodb-org/8.0 multiverse' ,china: 'https://mirrors.cloud.tencent.com/mongodb/apt/${distro_name} ${distro_codename}/mongodb-org/8.0 multiverse' }}
      - { name: redis          ,description: 'Redis'              ,module: redis   ,releases: [11,12,   22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.redis.io/deb ${distro_codename} main' }}
      - { name: llvm           ,description: 'LLVM'               ,module: llvm    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.llvm.org/${distro_codename}/ llvm-toolchain-${distro_codename} main' ,china: 'https://mirrors.tuna.tsinghua.edu.cn/llvm-apt/${distro_codename}/ llvm-toolchain-${distro_codename} main' }}
      - { name: haproxyd       ,description: 'Haproxy Debian'     ,module: haproxy ,releases: [   12            ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://haproxy.debian.net/ ${distro_codename}-backports-3.2 main' }}
      - { name: haproxyu       ,description: 'Haproxy Ubuntu'     ,module: haproxy ,releases: [            24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://ppa.launchpadcontent.net/vbernat/haproxy-3.2/ubuntu/ ${distro_codename} main' }}
      - { name: grafana        ,description: 'Grafana'            ,module: grafana ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://apt.grafana.com stable main' ,china: 'https://mirrors.cloud.tencent.com/grafana/apt/ stable main' }}
      - { name: kubernetes     ,description: 'Kubernetes'         ,module: kube    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /', china: 'https://mirrors.ustc.edu.cn/kubernetes/core:/stable:/v1.36/deb/ /' }}
      - { name: gitlab-ee      ,description: 'Gitlab EE'          ,module: gitlab  ,releases: [11,12,13,22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ee/${distro_name}/ ${distro_codename} main' }}
      - { name: gitlab-ce      ,description: 'Gitlab CE'          ,module: gitlab  ,releases: [11,12,13,22,24   ] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.gitlab.com/gitlab/gitlab-ce/${distro_name}/ ${distro_codename} main' }}
      - { name: clickhouse     ,description: 'ClickHouse'         ,module: click   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://packages.clickhouse.com/deb/ stable main', china: 'https://repo.huaweicloud.com/clickhouse/deb/ stable main' }}

...

Explanation

build/dev is mainly used to validate the Pigsty software repository build pipeline, not for ordinary production installation.

Key Features:

  • Default pg_version: 18
  • Local cache directory is dist/${version}
  • Builds infra,node,pgsql modules by default
  • Preloads PostgreSQL 18 full-category extension package groups
  • Covers both RPM and DEB build paths through three distro nodes

Use Cases:

  • Pigsty new version build validation
  • Software repository and mirror source debugging
  • Extension package download and cache testing

7.49 - demo/remote

Monitor remote PostgreSQL and cloud RDS with pg_exporter instances on an INFRA node

demo/remote deploys no local PostgreSQL cluster. Instead, it declares multiple pg_exporters on an INFRA node to monitor remote PostgreSQL, PolarDB, or cloud RDS instances.


Overview

  • Config Name: demo/remote
  • Local Node Count: One INFRA node
  • Example Exporter Ports: 20001-20016
  • Related: PG Exporter
./configure -c demo/remote [-i <infra_ip>]

Content

Source: pigsty/conf/demo/remote.yml

---
#==============================================================#
# File      :   remote.yml
# Desc      :   Monitoring Remote RDS with pigsty
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:
  children:

    infra:            # infra cluster for proxy, monitor, alert, etc..
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:           # install pg_exporter for remote postgres RDS on a group 'infra'
        pg_exporters: # list all remote instances here, alloc a unique unused local port as k
          20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 }
          20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.11 , pg_port: 5432 }
          20003: { pg_cluster: pg-bar, pg_seq: 2, pg_host: 10.10.10.12 , pg_exporter_url: 'postgres://dbuser_monitor:[email protected]:5432/postgres?sslmode=disable'}
          20004: { pg_cluster: pg-bar, pg_seq: 3, pg_host: 10.10.10.13 , pg_monitor_username: dbuser_monitor, pg_monitor_password: DBUser.Monitor }

          20011:
            pg_cluster: pg-polar                        # RDS Cluster Name (Identity, Explicitly Assigned, used as 'cls')
            pg_seq: 1                                   # RDS Instance Seq (Identity, Explicitly Assigned, used as part of 'ins')
            pg_host: pxx.polardbpg.rds.aliyuncs.com     # RDS Host Address
            pg_port: 1921                               # RDS Port
            pg_exporter_include_database: 'test'        # Only monitoring database in this list
            pg_monitor_username: dbuser_monitor         # monitor username, overwrite default
            pg_monitor_password: DBUser_Monitor         # monitor password, overwrite default
            pg_databases: [{ name: test }]              # database to be added to grafana datasource

          20012:
            pg_cluster: pg-polar                        # RDS Cluster Name (Identity, Explicitly Assigned, used as 'cls')
            pg_seq: 2                                   # RDS Instance Seq (Identity, Explicitly Assigned, used as part of 'ins')
            pg_host: pe-xx.polarpgmxs.rds.aliyuncs.com  # RDS Host Address
            pg_port: 1521                               # RDS Port
            pg_databases: [{ name: test }]              # database to be added to grafana datasource

          20014:
            pg_cluster: pg-rds
            pg_seq: 1
            pg_host: pgm-xx.pg.rds.aliyuncs.com
            pg_port: 5432
            pg_exporter_auto_discovery: true
            pg_exporter_include_database: 'rds'
            pg_monitor_username: dbuser_monitor
            pg_monitor_password: DBUser_Monitor
            pg_databases: [ { name: rds } ]

          20015:
            pg_cluster: pg-rdsha
            pg_seq: 1
            pg_host: pgm-2xx8wu.pg.rds.aliyuncs.com
            pg_port: 5432
            pg_exporter_auto_discovery: true
            pg_exporter_include_database: 'rds'
            pg_databases: [{ name: test }, {name: rds}]

          20016:
            pg_cluster: pg-rdsha
            pg_seq: 2
            pg_host: pgr-xx.pg.rds.aliyuncs.com
            pg_exporter_auto_discovery: true
            pg_exporter_include_database: 'rds'
            pg_databases: [{ name: test }, {name: rds}]
  
  
  vars:
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default,china,europe

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

Each pg_exporters entry uses a unique local listen port and declares the remote instance’s pg_cluster, pg_seq, pg_host, and optional connection settings. The template demonstrates complete URLs, split credentials, database allowlists, and auto-discovery.

All hostnames and credentials are placeholders. Keep only the entries you need, use a least-privilege monitoring account, and never commit real RDS passwords.

7.50 - demo/saas

Legacy single-node SaaS bundle with PostgreSQL, Silo, Redis, and multiple application entrypoints

demo/saas is a legacy feature-rich single-node example with predefined business users, databases, and application entrypoints. It demonstrates how PostgreSQL, Silo, Redis, Docker, and the portal can be combined.


Overview

  • Config Name: demo/saas
  • Node Count: Single node
  • Modules: INFRA, ETCD, MINIO, PGSQL, REDIS, DOCKER
  • Related: rich, supabase
./configure -c demo/saas [-i <primary_ip>]

Content

Source: pigsty/conf/demo/saas.yml

---
#==============================================================#
# File      :   saas.yml (1-node)
# Desc      :   Feature rich 1-node template with all extensions
# Ctime     :   2020-05-22
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#


all:

  #==============================================================#
  # Clusters, Nodes, and Modules
  #==============================================================#
  children:

    #----------------------------------#
    # infra: monitor, alert, repo, etc..
    #----------------------------------#
    infra:
      hosts:
        10.10.10.10: { infra_seq: 1 }
      vars:
        docker_enabled: true      # enabled docker with ./docker.yml
        #docker_registry_mirrors: ["https://docker.1panel.live","https://docker.1ms.run","https://docker.xuanyuan.me","https://registry-1.docker.io"]

    #----------------------------------#
    # etcd cluster for HA postgres DCS
    #----------------------------------#
    etcd:
      hosts:
        10.10.10.10: { etcd_seq: 1 }
      vars:
        etcd_cluster: etcd

    #----------------------------------#
    # minio (OPTIONAL backup repo)
    #----------------------------------#
    minio:
      hosts:
        10.10.10.10: { minio_seq: 1 }
      vars:
        minio_cluster: minio
        minio_users:                      # list of minio user to be created
          - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
          - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
          - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

    #----------------------------------#
    # pgsql (singleton on current node)
    #----------------------------------#
    # postgres cluster: pg-meta
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - {name: dbuser_meta     ,password: DBUser.Meta     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
          - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
          - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
          - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
          - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
          - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
          - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }
          - {name: dbuser_odoo     ,password: DBUser.Odoo     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for odoo service ,createdb: true} #,superuser: true}
        pg_databases:
          - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: vector},{name: postgis},{name: timescaledb}]}
          - {name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database  }
          - {name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
          - {name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong api gateway database }
          - {name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
          - {name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database  }
          - {name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database     }
          #- {name: odoo     ,owner: dbuser_odoo     ,revokeconn: true ,comment: odoo main database  }
        pg_hba_rules:
          - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
        pg_libs: 'timescaledb,pg_stat_statements, auto_explain'  # add timescaledb to shared_preload_libraries
        node_crontab:  # make one full backup 1 am everyday
          - '00 01 * * * /pg/bin/pg-backup full'

    redis-ms: # redis classic primary & replica
      hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
      vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }


  vars:                               # global variables
    version: v4.5.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    proxy_env:                        # global proxy env when downloading packages
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
      # http_proxy:  # set your proxy here: e.g http://user:[email protected]
      # https_proxy: # set your proxy here: e.g http://user:[email protected]
      # all_proxy:   # set your proxy here: e.g http://user:[email protected]
    infra_portal:                     # infra services exposed via portal
      home         : { domain: i.pigsty }     # default domain name
      minio        : { domain: m.pigsty    ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      postgrest    : { domain: api.pigsty  ,endpoint: "127.0.0.1:8884" }
      pgadmin      : { domain: adm.pigsty  ,endpoint: "127.0.0.1:8885" }
      pgweb        : { domain: cli.pigsty  ,endpoint: "127.0.0.1:8886" }
      bytebase     : { domain: ddl.pigsty  ,endpoint: "127.0.0.1:8887" }
      jupyter      : { domain: lab.pigsty  ,endpoint: "127.0.0.1:8888", websocket: true }
      gitea        : { domain: git.pigsty  ,endpoint: "127.0.0.1:8889" }
      wiki         : { domain: wiki.pigsty ,endpoint: "127.0.0.1:9002" }
      noco         : { domain: noco.pigsty ,endpoint: "127.0.0.1:9003" }
      supa         : { domain: supa.pigsty ,endpoint: "10.10.10.10:8000", websocket: true }
      dify         : { domain: dify.pigsty ,endpoint: "10.10.10.10:8001", websocket: true }
      odoo         : { domain: odoo.pigsty, endpoint: "127.0.0.1:8069"  , websocket: true }

    #----------------------------------#
    # MinIO Related Options
    #----------------------------------#
    pgbackrest_method: minio          # use minio as backup repo instead of 'local'
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /etc/pki/ca.crt  # minio ca file path, `/etc/pki/ca.crt` by default
        block: y                      # Enable block incremental backup
        bundle: y                     # bundle small files into a single file
        bundle_limit: 20MiB           # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB           # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days
    node_etc_hosts: [ "${admin_ip} i.pigsty sss.pigsty" ]
    dns_records: [ "${admin_ip} api.pigsty adm.pigsty cli.pigsty ddl.pigsty lab.pigsty git.pigsty wiki.pigsty noco.pigsty supa.pigsty dify.pigsty odoo.pigsty" ]

    #----------------------------------#
    # Safe Guard
    #----------------------------------#
    # you can enable these flags after bootstrap, to prevent purging running etcd / pgsql instances
    etcd_safeguard: false             # prevent purging running etcd instance?
    pg_safeguard: false               # prevent purging running postgres instance? false by default

    #----------------------------------#
    # Repo, Node, Packages
    #----------------------------------#
    repo_remove: true                 # remove existing repo on admin node during repo bootstrap
    node_repo_remove: true            # remove existing node repo for node managed by pigsty
    repo_extra_packages: [ pg17-core ,pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]
    pg_version: 18                    # default postgres version
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

The template contains placeholder database users and databases for Grafana, Bytebase, Kong, Gitea, Wiki, NocoDB, and Odoo. It uses Silo as the pgBackRest repository and includes a Redis replica example and multiple portal domains.

This compatibility/reference bundle does not install every listed application automatically. For new deployments, prefer rich plus the relevant app/* template. Remove unused users, databases, and entrypoints and replace all passwords first.

7.51 - demo/wool

Single-node tiny-tuning example for small cloud instances in China

demo/wool targets small cloud instances in China and defaults to region: china, PostgreSQL 18, and the tiny tuning profiles.


Overview

  • Config Name: demo/wool
  • Node Count: Single node
  • Suggested Size: Approximately 2 vCPU / 2 GB for testing
  • Related: meta, slim
./configure -c demo/wool [-i <private_ip>]

Content

Source: pigsty/conf/demo/wool.yml

---
#==============================================================#
# File      :   wool.yml
# Desc      :   Pigsty Aliyun ECS 羊毛机配置文件
# Ctime     :   2020-11-09
# Mtime     :   2025-12-12
# Docs      :   https://pigsty.io/docs/conf
# License   :   Apache-2.0 @ https://pigsty.io/docs/about/license/
# Copyright :   2018-2026  Ruohang Feng / Vonng ([email protected])
#==============================================================#

all:
  children:

    # 建议使用操作系统: RockyLinux 9.4
    # 这里的 10.10.10.10 都应该是你 ECS 的内网 IP 地址,用于安装 Infra/Etcd 模块
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
    etcd:  { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # 定义一个单节点的 PostgreSQL 数据库实例
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_databases:
          - { name: meta ,baseline: cmdb.sql ,schemas: [ pigsty ] }
        pg_users: # 最好把这里的两个样例用户的密码也修改一下
          - { name: dbuser_meta ,password: DBUser.Meta   ,roles: [ dbrole_admin ] }
          - { name: dbuser_view ,password: DBUser.Viewer ,roles: [ dbrole_readonly ] }
        pg_conf: tiny.yml   # 2C/2G 的云服务器,使用微型数据库配置模板
        node_tune: tiny     # 2C/2G 的云服务器,使用微型主机节点参数优化模板
        pgbackrest_enabled: false # 这么点磁盘空间,就别搞数据库物理备份了
        pg_version: 18           # 用 PostgreSQL 18

  vars:
    version: v4.5.0                   # pigsty version string
    region: china
    admin_ip: 10.10.10.10  # 这个 IP 地址应该是你 ECS 的内网IP地址
    infra_portal: # 如果你有自己的 DNS 域名,这里面的域名后缀 pigsty 换成你自己的 DNS 域名
      home : { domain: i.pigsty }     # default domain name
      minio: { domain: m.pigsty  ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
      postgrest: { domain: api.pigsty  ,endpoint: "127.0.0.1:8884" }
      pgadmin: { domain: adm.pigsty  ,endpoint: "127.0.0.1:8885" }
      pgweb: { domain: cli.pigsty  ,endpoint: "127.0.0.1:8886" }
      bytebase: { domain: ddl.pigsty  ,endpoint: "127.0.0.1:8887" ,websocket: true }
      jupyter: { domain: lab.pigsty  ,endpoint: "127.0.0.1:8888", websocket: true }
      gitea: { domain: git.pigsty  ,endpoint: "127.0.0.1:8889" }
      wiki: { domain: wiki.pigsty ,endpoint: "127.0.0.1:9002" }
      noco: { domain: noco.pigsty ,endpoint: "127.0.0.1:9003" }
      supa: { domain: supa.pigsty ,endpoint: "10.10.10.10:8000", websocket: true }

    # 把这里的密码都改掉!你也不想别人随便来串门对吧!
    #----------------------------------------------#
    # PASSWORD : https://pigsty.io/docs/setup/security/
    #----------------------------------------------#
    grafana_admin_password: pigsty
    grafana_view_password: DBUser.Viewer
    pg_admin_password: DBUser.DBA
    pg_monitor_password: DBUser.Monitor
    pg_replication_password: DBUser.Replicator
    patroni_password: Patroni.API
    haproxy_admin_password: pigsty
    minio_secret_key: S3User.MinIO
    etcd_root_password: Etcd.Root
...

Explanation

  • Explicitly sets pg_conf: tiny.yml and node_tune: tiny on pg-meta
  • Expects 10.10.10.10 to be replaced by the cloud instance’s private IP
  • Disables pgBackRest by default to reduce disk usage on a small test host
  • Includes several example portal domains

This template trades backup capability for lower resource use and is suitable only for temporary testing. Production deployments must enable and verify backups, tighten network rules, replace default passwords, and remove unused portal entries.

8 - Linux Repository

The APT / DNF repository to deliver PostgreSQL Kernel, Extensions and Infra packages.

Pigsty has a repository that provides additional PostgreSQL extension packages on mainstream Linux Distros. It is designed to work together with the official PostgreSQL Global Development Group (PGDG) repo. Together, they can provide 576 packaged PostgreSQL extensions out-of-the-box.

PGSQL RepoDescriptionLink
PGSQL RepoPigsty Extension Repo, supplementary extension packagespgsql.md
INFRA RepoPigsty Infrastructure Repo, monitoring/toolsinfra.md
PGDG RepoPGDG Official Repo Mirror, PG Kernelpgdg.md
GPG KeyGPG Public Key, signature verificationgpg.md

Compatibility Overview

OS / ArchOSx86_64aarch64
EL8el818, 17, 16, 15, 1418, 17, 16, 15, 14
EL9el918, 17, 16, 15, 1418, 17, 16, 15, 14
EL10el1018, 17, 16, 15, 1418, 17, 16, 15, 14
Debian 12d1218, 17, 16, 15, 1418, 17, 16, 15, 14
Debian 13d1318, 17, 16, 15, 1418, 17, 16, 15, 14
Ubuntu 22.04u2218, 17, 16, 15, 1418, 17, 16, 15, 14
Ubuntu 24.04u2418, 17, 16, 15, 1418, 17, 16, 15, 14
Ubuntu 26.04u2618, 17, 16, 15, 1418, 17, 16, 15, 14

Get Started

You can enable the pigsty infra & pgsql repo with the pig CLI tool:

Default
curl https://repo.pigsty.io/pig | bash      # download and install the pig CLI tool
pig repo add all -u                         # add linux, pgdg, pigsty repo and update cache
Mirror
curl https://repo.pigsty.cc/pig | bash      # download from mirror site
pig repo add -u                             # add linux, pgdg, pigsty repo and update cache

Manual Install

You can also add these repos to your system manually with the default apt, dnf, yum approach.

APT
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian / Ubuntu distribution codename (bookworm, trixie, jammy, noble, resolute), and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-io.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra generic main
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

# Refresh APT repository cache
sudo apt update
YUM
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory, including two repositories
sudo tee /etc/yum.repos.d/pigsty-io.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1

[pigsty-pgsql]
name=Pigsty PGSQL For el$releasever.$basearch
baseurl=https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo yum makecache;

All the RPM / DEB packages are signed with GPG Key fingerprint (B9BD8B20) in Pigsty repository.


Repository Components

Pigsty has two major repos: INFRA and PGSQL, providing DEB / RPM packages for x86_64 and aarch64 architecture.

The INFRA repo contains packages that are generic to any PostgreSQL version and Linux major version, including Prometheus & Grafana stack, admin tools for Postgres, and many utilities written in Go.

LinuxPackagex86_64aarch64
ELrpm
Debiandeb

The PGSQL repo contains packages that are ad hoc to specific PostgreSQL Major Versions (often ad hoc to a specific Linux distro major version, too). Including extensions and some kernel forks.


Compatibility Details

OS CodeVendorMajorMinorFullnamePG Major VersionComment
el7.x86_64EL77.9CentOS 7 x8615 14 13EOL
el8.x86_64EL88.10RockyLinux 8 x8618 17 16 15 14Near EOL
el8.aarch64EL88.10RockyLinux 8 ARM18 17 16 15 14Near EOL
el9.x86_64EL99.8RockyLinux 9 x8618 17 16 15 14OK
el9.aarch64EL99.8RockyLinux 9 ARM18 17 16 15 14OK
el10.x86_64EL1010.2RockyLinux 10 x8618 17 16 15 14OK
el10.aarch64EL1010.2RockyLinux 10 ARM18 17 16 15 14OK
d11.x86_64Debian1111.11Debian 11 x8617 16 15 14 13EOL
d11.aarch64Debian1111.11Debian 11 ARM17 16 15 14 13EOL
d12.x86_64Debian1212.15Debian 12 x8618 17 16 15 14OK
d12.aarch64Debian1212.15Debian 12 ARM18 17 16 15 14OK
d13.x86_64Debian1313.6Debian 13 x8618 17 16 15 14OK
d13.aarch64Debian1313.6Debian 13 ARM18 17 16 15 14OK
u22.x86_64Ubuntu2222.04.5Ubuntu 22.04 x8618 17 16 15 14OK
u22.aarch64Ubuntu2222.04.5Ubuntu 22.04 ARM18 17 16 15 14OK
u24.x86_64Ubuntu2424.04.4Ubuntu 24.04 x8618 17 16 15 14OK
u24.aarch64Ubuntu2424.04.4Ubuntu 24.04 ARM18 17 16 15 14OK
u26.x86_64Ubuntu2626.04.0Ubuntu 26.04 x8618 17 16 15 14OK
u26.aarch64Ubuntu2626.04.0Ubuntu 26.04 ARM18 17 16 15 14OK

Source

Building specs of these repos and packages are open-sourced on GitHub:

8.1 - PGDG Repo

The official PostgreSQL APT/YUM repository

The Pigsty PGSQL Repo is designed to work together with the official PostgreSQL Global Development Group (PGDG) repo. Together, they can provide 576 packaged PostgreSQL extensions out-of-the-box.

The PGDG mirror is continuously synchronized. Refer to each repository’s InRelease or repomd.xml metadata for its actual state.


Quick Start

You can install pig - the CLI tool, and add pgdg repo with it (recommended):

pig repo add pgdg                           # add pgdg repo file
pig repo add pgdg -u                        # add pgdg repo and update cache
pig repo add pgdg -u --region=default       # add pgdg repo, enforce using the default repo (postgresql.org)
pig repo add pgdg -u --region=china         # add pgdg repo, always use the china mirror (repo.pigsty.cc)
pig repo add pgsql -u                       # pgsql = pgdg + pigsty-pgsql (add pigsty + official PGDG)
pig repo add -u                             # all = node + pgsql (pgdg + pigsty) + infra

Mirror

Since 2025-05, PGDG has closed the rsync/ftp sync channel, which makes almost all mirror sites out-of-sync.

Currently, Pigsty, Yandex, and Xtom are providing regular synced mirror service.

The Pigsty PGDG mirror is a subset of the official PGDG repo, covering EL 7-10, Debian 11-13, and Ubuntu 22.04 - 26.04 on x86_64 and arm64. The stable repository covers supported PostgreSQL 14 - 18 releases, while the beta module additionally provides PostgreSQL 19 Beta.

2025-11 Update Notice: Aliyun/Tsinghua TUNA Resumed

Currently, the Aliyun/Tsinghua TUNA mirror sites have resumed PGDG repository synchronization.


Compatibility

OS CodeVendorMajorPG Major VersionComment
el7.x86_64EL718, 17, 16, 15, 14EOL
el8.x86_64EL818, 17, 16, 15, 14Near EOL
el8.aarch64EL818, 17, 16, 15, 14Near EOL
el9.x86_64EL918, 17, 16, 15, 14OK
el9.aarch64EL918, 17, 16, 15, 14OK
el10.x86_64EL1018, 17, 16, 15, 14OK
el10.aarch64EL1018, 17, 16, 15, 14OK
d11.x86_64Debian1118, 17, 16, 15, 14EOL
d11.aarch64Debian1118, 17, 16, 15, 14EOL
d12.x86_64Debian1218, 17, 16, 15, 14OK
d12.aarch64Debian1218, 17, 16, 15, 14OK
d13.x86_64Debian1318, 17, 16, 15, 14OK
d13.aarch64Debian1318, 17, 16, 15, 14OK
u22.x86_64Ubuntu2218, 17, 16, 15, 14OK
u22.aarch64Ubuntu2218, 17, 16, 15, 14OK
u24.x86_64Ubuntu2418, 17, 16, 15, 14OK
u24.aarch64Ubuntu2418, 17, 16, 15, 14OK
u26.x86_64Ubuntu2618, 17, 16, 15, 14OK
u26.aarch64Ubuntu2618, 17, 16, 15, 14OK

Repo Configuration

EL YUM/DNF Repo

  - { name: pgdg-common    ,description: 'PostgreSQL Common'  ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-$releasever-$basearch'      ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch'      ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/common/redhat/rhel-$releasever-$basearch' }}
  - { name: pgdg14         ,description: 'PostgreSQL 14'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/14/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/14/redhat/rhel-$releasever-$basearch' }}
  - { name: pgdg15         ,description: 'PostgreSQL 15'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/15/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/15/redhat/rhel-$releasever-$basearch' }}
  - { name: pgdg16         ,description: 'PostgreSQL 16'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/16/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/16/redhat/rhel-$releasever-$basearch' }}
  - { name: pgdg17         ,description: 'PostgreSQL 17'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/17/redhat/rhel-$releasever-$basearch' }}
  - { name: pgdg18         ,description: 'PostgreSQL 18'      ,module: pgsql   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/18/redhat/rhel-$releasever-$basearch'          ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch'          ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/18/redhat/rhel-$releasever-$basearch' }}
  - { name: pgdg-beta      ,description: 'PostgreSQL Testing' ,module: beta    ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/testing/19/redhat/rhel-$releasever-$basearch'  }}
  - { name: pgdg-extras    ,description: 'PostgreSQL Extra'   ,module: extra   ,releases: [8,9,10] ,arch: [x86_64, aarch64] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/extras/redhat/rhel-$releasever-$basearch'      ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch'      ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/extras/redhat/rhel-$releasever-$basearch'      }}
  - { name: pgdg14-nonfree ,description: 'PostgreSQL 14+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/14/redhat/rhel-$releasever-$basearch' } ,meta: { skip_if_unavailable: 1 }}
  - { name: pgdg15-nonfree ,description: 'PostgreSQL 15+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/15/redhat/rhel-$releasever-$basearch' } ,meta: { skip_if_unavailable: 1 }}
  - { name: pgdg16-nonfree ,description: 'PostgreSQL 16+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/16/redhat/rhel-$releasever-$basearch' } ,meta: { skip_if_unavailable: 1 }}
  - { name: pgdg17-nonfree ,description: 'PostgreSQL 17+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/17/redhat/rhel-$releasever-$basearch' } ,meta: { skip_if_unavailable: 1 }}
  - { name: pgdg18-nonfree ,description: 'PostgreSQL 18+'     ,module: extra   ,releases: [8,9,10] ,arch: [x86_64         ] ,baseurl: { default: 'https://download.postgresql.org/pub/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' ,china: 'https://mirrors.aliyun.com/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' ,europe: 'https://mirrors.xtom.de/postgresql/repos/yum/non-free/18/redhat/rhel-$releasever-$basearch' } ,meta: { skip_if_unavailable: 1 }}

Debian / Ubuntu APT Repo

  - { name: pgdg           ,description: 'PGDG'               ,module: pgsql   ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg main' ,china: 'https://mirrors.aliyun.com/postgresql/repos/apt/ ${distro_codename}-pgdg main' }}
  - { name: pgdg-beta      ,description: 'PGDG Beta'          ,module: beta    ,releases: [11,12,13,22,24,26] ,arch: [x86_64, aarch64] ,baseurl: { default: 'http://apt.postgresql.org/pub/repos/apt/ ${distro_codename}-pgdg-testing main 19' ,china: 'https://mirrors.aliyun.com/postgresql/repos/apt/ ${distro_codename}-pgdg-testing main 19' }}

APT GPG Key

PGDG APT repo is signed with the following GPG key: B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8 (ACCC4CF8)

MD5 checksum is f54c5c1aa1329dc26e33b29762faaec4, see https://www.postgresql.org/download/linux/debian/ for details.

Official
sudo curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
. /etc/os-release
sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
Mirror
sudo curl -fsSL https://repo.pigsty.cc/apt/pgdg/ACCC4CF8.key -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
. /etc/os-release
sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://repo.pigsty.cc/apt/pgdg/ $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list"

YUM GPG Key

PGDG YUM repo is signed with a series of keys from https://ftp.postgresql.org/pub/repos/yum/keys/. Please choose and use as needed.

8.2 - GPG Key

Import the GPG key for Pigsty repository

You can verify the integrity of the packages you download from Pigsty repository by checking the GPG signature. This document describes how to import the GPG key used to sign the packages.


Summary

All the RPM / DEB packages are signed with GPG key fingerprint (B9BD8B20) in Pigsty repository.

Full: 9592A7BC7A682E7333376E09E7935D8DB9BD8B20 Ruohang Feng (Pigsty) [email protected]

pub   rsa4096 2024-07-16 [SC]
      9592A7BC7A682E7333376E09E7935D8DB9BD8B20
uid           [ultimate] Ruohang Feng (Pigsty) <[email protected]>
sub   rsa4096 2024-07-16 [E]

You can find the public GPG key at: https://repo.pigsty.io/key or https://repo.pigsty.cc/key


Import

On RHEL compatible Linux distributions, you can import this key with the following command:

Default
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null
Mirror
curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

On Debian / Ubuntu compatible Linux distributions, you can import this key with the following command:

Default
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg
Mirror
curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

Public Key

The corresponding public key block is:

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGaV5PwBEACbErI+7yOrsXTT3mR83O6Fw9WyHJqozhyNPF3dA1gAtWpfWqd4
S9x6vBjVwUbIRn21jYgov0hDiaLABNQhRzifvVr0r1IjBW8lhA8zJGaO42Uz0aBW
YIkajOklsXgYMX+gSmy5WXzM31sDQVMnzptHh9dwW067hMM5pJKDslu2pLMwSb9K
QgIFcYsaR0taBkcDg4dNu1gncriD/GcdXIS0/V4R82DIYeIqj2S0lt0jDTACbUz3
C6esrTw2XerCeHKHb9c/V+KMhqvLJOOpy/aJWLrTGBoaH7xw6v0qg32OYiBxlUj9
VEzoQbDfbRkR+jlxiuYP3scUs/ziKrSh+0mshVbeuLRSNfuHLa7C4xTEnATcgD1J
MZeMaJXIcDt+DN+1aHVQjY5YNvr5wA3ykxW51uReZf7/odgqVW3+1rhW5pd8NQKQ
qoVUHOtIrC9KaiGfrczEtJTNUxcNZV9eBgcKHYDXB2hmR2pIf7WvydgXTs/qIsXg
SIzfKjisi795Dd5GrvdLYXVnu9YzylWlkJ5rjod1wnSxkI/CcCJaoPLnXZA9KV7A
cpMWWaUEXP/XBIwIU+vxDd1taBIaPIOv1KIdzvG7QqAQtf5Lphi5HfaGvBud/CVt
mvWhRPJMr1J0ER2xAgU2iZR7dN0vSF6zDqc0W09RAoC0nDS3tupDX2BrOwARAQAB
tCRSdW9oYW5nIEZlbmcgKFBpZ3N0eSkgPHJoQHZvbm5nLmNvbT6JAlEEEwEIADsW
IQSVkqe8emguczM3bgnnk12Nub2LIAUCZpXk/AIbAwULCQgHAgIiAgYVCgkICwIE
FgIDAQIeBwIXgAAKCRDnk12Nub2LIOMuEACBLVc09O4icFwc45R3KMvOMu14Egpn
UkpmBKhErjup0TIunzI0zZH6HG8LGuf6XEdH4ItCJeLg5349UE00BUHNmxk2coo2
u4Wtu28LPqmxb6sqpuRAaefedU6vqfs7YN6WWp52pVF1KdOHkIOcgAQ9z3ZHdosM
I/Y/UxO2t4pjdCAfJHOmGPrbgLcHSMpoLLxjuf3YIwS5NSfjNDd0Y8sKFUcMGLCF
5P0lv5feLLdZvh2Una34UmHKhZlXC5E3vlY9bf/LgsRzXRFQosD0RsCXbz3Tk+zF
+j/eP3WhUvJshqIDuY6eJYCzMjiA8sM5gety+htVJuD0mewp+qAhjxE0d4bIr4qO
BKQzBt9tT2ackCPdgW42VPS+IZymm1oMET0hgZfKiVpwsKO6qxeWn4RW2jJ0zkUJ
MsrrxOPFdZQAtuFcLwa5PUAHHs6XQT2vzxDpeE9lInQ14lshofU5ZKIeb9sbvb/w
P+xnDqvZ1pcotEIBvDK0S0jHbHHqtioIUdDFvdCBlBlYP1TQRNPlJ7TJDBBvhj8i
fmjQsYSV1u36aHOJVGYNHv+SyJpVd3nHCZn97ADM9qHnDm7xljyHXPzIx4FMmBGJ
UTiLH5yxa1xhWr42Iv3TykaQJVbpydmBuegFR8WbWitAvVqI3HvRG+FalLsjJruc
8YDAf7gHdj/937kCDQRmleT8ARAAmJxscC76NZzqFBiaeq2+aJxOt1HGPqKb4pbz
jLKRX9sFkeXuzhfZaNDljnr2yrnQ75rit9Aah/loEhbSHanNUDCNmvOeSEISr9yA
yfOnqlcVOtcwWQK57n6MvlCSM8Js3jdoSmCFHVtdFFwxejE5ok0dk1VFYDIg6DRk
ZBMuxGO7ZJW7TzCxhK4AL+NNYA2wX6b+IVMn6CA9kwNwCNrrnGHR1sblSxZp7lPo
+GsqzYY0LXGR2eEicgKd4lk38gaO8Q4d1mlpX95vgdhGKxR+CM26y9QU0qrO1hXP
Fw6lX9HfIUkVNrqAa1mzgneYXivnLvcj8gc7bFAdweX4MyBHsmiPm32WqjUJFAmw
kcKYaiyfDJ+1wusa/b+7RCnshWc8B9udYbXfvcpOGgphpUuvomKT8at3ToJfEWmR
BzToYYTsgAAX8diY/X53BHCE/+MhLccglEUYNZyBRkTwDLrS9QgNkhrADaTwxsv1
8PwnVKve/ZxwOU0QGf4ZOhA2YQOE5hkRDR5uY2OHsOS5vHsd9Y6kNNnO8EBy99d1
QiBJOW3AP0nr4Cj1/NhdigAujsYRKiCAuPT7dgqART58VU4bZ3PgonMlziLe7+ht
YYxV+wyP6LVqicDd0MLLvG7r/JOiWuABOUxsFFaRecehoPJjeAEQxnWJjedokXKL
HVOFaEkAEQEAAYkCNgQYAQgAIBYhBJWSp7x6aC5zMzduCeeTXY25vYsgBQJmleT8
AhsMAAoJEOeTXY25vYsgG8sP/3UdsWuiwTsf/x4BTW82K+Uk9YwZDnUNH+4dUMED
bKT1C6CbuSZ7Mnbi2rVsmGzOMs9MehIx6Ko8/iCR2OCeWi8Q+wM+iffAfWuT1GK6
7f/VIfoYBUWEa+kvDcPgEbd5Tu7ZdUO/jROVBSlXRSjzK9LpIj7GozBTJ8Vqy5x7
oqbWPPEYtGDVHime8o6f5/wfhNgL3mFnoq6srK7KhwACwfTXlNqAlGiXGa30Yj+b
Cj6IvmxoII49E67/ovMEmzDCb3RXiaL6OATy25P+HQJvWvAam7Qq5Xn+bZg65Mup
vXq3zoX0a7EKXc5vsJVNtTlXO1ATdYszKP5uNzkHrNAN52VRYaowq1vPy/MVMbSI
rL/hTFKr7ZNhmC7jmS3OuJyCYQsfEerubtBUuc/W6JDc2oTI3xOG1S2Zj8f4PxLl
H7vMG4E+p6eOrUGw6VQXjFsH9GtwhkPh/ZGMKENb2+JztJ02674Cok4s5c/lZFKz
mmRUcNjX2bm2K0GfGG5/hAog/CHCeUZvwIh4hZLkdeJ1QsIYpN8xbvY7QP6yh4VB
XrL18+2sontZ45MsGResrRibB35x7IrCrxZsVtRJZthHqshiORPatgy+AiWcAtEv
UWEnnC1xBSasNebw4fSE8AJg9JMCRw+3GAetlotOeW9q7PN6yrXD9rGuV/QquQNd
/c7w
=4rRi
-----END PGP PUBLIC KEY BLOCK-----

Usage

If you wish to distribute your own Repo with your own GPG key, here’s a tutorial:

Install GPG

brew
brew install gnupg pinentry-mac
apt
sudo apt install gnupg2 pinentry-curses
dnf
sudo dnf install gnupg2 pinentry-curses

Generate GPG Key

You can generate a GPG key with the following command:

gpg --full-generate-key

Import GPG Key

If you have a GPG Private key, you can just import it with:

gpg --import mykey.sec.as

List GPG Key

You can list GPG public keys and secret keys with the following commands:

$ gpg --list-key
[keyboxd]
---------
pub   rsa4096 2024-07-16 [SC]
      9592A7BC7A682E7333376E09E7935D8DB9BD8B20
uid           [ unknown] Ruohang Feng (Pigsty) <[email protected]>
sub   rsa4096 2024-07-16 [E]

$ gpg --list-secret-key
[keyboxd]
---------
sec   rsa4096 2024-07-16 [SC]
      9592A7BC7A682E7333376E09E7935D8DB9BD8B20
uid           [ unknown] Ruohang Feng (Pigsty) <[email protected]>
ssb   rsa4096 2024-07-16 [E]

Sign RPM Packages

If you wish to sign your RPM packages with a specific GPG key, you can specify the key in the ~/.rpmmacros file:

%_signature   gpg
%_gpg_path    ~/.gnupg
%_gpg_name    B9BD8B20
%_gpg_digest_algo  sha256
rpm --addsign yourpackage.rpm

Sign DEB Packages

To sign your DEB packages, add the key id to reprepro configuration:

Origin: Pigsty
Label: Pigsty INFRA
Codename: generic
Architectures: amd64 arm64
Components: main
Description: pigsty apt repository for infra components
SignWith: 9592A7BC7A682E7333376E09E7935D8DB9BD8B20

8.3 - INFRA Repo

Packages that are generic to any PostgreSQL version and Linux major version.

The pigsty-infra repo contains packages that are generic to any PostgreSQL version and Linux major version, including Prometheus & Grafana stack, admin tools for Postgres, and many utilities written in Go.

This repo is maintained by Ruohang Feng (Vonng) @ Pigsty, you can find all the build specs on https://github.com/pgsty/infra-pkg. Prebuilt RPM / DEB packages for RHEL / Debian / Ubuntu distros available for x86_64 and aarch64 arch. Hosted on Cloudflare CDN for free global access.

LinuxPackagex86_64aarch64
ELrpm
Debiandeb

You can check the Release - Infra Changelog for the latest updates.


Quick Start

You can add the pigsty-infra repo with the pig CLI tool, it will automatically choose from apt/yum/dnf.

Default
curl https://repo.pigsty.io/pig | bash  # download and install the pig CLI tool
pig repo add infra                      # add pigsty-infra repo file to your system
pig repo update                         # update local repo cache with apt / dnf
Mirror
# use when in mainland China or Cloudflare is down
curl https://repo.pigsty.cc/pig | bash  # install pig from China CDN mirror
pig repo add infra                      # add pigsty-infra repo file to your system
pig repo update                         # update local repo cache with apt / dnf
Hint
# you can manage infra repo with these commands:
pig repo add infra -u       # add repo file, and update cache
pig repo add infra -ru      # remove all existing repo, add repo and make cache
pig repo set infra          # = pigsty repo add infra -ru

pig repo add all            # add infra, node, pgsql repo to your system
pig repo set all            # remove existing repo, add above repos and update cache

Manual Setup

You can also use this repo directly without the pig CLI tool, by adding them to your Linux OS repo list manually:

APT Repo

On Debian / Ubuntu compatible Linux distros, you can add the GPG Key and APT repo file manually with:

Default
# Add Pigsty's GPG public key to your system keychain to verify package signatures, or just trust
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian / Ubuntu distribution codename (bookworm, trixie, jammy, noble, resolute)
# and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra generic main
EOF

# Refresh APT repository cache
sudo apt update
Mirror
# use when in mainland China or Cloudflare is down
# Add Pigsty's GPG public key to your system keychain to verify package signatures, or just trust
curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian / Ubuntu distribution codename (bookworm, trixie, jammy, noble, resolute)
# and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.cc/apt/infra generic main
EOF

# Refresh APT repository cache
sudo apt update
NoKey
# If you don't want to trust any GPG key, just trust the repo directly
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-infra.list > /dev/null <<EOF
deb [trust=yes] https://repo.pigsty.io/apt/infra generic main
EOF

sudo apt update

YUM Repo

On RHEL compatible Linux distros, you can add the GPG Key and YUM repo file manually with:

Default
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo yum makecache;
Mirror
# use when in mainland China or Cloudflare is down
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.cc/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
module_hotfixes=1
EOF

# Refresh YUM/DNF repository cache
sudo yum makecache;
NoKey
# If you don't want to trust any GPG key, just trust the repo directly
sudo tee /etc/yum.repos.d/pigsty-infra.repo > /dev/null <<-'EOF'
[pigsty-infra]
name=Pigsty Infra for $basearch
baseurl=https://repo.pigsty.io/yum/infra/$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 0
module_hotfixes=1
EOF

sudo yum makecache;

Content

For a detailed list of all packages available in the Infra repository, see the Package List.

For the changelog and release history, see the Release Log.


Source

Building specs of this repo is open-sourced on GitHub:

If the platform is not supported, you can also build the packages from source code by yourself.

8.3.1 - Package List

Available packages in the Infra repository

Grafana Stack

NameVersionLicenseComment
grafana13.1.3AGPLv3Observability and visualization platform
loki3.6.7AGPLv3Log aggregation system (obsolete, frozen)
promtail3.6.7AGPLv3Loki log collection agent (obsolete, frozen)
logcli3.6.7AGPLv3Loki query CLI (obsolete, frozen)
grafana-infinity-ds3.11.3Apache-2.0JSON/CSV/XML datasource support
grafana-plugins13.0.0Apache-2.0Extra panel plugins by Pigsty (noarch)

Victoria Stack

NameVersionLicenseComment
victoria-metrics1.149.0Apache-2.0High-performance TSDB, Prometheus alternative
victoria-logs1.52.0Apache-2.0High-performance log storage and query engine
victoria-traces0.10.0Apache-2.0Distributed tracing backend
victoria-metrics-cluster1.149.0Apache-2.0VictoriaMetrics distributed cluster
vmutils1.149.0Apache-2.0VictoriaMetrics CLI utilities
vlogscli1.52.0Apache-2.0VictoriaLogs interactive query client
vlagent1.52.0Apache-2.0VictoriaLogs log collection agent
grafana-victorialogs-ds0.31.0Apache-2.0VictoriaLogs Grafana datasource
grafana-victoriametrics-ds0.25.2Apache-2.0VictoriaMetrics Grafana datasource
Note on Victoria Grafana Datasource Plugins

Pigsty splits the Victoria datasource extensions into architecture-specific sub-packages. If you choose to install these plugins to your own Grafana instance, please configure the following parameter in /etc/grafana/grafana.ini to allow loading unsigned plugins.

allow_loading_unsigned_plugins = victoriametrics-logs-datasource,victoriametrics-metrics-datasource

Prometheus Stack

NameVersionLicenseComment
prometheus3.13.2Apache-2.0Cloud-native monitoring & TSDB
pushgateway1.11.3Apache-2.0Metrics push gateway for short-lived jobs
alertmanager0.33.1Apache-2.0Alert management & notification dispatch
blackbox-exporter0.28.0Apache-2.0Blackbox probing, endpoint availability

Metric Exporters

NameVersionLicenseComment
pg-exporter1.4.1Apache-2.0Advanced Postgres metrics exporter
pgbackrest-exporter0.24.0MITExpose pgbackrest metrics
node-exporter1.12.1Apache-2.0Expose Linux node metrics
keepalived-exporter1.7.1GPL-3.0Expose keepalived/VIP metrics
nginx-exporter1.5.1Apache-2.0Expose nginx metrics
zfs-exporter3.8.1MITExpose zfs metrics
mysqld-exporter0.19.0Apache-2.0Expose mysql metrics
redis-exporter1.89.0MITExpose redis metrics
kafka-exporter1.9.0Apache-2.0Expose kafka metrics
jmx-exporter1.6.0Apache-2.0Expose JVM metrics (noarch)
mongodb-exporter0.52.0Apache-2.0Expose mongodb metrics
mtail3.4.7Apache-2.0Parse logs and generate metrics
vector0.57.0MPL-2.0Versatile log collector

Object Storage

NameVersionLicenseComment
silo20260806000000AGPLv3FOSS S3-compatible object storage maintained by Pigsty
mcli20260806000000AGPLv3FOSS S3 client, now built by pgsty
rustfs1.0.0-rc1Apache-2.0Repository-retained package; not a v4.5 MINIO backend
garage2.3.0AGPL-3.0Lightweight S3
seaweedfs4.41Apache-2.0S3 for small files
rclone1.75.0MITS3 command line tool
restic0.19.1BSD-2Backup tool
juicefs1.4.1Apache-2.0Filesystem over S3
SILO has replaced MinIO

silo and mcli are the Pigsty-maintained server and client. Since 2026-08-06, the package, binary, and systemd service use the silo name while S3/Admin APIs, /minio/* routes, MINIO_* variables, and the on-disk format remain compatible.


Kubernetes

NameVersionLicenseComment
k3s1.36.3Apache-2.0Lightweight Kubernetes; upstream v1.36.3+k3s1
k3s-images1.36.3MultipleExact-match, architecture-specific offline system images

Databases

PostgreSQL related tools, DBMS, and other utilities

NameVersionLicenseComment
etcd3.7.1Apache-2.0Fault-tolerant distributed coordination
kafka4.3.1Apache-2.0Message queue
duckdb1.5.5MITEmbedded OLAP
ferretdb2.7.0Apache-2.0MongoDB over PG
tigerbeetle0.17.9Apache-2.0Financial OLTP
ivorysql5.4Apache-2.0Oracle compatible PG 18.4

Utilities

Pig package manager, PostgreSQL tools, and other database related utilities

NameVersionLicenseComment
pig1.7.0Apache-2.0PG package manager
sow0.3.0Apache-2.0Package repository builder
vip-manager4.2.0BSD-2Bind L2 VIP to PG primary
pg-hardstorage1.2.1Apache-2.0PostgreSQL backup with continuous WAL streaming
pgschema1.12.2Apache-2.0Terraform-style declarative Postgres schema migration CLI
pgstream1.3.1Apache-2.0PostgreSQL replication with DDL changes
pg-timetable7.0.0PostgreSQLAdvanced scheduling for PostgreSQL
timescaledb-tools0.19.0Apache-2.0Optimize timescaledb params
timescaledb-event-streamer0.20.0Apache-2.0CDC on timescaledb hypertable
tigerfs0.7.0MITMount PostgreSQL as a filesystem
dblab0.47.4MITMulti-database CLI tool
rainfrog0.4.3MITTerminal Postgres database management tool
sql-studio0.1.51MITTerminal SQL database explorer
sqlcmd1.10.0MITMS SQL Server CLI client
asciinema3.2.1GPL-3.0Terminal session recorder and player
pev21.23.0PostgreSQLPostgreSQL explain visualizer 2
sealos5.1.1Apache-2.0Battery-included Kubernetes distribution
vray5.52.0MITBuild proxies to bypass network restrictions
xray26.7.28MPL-2.0Next-generation proxy core with advanced routing and transports
gost2.12.0MITGeneral-purpose tunneling and proxy tool written in Go
sabiql1.15.1MITModern SQL client for PostgreSQL and MySQL
postgrest16.1MITPostgreSQL RESTful API server (PostgreSQL 14+)
npgsqlrest3.21.0MIT.NET PostgreSQL REST API generator
caddy2.11.4Apache-2.0Web server with automatic HTTPS
hugo0.164.0Apache-2.0Fast static site generator
cloudflared2026.7.3Apache-2.0Cloudflare tunnel client
headscale0.29.3BSD-3Self-hosted Tailscale control server
stalwart0.16.17AGPLv3Modern full-featured mail server
maddy0.9.5GPL-3.0Lightweight mail server

AI

AI agents, MCP toolboxes, coding IDEs, Python/Go/Node tools…

NameVersionLicenseComment
claude2.1.227ProprietaryClaude Code - Anthropic agentic coding
opencode1.18.16MITTerminal AI coding assistant
codex0.147.0Apache-2.0OpenAI coding agent CLI
crush0.88.1FSL-1.1-MITCharm’s terminal AI coding agent
agentsview0.40.1MITBrowse and replay AI coding agent trajectories in terminal
code1.132.0MITVisual Studio Code editor
code-server4.132.0MITVS Code in the browser
genai-toolbox1.8.0Apache-2.0Google database MCP server
uv0.12.3MITNext-gen Python package manager
golang1.26.5BSD-3Go compiler
nodejs24.19.0MIT/MixedServer-side JavaScript runtime

8.3.2 - Release Log

pigsty-infra repository changelog and observability package release notes

2026-08-12

NameOldNewComment
claude2.1.2262.1.227Official manifest verified via proxy; dual-arch RPM/DEB built
code-server4.131.04.132.0Official dual-architecture RPM/DEB downloaded and verified
grafana-infinity-ds3.11.23.11.3Built as dual-architecture RPM/DEB
mtail3.4.63.4.7Built as dual-architecture RPM/DEB
opencode1.18.151.18.16Built as dual-architecture RPM/DEB
pg-hardstorage1.1.11.2.1Official dual-architecture RPM/DEB downloaded and verified
pig1.6.11.7.0Official dual-architecture RPM/DEB downloaded and verified
postgrest16.016.1Static dual-architecture RPM/DEB; requires PostgreSQL 14+
redis-exporter1.88.01.89.0Built as dual-architecture RPM/DEB
sow0.2.00.3.0Official dual-architecture RPM/DEB downloaded and verified
stalwart0.16.160.16.17Built as dual-architecture RPM/DEB

2026-08-08

NameOldNewComment
claude2.1.2232.1.226Official manifest verified via proxy; dual-arch built
codex0.146.10.147.0Stable tag rust-v0.147.0; dual-arch built
crush0.88.00.88.1Official tarballs repacked as 1PGSTY with license
grafana13.1.213.1.3Official dual-architecture RPM/DEB artifacts
opencode1.18.141.18.15Built as dual-architecture RPM/DEB
postgrest14.1616.0Static dual-architecture assets; requires PostgreSQL 14+
rainfrog0.4.20.4.3Built as dual-architecture RPM/DEB
rustfs1.0.0-b121.0.0-rc1Upstream rc.1-preview.1; dual-arch RPM/DEB built
uv0.12.20.12.3Built as dual-architecture RPM/DEB

2026-08-07

NameOldNewComment
claude2.1.2222.1.223Official manifest verified via proxy; built
codex0.146.00.146.1Stable tag rust-v0.146.1; built
code1.131.01.132.0Official dual-architecture RPM/DEB verified
dblab0.47.20.47.4Built as dual-architecture RPM/DEB
grafana-infinity-ds3.11.13.11.2Built as dual-architecture RPM/DEB
grafana-victorialogs-ds0.30.10.31.0Built as dual-architecture RPM/DEB
k3s1.36.21.36.3Official stable channel v1.36.3+k3s1; built
k3s-images1.36.21.36.3Exact-match dual-architecture airgap images; built
mcli2026080400000020260806000000Official pgsty fork dual-architecture RPM/DEB verified
opencode1.18.131.18.14Built as dual-architecture RPM/DEB
pgschema1.12.11.12.2Official dual-architecture RPM/DEB verified
seaweedfs4.404.41Built as dual-architecture RPM/DEB
silominio 2026080400000020260806000000Official replacement; dual-architecture RPM/DEB verified
uv0.12.10.12.2Built as dual-architecture RPM/DEB
victoria-metrics1.148.01.149.0Main, cluster, and vmutils packages built for both arches

ferretdb2 was also rebuilt at the current 2.7.0 version for both architectures. silo now officially replaces minio and is included in the Infra repository together with mcli.


2026-08-05

NameOldNewComment
agentsview0.39.00.40.1Built as dual-architecture RPM/DEB
claude2.1.2202.1.222Official manifest verified via proxy; built
code-server4.130.04.131.0Official artifacts downloaded and verified
crush0.87.00.88.0Official links only; redistribution blocked
grafana13.1.113.1.2Official artifacts verified; security fix
juicefs1.4.01.4.1Built as dual-architecture RPM/DEB
mcli2026041700000020260804000000pgsty fork artifacts downloaded and verified
minio2026061800000020260804000000pgsty fork artifacts downloaded and verified
mongodb-exporter0.51.00.52.0Built as dual-architecture RPM/DEB
mtail3.0.83.4.6Built as dual-architecture RPM/DEB
nodejs24.18.124.19.0Node.js 24.x LTS; built
opencode1.18.91.18.13Built as dual-architecture RPM/DEB
pg-hardstorage1.0.171.1.1Official artifacts downloaded and verified
pgbackrest-exporter0.23.00.24.0Built as dual-architecture RPM/DEB
pgstream1.2.51.3.1Built as dual-architecture RPM/DEB
rclone1.74.41.75.0Official artifacts downloaded and verified
rustfs1.0.0-b111.0.0-b12Beta line; built as dual-architecture RPM/DEB
stalwart0.16.150.16.16Built as dual-architecture RPM/DEB
uv0.12.00.12.1Built as dual-architecture RPM/DEB
vray5.51.25.52.0Latest stable; built as dual-architecture RPM/DEB
xray26.3.2726.7.28Latest dated release; built as dual-architecture RPM/DEB
prometheus3.13.13.13.2Security and stability release
pig1.6.01.6.1Refreshed extension catalog

2026-07-30

NameOldNewComment
agentsview0.38.10.39.0
claude2.1.2182.1.220
cloudflared2026.7.22026.7.3
code1.130.01.131.0
code-server4.129.04.130.0
codex0.145.00.146.0Release tag rust-v0.146.0
crush0.86.00.87.0
dblab0.46.00.47.2
etcd3.7.03.7.1
genai-toolbox1.7.01.8.0Source build; Rocky 8/9 and Debian 12 verified
headscale0.29.20.29.3
nodejs24.18.024.18.1Security release
opencode1.18.41.18.9
pg-exporter1.4.01.4.1Official release artifacts
pg-hardstorage1.0.131.0.17
pgschema1.12.01.12.1
pgstream1.2.21.2.5
pig1.5.11.6.0
postgrest14.1514.16
rainfrog0.3.200.4.2
redis-exporter1.87.01.88.0
rustfs1.0.0-beta.101.0.0-beta.11Preview releases excluded
stalwart0.16.140.16.15
uv0.11.310.12.0
victoria-traces0.9.40.10.0

2026-07-23

NameOldNewComment
claude2.1.2152.1.218Verified against the official manifest via proxy
codex0.144.60.145.0Release tag rust-v0.145.0
dblab0.44.10.46.0
duckdb1.5.41.5.5
grafana-infinity-ds3.8.03.11.1
grafana-victorialogs-ds0.30.00.30.1
opencode1.18.31.18.4
pg-timetable6.3.07.0.0Major release
pgstream1.2.01.2.2
stalwart0.16.130.16.14
uv0.11.290.11.31
grafana13.1.013.1.1Direct-download artifacts
pg-hardstorage1.0.121.0.13Direct-download artifacts
crush0.85.00.86.0Direct-download artifacts
code1.129.11.130.0Direct-download artifacts

2026-07-20

Rename xxx_exporter rpm packages to xxx-exporter style to keep consistent with deb packaging convention.

NameOldNewComment
pg-exporter1.3.01.4.0Repackaged from the upstream Linux tarball
victoria-metrics1.147.01.148.0VictoriaMetrics main package
victoria-metrics-cluster1.147.01.148.0VictoriaMetrics companion package
vmutils1.147.01.148.0VictoriaMetrics companion package
victoria-logs1.51.01.52.0VictoriaLogs main package
vlogscli1.51.01.52.0VictoriaLogs companion package
vlagent1.51.01.52.0VictoriaLogs companion package
grafana-victorialogs-ds0.29.00.30.0
seaweedfs4.394.40
rustfs1.0.0-b91.0.0-b10Prerelease line; preview releases excluded
sabiql1.14.01.15.1
timescaledb-tools0.19.0-10.19.0-2Bundles timescaledb-parallel-copy 0.13.0
claude2.1.2112.1.215Downloaded through the 8118 proxy and verified
codex0.144.40.144.6Release tag rust-v0.144.6
genai-toolbox1.6.01.7.0External build from official GCS binary and arm64 container artifact
opencode1.18.21.18.3
pg-hardstorage1.0.101.0.12Direct-download artifacts
code1.129.01.129.1Direct-download artifacts
code-server4.128.04.129.0Direct-download artifacts
pev21.22.01.23.0Noarch package
k3s-1.36.2Upstream v1.36.2+k3s1; amd64 and arm64
k3s-images-1.36.2Exact-match system image package for both architectures

2026-07-16

NameOldNewComment
jmx-exporter-1.6.0New noarch package
node_exporter1.11.11.12.1
redis_exporter1.86.01.87.0
etcd3.6.133.7.0
dblab0.43.00.44.1
pgstream1.1.11.2.0
rainfrog0.3.190.3.20
rustfs1.0.0-b81.0.0-b9Prerelease line
agentsview0.37.50.38.1
claude2.1.2062.1.211Downloaded through the 8118 proxy and verified
codex0.144.10.144.4Release tag rust-v0.144.4
stalwart0.16.120.16.13
npgsqlrest3.20.03.21.0
postgrest14.1414.15
opencode1.17.181.18.2
uv0.11.280.11.29
vector0.56.00.57.0Direct-download artifacts
pg-hardstorage1.0.81.0.10Direct-download artifacts
crush0.84.00.85.0Direct-download artifacts
code1.128.01.129.0Direct-download artifacts
code-server4.127.04.128.0Direct-download artifacts
cloudflared2026.7.12026.7.2Direct-download artifacts

2026-07-10

NameOldNewComment
prometheus3.13.03.13.1
seaweedfs4.384.39
agentsview0.36.10.37.5
claude2.1.2042.1.206Downloaded through the 8118 proxy and verified
codex0.143.00.144.1Release tag rust-v0.144.1
npgsqlrest3.19.03.20.0
opencode1.17.151.17.18
crush0.82.00.84.0Direct-download artifacts
rclone1.74.31.74.4Direct-download artifacts
cloudflared2026.6.12026.7.1Direct-download artifacts

2026-07-08

NameOldNewComment
pg-hardstorage-1.0.8
alertmanager0.33.00.33.1
victoria-metrics1.146.01.147.0
victoria-metrics-cluster1.146.01.147.0
vmutils1.146.01.147.0
restic0.19.00.19.1
juicefs1.3.11.4.0
dblab0.42.10.43.0
pgstream1.1.01.1.1
tigerbeetle0.17.80.17.9
grafana-victoriametrics-ds0.25.10.25.2
hugo0.163.30.164.0
seaweedfs4.374.38
v2ray5.49.05.51.2
sabiql1.13.01.14.0
claude2.1.2012.1.204
codex0.142.50.143.0
stalwart0.16.110.16.12
opencode1.17.131.17.15
uv0.11.260.11.28
golang1.26.41.26.5
pgschema1.11.11.12.0
crush0.81.00.82.0
code1.127.01.128.0
pig1.5.01.5.1

2026-07-04

NameOldNewComment
prometheus3.12.03.13.0
victoria-traces0.9.30.9.4
etcd3.6.123.6.13
dblab0.42.00.42.1
grafana-victoriametrics-ds0.25.00.25.1
headscale0.29.10.29.2
seaweedfs4.354.37
agentsview0.34.50.36.1
claude2.1.1872.1.201
codex0.142.00.142.5
stalwart0.16.100.16.11
genai-toolbox1.5.01.6.0
npgsqlrest3.18.13.19.0
postgrest14.1314.14
opencode1.17.91.17.13
uv0.11.240.11.26
grafana13.0.213.1.0
crush0.79.10.81.0
code1.125.11.127.0
code-server4.125.04.127.0
pig1.4.21.5.0

2026-07-01

NameOld VerNew VerNote
agentsview0.32.10.34.5
alertmanager0.32.20.33.0
asciinema3.2.03.2.1
claude2.1.1722.1.187
codex0.139.00.142.0
dblab0.40.10.42.0
duckdb1.5.31.5.4
grafana-victorialogs-ds0.28.00.29.0
headscale0.28.00.29.1
hugo0.163.00.163.3
kafka4.3.04.3.1
minio2026041700000020260618000000
nodejs24.16.024.18.0
npgsqlrest3.16.33.18.1
opencode1.17.31.17.9
pev21.21.01.22.0
pg_exporter1.2.21.3.0
pgschema1.11.01.11.1
pgstream1.0.31.1.0
pig1.4.11.4.2
rainfrog0.3.180.3.19
sabiql1.12.31.13.0
seaweedfs4.324.35
stalwart0.16.80.16.10
tigerbeetle0.17.60.17.8
uv0.11.200.11.24
victoria-logs1.50.01.51.0
vlagent1.50.01.51.0
vlogscli1.50.01.51.0
victoria-metrics1.145.01.146.0
victoria-metrics-cluster1.145.01.146.0
vmutils1.145.01.146.0
victoria-traces0.9.20.9.3
code1.124.01.125.1
code-server4.123.04.125.0
cloudflared2026.6.02026.6.1
crush0.76.00.79.1
genai-toolbox1.1.01.5.0

2026-06-12

NameOld VerNew VerNote
prometheus3.11.33.12.0
pushgateway1.11.21.11.3
alertmanager0.32.10.32.2
node_exporter1.11.11.11.1Tarball cache restored; version metadata fixed
redis_exporter1.83.01.86.0
victoria-metrics1.143.01.145.0Base package
victoria-metrics-cluster1.143.01.145.0VictoriaMetrics companion package
vmutils1.143.01.145.0VictoriaMetrics companion package
victoria-traces0.8.20.9.2
duckdb1.5.21.5.3
etcd3.6.113.6.12
restic0.18.10.19.0
tigerfs0.6.00.7.0
dblab0.38.00.40.1
pgstream1.0.21.0.3
tigerbeetle0.17.40.17.6
grafana-victorialogs-ds0.26.30.28.0
grafana-victoriametrics-ds0.24.00.25.0
kafka4.2.04.3.0
caddy2.11.22.11.4
hugo0.161.10.163.0
seaweedfs4.234.32
rustfs1.0.0-b21.0.0-b8Prerelease line
v2ray5.48.05.49.0
sabiql1.12.21.12.3
agentsview0.29.00.32.1Upstream moved to kenn-io/agentsview
claude2.1.1382.1.172Downloaded through the 8118 proxy and verified
codex0.130.00.139.0Release tag rust-v0.139.0
stalwart0.16.40.16.8
maddy0.9.40.9.5
npgsqlrest3.15.13.16.3
postgrest14.1114.13
opencode1.14.481.17.3
uv0.11.130.11.20
golang1.26.31.26.4
nodejs24.15.024.16.0Stayed on the 24.x policy line
grafana13.0.113.0.2Skipped 13.1 nightly
vector0.55.00.56.0
pgschema1.9.01.11.0
crush0.66.10.76.0Direct-download artifact refresh
rclone1.74.11.74.3Direct-download artifact refresh
code1.118.11.124.0Direct-download artifact refresh
code-server4.118.04.123.0Direct-download artifact refresh
cloudflared2026.3.02026.6.0Direct-download artifact refresh

2026-05-11

NameOld VerNew VerNote
victoria-metrics1.142.01.143.0
victoria-metrics-cluster1.142.01.143.0VictoriaMetrics companion package
vmutils1.142.01.143.0VictoriaMetrics companion package
mongodb_exporter0.50.00.51.0
redis_exporter1.82.01.83.0
etcd3.6.103.6.11
pgstream1.0.11.0.2
seaweedfs4.224.23
rustfs1.0.0-b11.0.0-b2Prerelease line
tigerbeetle0.17.20.17.4
sabiql1.11.11.12.2
agentsview0.26.00.29.0
claude2.1.1232.1.138Downloaded through the 8118 proxy and verified
codex0.125.00.130.0
stalwart0.16.20.16.4
maddy0.9.30.9.4
npgsqlrest3.12.03.15.1
postgrest14.1014.11
opencode1.14.301.14.48
uv0.11.80.11.13
golang1.26.21.26.3
crush0.64.00.66.1Direct-download artifact refresh
rclone1.73.51.74.1Direct-download artifact refresh
code-server4.117.04.118.0Direct-download artifact refresh
cloudflared2026.2.02026.3.0Direct-download artifact refresh

2026-05-01

NameOld VerNew VerNote
prometheus3.11.23.11.3
alertmanager0.32.00.32.1
victoria-metrics1.140.01.142.0
victoria-metrics-cluster1.140.01.142.0VictoriaMetrics companion package
vmutils1.140.01.142.0VictoriaMetrics companion package
victoria-traces0.8.10.8.2
tigerbeetle0.17.10.17.2
loki3.6.73.6.7Obsolete and kept frozen
promtail3.6.73.6.7Obsolete and kept frozen
logcli3.6.73.6.7Obsolete and kept frozen with Loki
hugo0.160.10.161.1
seaweedfs4.214.22
rustfs1.0.0-alpha.941.0.0-b1Prerelease line
sabiql1.11.01.11.1
timescaledb-tools0.18.20.19.0Rebuilt timescaledb-tune Linux binaries
agentsview0.25.00.26.0
claude2.1.1192.1.123Downloaded through the 8118 proxy and verified
stalwart0.16.00.16.2
opencode1.14.241.14.30
uv0.11.70.11.8
vip-manager4.0.04.2.0Direct-download metadata refresh
crush0.62.10.64.0Direct-download metadata refresh
code1.115.01.118.1Direct-download metadata refresh
pig1.4.01.4.1Metadata only

2026-04-25

NameOld VerNew VerNote
grafana13.0.013.0.1Direct-download metadata refresh
vector0.54.00.55.0Direct-download metadata refresh
keepalived_exporter1.7.01.7.1
seaweedfs4.204.21
tigerbeetle0.17.00.17.1
agentsview0.22.20.25.0
claude2.1.1142.1.119Downloaded through the 8118 proxy and verified
codex0.121.00.125.0
stalwart0.15.50.16.0
opencode1.4.111.14.24
crush0.57.00.62.1Direct-download metadata refresh
rclone1.73.41.73.5Direct-download metadata refresh
code-server4.115.04.117.0Direct-download metadata refresh

2026-04-19

NameOld VerNew VerNote
victoria-logs1.49.01.50.0base package
vlagent1.49.01.50.0VictoriaLogs companion package
vlogscli1.49.01.50.0VictoriaLogs companion package
victoria-traces0.8.00.8.1
dblab0.37.10.38.0
grafana-victoriametrics-ds0.23.40.24.0
grafana-plugins12.3.013.0.0Noarch plugin bundle, manually curated
garage2.2.02.3.0
rustfs1.0.0-alpha.931.0.0-alpha.94
claude2.1.1072.1.114Refactored to versioned templates and converged on latest stable
codex0.121.0-alpha.70.121.0Switched to the stable release and rebuilt
genai-toolbox1.0.01.1.0Synced build artifacts from the genai-toolbox project
postgrest14.914.10
opencode1.4.31.4.11Switched to versioned cache and rebuilt
uv0.11.60.11.7
nodejs24.14.124.15.0Stayed on the 24.x policy line
minio2026032500000020260417000000Direct-link metadata refresh; rebuilt from the pgsty fork
mcli2026032100000020260417000000Direct-link metadata refresh; rebuilt from the pgsty fork
sabiql1.10.01.11.0
etcd3.6.83.6.10Unified package version
pig1.3.41.4.0

2026-04-14

NameOld VerNew VerNote
prometheus3.10.03.11.2
alertmanager0.31.10.32.0
node_exporter1.10.21.11.1
mongodb_exporter0.49.00.50.0
victoria-metrics1.138.01.140.0
victoria-metrics-cluster1.138.01.140.0VictoriaMetrics companion package
vmutils1.138.01.140.0VictoriaMetrics companion package
victoria-logs1.48.01.49.0
vlagent1.48.01.49.0VictoriaLogs companion package
vlogscli1.48.01.49.0VictoriaLogs companion package
grafana12.4.113.0.0Major release upgrade
duckdb1.5.01.5.2
dblab0.34.30.37.1
grafana-victoriametrics-ds0.23.10.23.4
grafana-infinity-ds3.7.43.8.0
seaweedfs4.174.20
rustfs1.0.0-alpha.891.0.0-alpha.93Switched to versioned release asset names
v2ray5.47.05.48.0
xray26.2.626.3.27
agentsview0.15.00.22.2
claude2.1.812.1.107Rebuilt; Makefile now pulls from a versioned bucket
codex0.116.00.121.0-alpha.7Prerelease chain upgrade; rebuilt
maddy0.8.20.9.3
genai-toolbox0.27.01.0.0Metadata-only refresh; upstream renamed to mcp-toolbox
npgsqlrest3.11.13.12.0
postgrest14.714.9
rainfrog0.3.170.3.18
sqlcmd1.9.01.10.0
opencode1.2.271.4.3Rebuilt
uv0.10.120.11.6
golang1.26.11.26.2
nodejs24.14.024.14.1Stayed on the 24.x policy line
pgschema1.7.41.9.0
crush0.51.20.57.0
rclone1.73.21.73.4
code1.112.01.115.0
code-server4.112.04.115.0
tigerbeetle0.16.770.17.0
tigerfs0.5.00.6.0
sabiql1.8.21.10.0
hugo0.158.00.160.1
etcd3.6.93.6.8Frozen at 3.6.8 and README corrected
loki3.6.73.6.7Deprecated and kept frozen
promtail3.6.73.6.7Deprecated and kept frozen
pg_exporter1.2.11.2.2Direct-link metadata refresh
pig1.3.21.3.4Direct-link metadata refresh

2026-03-21

NameOld VerNew VerNote
grafana12.4.012.4.1
pgbackrest_exporter0.22.00.23.0
redis_exporter1.81.01.82.0
victoria-logs1.47.01.48.0
vlagent1.47.01.48.0
vlogscli1.47.01.48.0
victoria-traces0.7.10.8.0
duckdb1.4.41.5.0
pg_timetable6.2.06.3.0
pgschema1.4.21.7.4
pgstream-1.0.1new
tigerbeetle0.16.750.16.77
grafana-victorialogs-ds0.26.20.26.3
grafana-infinity-ds3.7.33.7.4
caddy2.11.12.11.2
npgsqlrest3.10.03.11.1
postgrest14.514.7
opencode1.2.171.2.27
pev21.20.21.21.0
golang1.26.01.26.1
vector0.53.00.54.0
rclone1.73.11.73.2
code-server4.109.54.112.0
code1.109.41.112.0
seaweedfs4.154.17
uv0.10.80.10.12
codex0.110.00.116.0
v2ray5.44.15.47.0
sabiql1.6.21.8.2
sql-studio-0.1.51new
rainfrog-0.3.17new
agentsview0.10.00.15.0
crush-0.51.2new
tigerfs-0.5.0new
victoria-metrics1.137.01.138.0
victoria-metrics-cluster1.137.01.138.0
vmutils1.137.01.138.0
hugo0.157.00.158.0
rustfs1.0.0-alpha.851.0.0-alpha.89
mysqld_exporter0.18.00.19.0
pg_exporter1.2.01.2.1
pig1.3.11.3.2
minio2026021420260321000000
mcli2026021320260321000000
claude2.1.682.1.81
ivroysql5.15.3

2026-03-05

NameOld VerNew VerNote
asciinema3.1.03.2.0
grafana-infinity-ds3.7.23.7.3
victoria-metrics1.136.01.137.0
victoria-metrics-cluster1.136.01.137.0
vmutils1.136.01.137.0
hugo0.155.30.157.0
opencode1.2.151.2.17
rustfs1.0.0-alpha.831.0.0-alpha.85
seaweedfs4.134.15
tigerbeetle0.16.740.16.75
uv0.10.40.10.8
codex0.105.00.110.0
claude2.1.592.1.68
xray-26.2.6new
gost-2.12.0new
sabiql-1.6.2new
agentsview-0.10.0new

2026-02-26

NameOld VerNew VerNote
grafana12.3.312.4.0
prometheus3.9.13.10.0
mongodb_exporter0.47.20.49.0
victoria-logs1.45.01.47.0
vlagent1.45.01.47.0
vlogscli1.45.01.47.0
tigerbeetle0.16.730.16.74
loki3.6.63.6.7
promtail3.6.63.6.7
logcli3.6.63.6.7
grafana-victorialogs-ds0.25.00.26.2
grafana-victoriametrics-ds0.22.00.23.1
grafana-infinity-ds3.7.13.7.2
caddy2.10.22.11.1
npgsqlrest3.8.03.10.0
opencode1.2.101.2.15
nodejs24.13.124.14.0
pev21.20.11.20.2
claude2.1.452.1.59
codex0.104.00.105.0
pig1.2.01.3.0

2026-02-22

NameOld VerNew VerNote
victoria-metrics1.135.01.136.0
victoria-metrics-cluster1.135.01.136.0
vmutils1.135.01.136.0
loki3.6.53.6.6
promtail3.6.53.6.6
logcli3.6.53.6.6
opencode1.2.61.2.10
pig1.1.21.2.0
stalwart-0.15.5new
maddy-0.8.2new

2026-02-18

NameOld VerNew VerNote
grafana12.3.212.3.3
grafana-victorialogs-ds0.24.10.25.0
grafana-victoriametrics-ds0.21.00.22.0
grafana-infinity-ds3.7.03.7.1
redis_exporter1.80.21.81.0
etcd3.6.73.6.8
dblab0.34.20.34.3
tigerbeetle0.16.720.16.73
seaweedfs4.094.13
rustfs1.0.0-alpha.821.0.0-alpha.83
uv0.10.00.10.4
kafka4.1.14.2.0
npgsqlrest3.7.03.8.0
postgrest14.414.5
opencode1.1.591.2.6
genai-toolbox0.25.00.27.0
claude2.1.372.1.45
rclone1.73.01.73.1
code-server4.108.24.109.2
code1.109.21.109.4

2026-02-12

NameOld VerNew VerNote
alertmanager0.31.00.31.1
tigerbeetle0.16.700.16.72
grafana-infinity-ds3.7.03.7.1
nodejs24.13.024.13.1
opencode1.1.531.1.59
golang1.25.71.26.0
minio2025120312000020260214120000pgsty fork
pig1.1.01.1.1

2026-02-08

NameOld VerNew VerNote
alertmanager0.30.10.31.0
victoria-metrics1.134.01.135.0
victoria-metrics-cluster1.134.01.135.0
vmutils1.134.01.135.0
victoria-logs1.43.11.45.0
vlagent1.43.11.45.0
vlogscli1.43.11.45.0
grafana-victorialogs-ds0.23.50.24.1
grafana-victoriametrics-ds0.20.10.21.0
tigerbeetle0.16.680.16.70
loki3.1.13.6.5
promtail3.0.03.6.5
logcli3.1.13.6.5
redis_exporter1.80.11.80.2
timescaledb-tools0.18.10.18.2
seaweedfs4.064.09
rustfs1.0.0-alpha.801.0.0-alpha.82
uv0.9.260.10.0
garage2.1.02.2.0
headscale0.27.10.28.0
hugo0.154.50.155.2
pev21.20.01.20.1
postgrest14.314.4
npgsqlrest3.4.73.7.0
opencode1.1.341.1.53
golang1.25.61.25.7
nodejs24.12.024.13.0
claude2.1.192.1.37
vector0.52.00.53.0
code1.108.01.109.0
code-server4.108.04.108.2
rclone1.72.11.73.0
pg_exporter1.1.21.2.0
grafana12.3.112.3.2
pig1.0.01.1.0
cloudflared2026.1.12026.2.0

2026-01-25

NameOld VerNew VerNote
alertmanager0.30.00.30.1
victoria-metrics1.133.01.134.0
victoria-traces0.5.10.7.1
grafana-victorialogs-ds0.23.30.23.5
grafana-victoriametrics-ds0.20.00.20.1
npgsqlrest3.4.33.4.7
claude2.1.92.1.19
opencode1.1.231.1.34
caddy-2.10.2new
hugo-0.154.5new
cloudflared-2026.1.1new
headscale-0.27.1new
pig0.9.01.0.0
duckdb1.4.31.4.4

2026-01-16

NameOld VerNew VerNote
prometheus3.8.13.9.1
victoria-metrics1.132.01.133.0
tigerbeetle0.16.650.16.68
kafka4.0.04.1.1
grafana-victoriametrics-ds0.19.70.20.0
grafana-victorialogs-ds0.23.20.23.3
grafana-infinity-ds3.6.03.7.0
uv0.9.180.9.26
seaweedfs4.014.06
rustfsalpha.71alpha.80
v2ray5.28.05.44.1
sqlcmd1.8.01.9.0
opencode1.0.2231.1.23
claude2.1.12.1.9
golang1.25.51.25.6
asciinema3.0.13.1.0
code1.107.01.108.0
code-server4.107.04.108.0
npgsqlrest3.3.03.4.3
genai-toolbox0.24.00.25.0
pg_exporter1.1.11.1.2
pig0.9.00.9.1

2026-01-08

NameOld VerNew VerNote
pg_exporter1.1.01.1.1new pg_timeline collector
npgsqlrest3.3.3new
postgrest14.3new
opencode1.0.223new
code-server4.107.0new
claude2.0.762.1.1update
genai-toolbox0.23.00.24.0removed broken oracle driver
golang1.25.5new
nodejs24.12.0new

2025-12-25

NameOld VerNew VerNote
pig0.8.00.9.0routine update
etcd3.6.63.6.7routine update
uv-0.9.18new python package manager
ccm-2.0.76new claude code
asciinema-3.0.1new terminal recorder
ivorysql5.05.1
grafana12.3.012.3.1
vector0.51.10.52.0
prometheus3.8.03.8.1
alertmanager0.29.00.30.0
victoria-logs1.41.01.43.1
pgbackrest_exporter0.21.00.22.0
grafana-victorialogs-ds0.22.40.23.2

2025-12-16

NameOld VerNew VerNote
victoria-metrics1.131.01.132.0
victoria-logs1.40.01.41.0
blackbox_exporter0.27.00.28.0
duckdb1.4.21.4.3
rclone1.72.01.72.1
pev21.17.01.19.0
pg_exporter1.0.31.1.0
pig0.7.40.8.0
genai-toolbox0.22.00.23.0
minio2025090716130920251203120000by pgsty

2025-12-04

NameOld VerNew VerNote
rustfs-1.0.0-a71new
seaweedfs-4.1.0new
garage-2.1.0new
rclone1.71.21.72.0
vector0.51.00.51.1
prometheus3.7.33.8.0
victoria-metrics0.130.00.131.0
victoria-logs0.38.00.40.0
victoria-traces-0.5.1new
grafana-victorialogs-ds0.22.10.22.4
redis_exporter1.80.01.80.1
mongodb_exporter0.47.10.47.2
genai-toolbox0.21.00.22.0

2025-11-23

NameOld VerNew VerNote
pgschema-1.4.2new
pgflo-0.0.15new
vector0.51.00.51.1bug fix
sealos5.0.15.1.1
etcd3.6.53.6.6
duckdb1.4.11.4.2
pg_exporter1.0.21.0.3
pig0.7.10.7.2
grafana12.1.012.3.0
pg_timetable6.1.06.2.0
genai-toolbox0.16.00.21.0
timescaledb-tools0.18.00.18.1moved from PGSQL to INFRA
timescaledb-event-streamer0.12.00.20.0
tigerbeetle0.16.600.16.65
victoria-metrics1.129.11.130.0
victoria-logs1.37.21.38.0
grafana-victorialogs-ds0.21.40.22.1
grafana-victoriametrics-ds0.19.60.19.7
grafana-plugins12.0.012.3.0

2025-11-11

NameOld VerNew VerNote
grafana12.1.012.2.1download url change
prometheus3.6.03.7.3
pushgateway1.11.11.11.2
alertmanager0.28.10.29.0
nginx_exporter1.5.01.5.1
node_exporter1.9.11.10.2
pgbackrest_exporter0.20.00.21.0
redis_exporter1.77.01.80.0
duckdb1.4.01.4.1
dblab0.33.00.34.2
pg_timetable5.13.06.1.0
vector0.50.00.51.0
rclone1.71.11.71.2
victoria-metrics1.126.01.129.1
victoria-logs1.35.01.37.2
grafana-victorialogs-ds0.21.00.21.4
grafana-victoriametrics-ds0.19.40.19.6
grafana-infinity-ds3.5.03.6.0
genai-toolbox0.16.00.18.0
pev21.16.01.17.0
pig0.6.20.7.1

2025-10-18

NameOld VerNew VerNote
prometheus3.5.03.6.0
nginx_exporter1.4.21.5.0
mysqld_exporter0.17.20.18.0
redis_exporter1.75.01.77.0
mongodb_exporter0.47.00.47.1
victoria-metrics1.121.01.126.0
victoria-logs1.25.11.35.0
duckdb1.3.21.4.0
etcd3.6.43.6.5
restic0.18.00.18.1
tigerbeetle0.16.540.16.60
grafana-victorialogs-ds0.19.30.21.0
grafana-victoriametrics-ds0.18.30.19.4
grafana-infinity-ds3.3.03.5.0
genai-toolbox0.9.00.16.0
grafana12.1.012.2.0
vector0.49.00.50.0
rclone1.70.31.71.1
minio2025072315540220250907161309
mcli2025072105280820250813083541

2025-08-15

NameOld VerNew VerNote
grafana12.0.012.1.0
pg_exporter1.0.11.0.2
pig0.6.00.6.1
vector0.48.00.49.0
redis_exporter1.74.01.75.0
mongodb_exporter0.46.00.47.0
victoria-metrics1.121.01.123.0
victoria-logs1.25.01.28.0
grafana-victoriametrics-ds0.17.00.18.3
grafana-victorialogs-ds0.18.30.19.3
grafana-infinity-ds3.3.03.4.1
etcd3.6.13.6.4
ferretdb2.3.12.5.0
tigerbeetle0.16.500.16.54
genai-toolbox0.9.00.12.0

2025-07-24

NameOld VerNew VerNote
ferretdb-2.4.0pair with documentdb 1.105
etcd-3.6.3
minio-20250723155402
mcli-20250721052808
ivorysql-4.5-0ffca11-20250709fix libxcrypt dep issue

2025-07-16

NameOld VerNew VerNote
genai-toolbox0.8.00.9.0MCP toolbox for various DBMS
victoria-metrics1.120.01.121.0split into various packages
victoria-logs1.24.01.25.0split into various packages
prometheus3.4.23.5.0
duckdb1.3.11.3.2
etcd3.6.13.6.2
tigerbeetle0.16.480.16.50
grafana-victoriametrics-ds0.16.00.17.0
rclone1.69.31.70.3
pig0.5.00.6.0
pev21.15.01.16.0
pg_exporter1.0.01.0.1

2025-07-04

NameOld VerNew VerNote
prometheus3.4.13.4.2
grafana12.0.112.0.2
vector0.47.00.48.0
rclone1.69.01.70.2
vip-manager3.0.04.0.0
blackbox_exporter0.26.00.27.0
redis_exporter1.72.11.74.0
duckdb1.3.01.3.1
etcd3.6.03.6.1
ferretdb2.2.02.3.1
dblab0.32.00.33.0
tigerbeetle0.16.410.16.48
grafana-victorialogs-ds0.16.30.18.1
grafana-victoriametrics-ds0.15.10.16.0
grafana-infinity-ds3.2.13.3.0
victoria-logs1.22.21.24.0
victoria-metrics1.117.11.120.0

2025-06-01

NameOld VerNew VerNote
grafana-12.0.1
prometheus-3.4.1
keepalived_exporter-1.7.0
redis_exporter-1.73.0
victoria-metrics-1.118.0
victoria-logs-1.23.1
tigerbeetle-0.16.42
grafana-victorialogs-ds-0.17.0
grafana-infinity-ds-3.2.2

2025-05-22

NameOld VerNew VerNote
dblab-0.32.0
prometheus-3.4.0
duckdb-1.3.0
etcd-3.6.0
pg_exporter-1.0.0
ferretdb-2.2.0
rclone-1.69.3
minio-20250422221226last version with admin GUI
mcli-20250416181326
nginx_exporter-1.4.2
keepalived_exporter-1.6.2
pgbackrest_exporter-0.20.0
redis_exporter-1.27.1
victoria-metrics-1.117.1
victoria-logs-1.22.2
pg_timetable-5.13.0
tigerbeetle-0.16.41
pev2-1.15.0
grafana-12.0.0
grafana-victorialogs-ds-0.16.3
grafana-victoriametrics-ds-0.15.1
grafana-infinity-ds-3.2.1
grafana-plugins-12.0.0

2025-04-23

NameOld VerNew VerNote
mtail-3.0.8new
pig-0.4.0
pg_exporter-0.9.0
prometheus-3.3.0
pushgateway-1.11.1
keepalived_exporter-1.6.0
redis_exporter-1.70.0
victoria-metrics-1.115.0
victoria-logs-1.20.0
duckdb-1.2.2
pg_timetable-5.12.0
vector-0.46.1
minio-20250422221226
mcli-20250416181326

2025-04-05

NameOld VerNew VerNote
pig-0.3.4
etcd-3.5.21
restic-0.18.0
ferretdb-2.1.0
tigerbeetle-0.16.34
pg_exporter-0.8.1
node_exporter-1.9.1
grafana-11.6.0
zfs_exporter-3.8.1
mongodb_exporter-0.44.0
victoria-metrics-1.114.0
minio-20250403145628
mcli-20250403170756

2025-03-23

NameOld VerNew VerNote
etcd-3.5.20
pgbackrest_exporter-0.19.0rebuilt
victoria-logs-1.17.0
vlogscli-1.17.0

2025-03-17

NameOld VerNew VerNote
kafka-4.0.0
prometheus-3.2.1
alertmanager-0.28.1
blackbox_exporter-0.26.0
node_exporter-1.9.0
mysqld_exporter-0.17.2
kafka_exporter-1.9.0
redis_exporter-1.69.0
duckdb-1.2.1
etcd-3.5.19
ferretdb-2.0.0
tigerbeetle-0.16.31
vector-0.45.0
victoria-metrics-1.114.0
victoria-logs-1.16.0
rclone-1.69.1
pev2-1.14.0
grafana-victorialogs-ds-0.16.0
grafana-victoriametrics-ds-0.14.0
grafana-infinity-ds-3.0.0
timescaledb-event-streamer-0.12.0new
restic-0.17.3new
juicefs-1.2.3new

2025-02-12

NameOld VerNew VerNote
pushgateway1.10.01.11.0
alertmanager0.27.00.28.0
nginx_exporter1.4.01.4.1
pgbackrest_exporter0.18.00.19.0
redis_exporter1.66.01.67.0
mongodb_exporter0.43.00.43.1
victoria-metrics1.107.01.111.0
victoria-logs1.3.21.9.1
duckdb1.1.31.2.0
etcd3.5.173.5.18
pg_timetable5.10.05.11.0
ferretdb1.24.02.0.0
tigerbeetle0.16.130.16.27
grafana11.4.011.5.1
vector0.43.10.44.0
minio2024121813154420250207232109
mcli2024112117215420250208191421
rclone1.68.21.69.0

2024-11-19

NameOld VerNew VerNote
prometheus2.54.03.0.0
victoria-metrics1.102.11.106.1
victoria-logs0.28.01.0.0
mysqld_exporter0.15.10.16.0
redis_exporter1.62.01.66.0
mongodb_exporter0.41.20.42.0
keepalived_exporter1.3.31.4.0
duckdb1.1.21.1.3
etcd3.5.163.5.17
tigerbeetle16.80.16.13
grafana-11.3.0
vector-0.42.0

8.4 - PGSQL Repo

The repo for PostgreSQL Extensions & Kernel Forks

The pigsty-pgsql repo contains packages that are ad hoc to specific PostgreSQL Major Versions (often ad hoc to a specific Linux distro major version, too). Including extensions and some kernel forks.

You can check the Release - RPM Changelog / Release - DEB Changelog for the latest updates.


Compatibility

OS / ArchOSx86_64aarch64
EL8el818, 17, 16, 15, 1418, 17, 16, 15, 14
EL9el918, 17, 16, 15, 1418, 17, 16, 15, 14
EL10el1018, 17, 16, 15, 1418, 17, 16, 15, 14
Debian 12d1218, 17, 16, 15, 1418, 17, 16, 15, 14
Debian 13d1318, 17, 16, 15, 1418, 17, 16, 15, 14
Ubuntu 22.04u2218, 17, 16, 15, 1418, 17, 16, 15, 14
Ubuntu 24.04u2418, 17, 16, 15, 1418, 17, 16, 15, 14
Ubuntu 26.04u2618, 17, 16, 15, 1418, 17, 16, 15, 14

Quick Start

PIG

You can install pig - the CLI tool, and add pgdg / pigsty repo with it (recommended):

pig repo add pigsty                         # add pigsty-pgsql repo
pig repo add pigsty -u                      # add pigsty-pgsql repo, and update cache
pig repo add pigsty -u --region=default     # add pigsty-pgsql repo and enforce default region (pigsty.io)
pig repo add pigsty -u --region=china       # add pigsty-pgsql repo with china region   (pigsty.cc)
pig repo add pgsql -u                       # pgsql = pgdg + pigsty-pgsql (add pigsty + official PGDG)
pig repo add -u                             # all = node + pgsql (pgdg + pigsty) + infra

Hint: If you are in mainland China, consider using the China CDN mirror (replace pigsty.io with pigsty.cc)

APT

You can also enable this repo with apt directly on Debian / Ubuntu:

Default
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian / Ubuntu distribution codename (bookworm, trixie, jammy, noble, resolute), and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-io.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

# Refresh APT repository cache
sudo apt update
Mirror
# Use when in mainland China or Cloudflare is unavailable
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.cc/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg

# Get Debian distribution codename, and write the corresponding upstream repository address to the APT List file
distro_codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/pigsty-io.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.cc/apt/pgsql/${distro_codename} ${distro_codename} main
EOF

# Refresh APT repository cache
sudo apt update

DNF

You can also enable this repo with dnf/yum directly on EL-compatible systems:

Default
# Add Pigsty's GPG public key to your system keychain to verify package signatures
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null

# Add Pigsty Repo definition files to /etc/yum.repos.d/ directory, including two repositories
sudo tee /etc/yum.repos.d/pigsty-pgsql.repo > /dev/null <<-'EOF'
[pigsty-pgsql]
name=Pigsty PGSQL For el$releasever.$basearch
baseurl=https://repo.pigsty.io/yum/pgsql/el$releasever.$basearch
skip_if_unavailable = 1
enabled = 1
priority = 1
gpgcheck = 1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty