Skip to content

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

Return to the regular view of this page.

Administration

Manage your deployment
Ansible
    Run admin commands with ansible
Playbook
    Built-in playbooks in Pigsty
Dashboard
    Introduction to grafana dashboards
Monitor
    Introduction to prometheus & alertmanager

Nginx Portal
    Nginx Portal for WebUI services
Local Repo
    Manage local APT / YUM repository
Domain Name
    Use local / public domain names
CA & Cert
    Use self-signed or real HTTPS certificates

PGSQL
    PostgreSQL Cluster with HA, PITR, IaC, ACL, Monitoring, Pooling
INFRA
    Nginx, Repo, DNS, NTP, Prometheus and Grafana stack for Observability
NODE
    Enroll nodes into the desired state and monitor it, and VIP, HAProxy
ETCD
    Reliable distributed consensus storage (DCS), empowering PGSQL HA
MINIO
    S3 compatible object storage, optional backup storage
REDIS
    High-performance in-memory cache, optional data structure server

1 - Ansible

Get started with basic ansible concepts

Pigsty implements admin controllers with Ansible, which is an open source automation tool for managing large-scale infrastructure in an Infra-as-Code (IaC) manner. Widely used in the industry by operators.


Install

Pigsty will try its best to install ansible and its dependencies during bootstrap. But you can always install it manually, it is available on most OS’s official repos and can be installed with one command.

Install Ansible

Playbooks also require a weak dependency: the jmespath python package.

cd ~/pigsty; ./bootstrap
sudo apt install -y ansible python3-jmespath
sudo dnf install -y ansible python-jmespath
sudo dnf install -y ansible python3.12-jmespath
sudo yum install -y ansible python-jmespath
brew install ansible
pip3 install jmespath

Beware that el10 epel does not offer the ansible package, which is fixed by Pigsty PGDG el10 repo

macOS

Ansible is available on macOS too. You can install Ansible on your Mac with Homebrew. And use it as the admin node to manage remote cloud server. It’s convenient if you are deploying a single-node pigsty on cloud VPS. But not recommended for production use.


Basics

Knowledge about Ansible is good but NOT REQUIRED. You only need to know how to run Ansible Playbooks. Playbooks are executable YAML files that contain a series of tasks to be executed.

Running the ./node.yml playbook essentially translates to ansible-playbook node.yml. The hashbang at the top of the file makes it directly executable. And you can use Args to control the playbook execution:

~/pigsty
./node.yml                         # run infra playbook on all nodes
./pgsql.yml -l pg-test             # run pgsql playbook on pg-test cluster
./infra.yml -t repo                # run subtask repo of infra.yml
./pgsql-rm.yml -e pg_rm_pkg=false  # remove pgsql, but keep packages

The following 4 parameters need your attention to use ansible effectively:

Purpose Parameter Description
Where -l|--limit <pattern> Limit execution target on specific group/host/pattern
What -t|--tags <tags> Only run tasks with specific tags
How -e|--extra-vars <vars> Extra command line arguments
Config -i|--inventory <path> Using a specific inventory file

Limit Host

The execution target of a playbook can be limited with -l|--limit <selector>. It is handy when trying to run playbooks on a specific host/node or group/clusters. Here are some examples of host limits:

./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 host/group matching glob pattern `pg-*`
./pgsql.yml -l '10.10.10.11,&pg-test'    # run on 10.10.10.11 of group pg-test
./pgsql-rm.yml -l 'pg-test,!10.10.10.11' # run on pg-test, except 10.10.10.11
./pgsql.yml -l pg-test                   # Execute the pgsql playbook against the hosts in the pg-test cluster

Check all details in the ansible docs: Patterns: targeting hosts and groups

Running playbook without host limit can be Dangerous!

Missing this value could be dangerous, since most playbooks will execute on all hosts. DO USE WITH CAUTION.


Limit Task

The execution tasks can be controlled with -t|--tags <tags>. If specified, tasks with given tags will be executed instead of the ENTIRE playbook. Here are some task limit examples:

./infra.yml -t repo          # create repo
./node.yml  -t node_pkg      # install node packages
./pgsql.yml -t pg_install    # install pg packages & extensions
./etcd.yml  -t etcd_purge    # nuke the etcd cluster
./minio.yml -t minio_alias   # write minio cli config

To run multiple tasks, specify multiple tags and separate with comma: -t tag1,tag2:

./node.yml  -t node_repo,node_pkg   # add repo, then install packages
./pgsql.yml -t pg_hba,pg_reload     # config, then reload pg hba rules

Extra Vars

You can override config param at runtime with cli args, it has the highest precedence.

Extra command-line args can be passed via -e|--extra-vars KEY=VALUE, it can be used multiple times:

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

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

# remove postgres, but keeps packages and data
./pgsql-rm.yml -e pg_rm_pkg=false -e pg_rm_data=false

for complex parameters, JSON string can be used:

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

Designate Inventory

The default config file is pigsty.yml in the pigsty home directories.

You can use the -i <path> parameter to specify a different Inventory file path.

./pgsql.yml -i conf/rich.yml            # initialize a single node with all extensions downloaded according to rich config
./pgsql.yml -i conf/ha/full.yml            # initialize a 4-node cluster according to full config
./pgsql.yml -i conf/app/supa.yml        # initialize a 1-node Supabase deployment according to supa.yml config
Change Default Inventory File

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

2 - Playbook

Run playbooks with ansible

Pigsty implements admin controllers with idempotent Ansible playbooks. Playbooks require the ansible-playbook executable bin in your PATH. You’ll have to install ansible to run playbooks.

Here are built-in playbooks in Pigsty, you can also add your own.

Module Playbook Function
INFRA install.yml Install Pigsty on current node in one-pass
INFRA infra.yml Init pigsty infrastructure on infra nodes
INFRA infra-rm.yml Remove infrastructure components from infra nodes
INFRA cache.yml Make offline install packages from target node
INFRA cert.yml Issue cert with pigsty self-signed CA (e.g. for pg clients)
NODE node.yml Init node for pigsty, tune node into desired status
NODE node-rm.yml Remove node from pigsty
PGSQL pgsql.yml Init HA PostgreSQL clusters, or adding new replicas
PGSQL pgsql-rm.yml Remove PostgreSQL cluster, or remove replicas
PGSQL pgsql-db.yml Add new business database to existing PostgreSQL cluster
PGSQL pgsql-user.yml Add new business user to existing PostgreSQL cluster
PGSQL pgsql-pitr.yml Run point-in-time-recovery on existing PostgreSQL cluster
PGSQL pgsql-monitor.yml Monitor remote postgres instance with local exporters
PGSQL pgsql-migration.yml Generate Migration manual & scripts for existing PostgreSQL
PGSQL slim.yml Install Pigsty with minimal components
REDIS redis.yml Init redis cluster/node/instance
REDIS redis-rm.yml Remove redis cluster/node/instance
ETCD etcd.yml Init etcd cluster, or append new member
ETCD etcd-rm.yml Remove etcd cluster, or remove existing member
MINIO minio.yml Init minio cluster
MINIO minio-rm.yml Remove minio cluster
DOCKER docker.yml Install docker on nodes
DOCKER app.yml Install application with docker compose
FERRET mongo.yml Install Mongo/FerretDB on nodes

Deployment

The special playbook install.yml will deploy everything with ad hoc playbooks:

Playbook Command Group infra [nodes] etcd minio [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
Circular Dependency Between NODE and INFRA

There is a weak circular dependency between NODE and INFRA: to register a NODE to INFRA, the INFRA should already exist, while the INFRA module relies on NODE to work.

One way to work around it is to init infra nodes first, then add other nodes, if you wish to deploy them all in one-pass, install.yml is the way to go.


Safety Considerations

Idempotent but Potentially Destructive

Most playbooks are idempotent, meaning that some deployment playbooks may erase existing databases and create new ones without the protection option turned on. Especially care with pgsql, minio, and infra playbooks.

Please read the documentation carefully and operate with caution. The author is not responsible for any loss of databases due to misuse.

Safety Best Practices
  1. Read playbook documentation carefully before execution
  2. Ctrl-C to stop immediately if you see something wrong
  3. Start with non-production environments for testing
  4. Limit execution hosts (-l) to avoid unintended hosts if applicable
  5. Use specific tags (-t) to run subset of tasks if possible
Dry Run Mode
# Preview what would be changed without actually executing
./pgsql.yml -l pg-test --check --diff

# Combine with tags to check specific tasks
./pgsql.yml -l pg-test -t pg_config --check --diff

3 - Nginx Portal

Configure infra portal and nginx settings

Pigsty installs Nginx on the INFRA Node as a web service proxy, using ports 80/443 by default. The global parameter infra_portal configures Nginx proxy rules and upstream services.


The Nginx server configuration is specified through the infra_portal parameter. Users declare all domains to be proxied through Nginx, along with corresponding upstream server endpoints or local directory paths.

Basic Example

infra_portal:  # domain names and upstream servers
  home         : { domain: h.pigsty }
  grafana      : { domain: g.pigsty, endpoint: "${admin_ip}:3000", websocket: true }
  prometheus   : { domain: p.pigsty, endpoint: "${admin_ip}:9058" }
  alertmanager : { domain: a.pigsty, endpoint: "${admin_ip}:9059" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  loki         : { endpoint: "${admin_ip}:3100" }

Complex Example

infra_portal:
  home         : { domain: home.pigsty.cc }
  grafana      : { domain: g.pgsty.com, endpoint: "${admin_ip}:3000", websocket: true }
  cc           : { domain: pigsty.cc, path: "/www/pigsty.cc" }
  en           : { domain: pigsty.io, path: "/www/pigsty.io" }
  prometheus   : { domain: p.pigsty.cc, endpoint: "${admin_ip}:9058" }
  alertmanager : { domain: a.pigsty.cc, endpoint: "${admin_ip}:9059" }
  minio        : { domain: s3.pigsty.cc, endpoint: "${admin_ip}:9001", websocket: true }
  jupyter      : { domain: lab.pigsty.cc, endpoint: "${admin_ip}:8888", websocket: true }
  repo         : { domain: repo.pigsty.cc, path: "/www/repo", index: true }
  wiki         : { domain: wiki.pigsty.cc, endpoint: "${admin_ip}:9002" }
  noco         : { domain: noco.pigsty.cc, endpoint: "${admin_ip}:8080" }
  supa         : { domain: supa.pigsty.cc, endpoint: "${admin_ip}:3001" }
  dify         : { domain: dify.pigsty.cc, endpoint: "${admin_ip}:8001" }
  pg1          : { domain: pg1.pigsty.cc, endpoint: "10.10.10.11:5432", scheme: tcp }
  pg2          : { domain: pg2.pigsty.cc, endpoint: "10.10.10.12:5432", scheme: tcp }
  pg3          : { domain: pg3.pigsty.cc, endpoint: "10.10.10.13:5432", scheme: tcp }

Playbook Configuration

Nginx can be reconfigured using Ansible playbooks:

./infra.yml -t nginx           # Reconfigure Nginx completely
./infra.yml -t nginx_config    # Regenerate Nginx configuration files
./infra.yml -t nginx_launch    # Restart Nginx service
./infra.yml -t nginx_cert      # Regenerate SSL certificates

Server

Each server record in infra_portal supports the following configuration options:

Core Parameters

  • domain - Optional proxy domain name
  • endpoint - Upstream service address (IP:PORT or socket path)
  • path - Local web server root directory for static content
  • scheme - Protocol specification (http/https/tcp/udp)

SSL/TLS Parameters

  • certbot - Enable Let’s Encrypt certificate management
  • cert - Custom SSL certificate file path
  • key - Custom SSL private key file path

Advanced Parameters

  • conf - Custom Nginx configuration template
  • domains - Additional domain names for the service
  • index - Enable directory listing for static content
  • log - Custom log file configuration
  • websocket - Enable WebSocket support for real-time applications

Parameter Usage Examples

# Static file serving with directory listing
repo: { domain: repo.pigsty.cc, path: "/www/repo", index: true }

# WebSocket-enabled service
grafana: { domain: g.pigsty.cc, endpoint: "${admin_ip}:3000", websocket: true }

# Custom SSL certificate
secure_app: {
  domain: secure.pigsty.cc,
  endpoint: "${admin_ip}:8443",
  cert: "/etc/ssl/certs/custom.crt",
  key: "/etc/ssl/private/custom.key"
}

# Let's Encrypt managed certificate
public_api: { domain: api.pigsty.cc, endpoint: "${admin_ip}:8080", certbot: true }

# TCP stream proxy
pg_primary: { domain: pg.pigsty.cc, endpoint: "10.10.10.11:5432", scheme: tcp }

Using Domain Names

DNS Resolution Methods

  1. Public internet domain via DNS provider
  2. Internal network DNS server
  3. Local /etc/hosts file modification

For local development and testing, add entries to your /etc/hosts file:

# Add to /etc/hosts
<your_public_ip_address> h.pigsty g.pigsty p.pigsty a.pigsty

Replace <your_public_ip_address> with your actual admin node IP address.

HTTPS Configuration

Configure HTTPS access via the nginx_sslmode parameter with the following options:

  • disabled - HTTP only, no SSL
  • self-signed - Use self-signed certificates (default)
  • provided - Use provided certificates
  • letsencrypt - Use Let’s Encrypt certificates

Certificate Management

./infra.yml -t nginx_cert      # Regenerate SSL certificates

HTTPS Access Methods

For self-signed certificates, you can:

  • Trust the self-signed CA in your browser
  • Use browser security bypass options (type thisisunsafe in Chrome)
  • Configure proper CA-signed certificates for production

Service Access Examples

With the default configuration, services are accessible via:

  • Home Page: http://h.pigsty or https://h.pigsty
  • Grafana Dashboard: http://g.pigsty or https://g.pigsty
  • Prometheus Metrics: http://p.pigsty or https://p.pigsty
  • Alertmanager: http://a.pigsty or https://a.pigsty

Best Practices

  1. Use domain names for service access rather than direct IP:PORT
  2. Configure DNS resolution or update local hosts file appropriately
  3. Enable WebSocket support for services that require it (like Grafana, Jupyter)
  4. Use HTTPS in production environments with proper certificates
  5. Organize services logically with meaningful subdomain naming
  6. Monitor certificate expiration for Let’s Encrypt certificates
  7. Centralize web service proxy through Nginx for better management
  8. Use static file serving for documentation and repository browsing

4 - Local Repo

Configure local APT / YUM software repo

Quick Start

If you want to add some packages to the local repo, add them to:

Then run the make repo shortcut to update the local repo and node repo cache:

make repo
./infra.yml -t repo_build
./node.yml -t node_repo

Using Alias

You can use alias to specify a bundle of packages, check roles/node_id/vars/<os>.<arch>.yml for available aliases:

EL

node-bootstrap: "ansible python3 python3-pip python3-virtualenv python3-requests python3-jmespath python3-cryptography dnf-utils modulemd-tools createrepo_c sshpass"
infra-package:  "nginx dnsmasq etcd haproxy vip-manager node_exporter keepalived_exporter pg_exporter pgbackrest_exporter redis_exporter redis minio mcli pig"
infra-addons:   "grafana grafana-plugins loki logcli promtail prometheus alertmanager pushgateway blackbox_exporter nginx_exporter pev2 certbot python3-certbot-nginx"
extra-modules:  "docker-ce docker-compose-plugin ferretdb2 duckdb restic juicefs vray grafana-infinity-ds"
node-package1:  "lz4 unzip bzip2 zlib yum pv jq git ncdu make patch bash lsof wget uuid tuned nvme-cli numactl grubby sysstat iotop htop rsync tcpdump perf flamegraph chkconfig"
node-package2:  "netcat socat ftp lrzsz net-tools ipvsadm bind-utils telnet audit ca-certificates readline vim-minimal keepalived chrony openssl openssh-server openssh-clients"
pgsql-utility:  "patroni patroni-etcd pgbouncer pgbackrest pgbadger pg_activity pg_timetable pgFormatter pg_filedump pgxnclient timescaledb-tools timescaledb-event-streamer pgcopydb pgloader"

postgresql:     "postgresql$v*"
pgsql:          "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit"
pgsql-mini:     "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib"
pgsql-core:     "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit"
pgsql-full:     "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit postgresql$v-test postgresql$v-devel"
pgsql-main:     "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-llvmjit pg_repack_$v* wal2json_$v* pgvector_$v*"
pgsql-client:   "postgresql$v"
pgsql-server:   "postgresql$v-server postgresql$v-libs postgresql$v-contrib"
pgsql-devel:    "postgresql$v-devel"
pgsql-basic:    "pg_repack_$v* wal2json_$v* pgvector_$v*"
# ......

Debian

node-bootstrap: "ansible python3 python3-pip python3-venv python3-jmespath dpkg-dev sshpass tnftp linux-perf"
infra-package:  "nginx dnsmasq etcd haproxy vip-manager node-exporter keepalived-exporter pg-exporter pgbackrest-exporter redis-exporter redis minio mcli pig"
infra-addons:   "grafana grafana-plugins loki logcli promtail prometheus alertmanager pushgateway blackbox-exporter nginx-exporter pev2 certbot python3-certbot-nginx"
extra-modules:  "docker-ce docker-compose-plugin ferretdb2 duckdb restic juicefs vray grafana-infinity-ds"
node-package1:  "lz4 unzip bzip2 zlib1g pv jq git ncdu make patch bash lsof wget uuid tuned nvme-cli numactl sysstat iotop htop rsync tcpdump acl chrony"
node-package2:  "netcat-openbsd socat lrzsz net-tools ipvsadm dnsutils telnet ca-certificates libreadline-dev vim-tiny keepalived openssl openssh-server openssh-client"
pgsql-utility:  "patroni pgbouncer pgbackrest pgbadger pg-activity pg-timetable pgformatter postgresql-filedump pgxnclient timescaledb-tools timescaledb-event-streamer pgcopydb pgloader"

postgresql:     "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v postgresql-server-dev-$v"
pgsql:          "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v"
pgsql-mini:     "postgresql-$v postgresql-client-$v"
pgsql-core:     "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v"
pgsql-full:     "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v postgresql-server-dev-$v"
pgsql-main:     "postgresql-$v postgresql-client-$v postgresql-plpython3-$v postgresql-plperl-$v postgresql-pltcl-$v postgresql-$v-repack postgresql-$v-wal2json postgresql-$v-pgvector"
pgsql-client:   "postgresql-client-$v"
pgsql-server:   "postgresql-$v"
pgsql-devel:    "postgresql-server-dev-$v"
pgsql-basic:    "postgresql-$v-repack postgresql-$v-wal2json postgresql-$v-pgvector"
# ......
Distro x86_64 aarch64
Debian 11 d11.x86_64.yml -
Debian 12 d12.x86_64.yml d12.aarch64.yml
Debian 13 d13.x86_64.yml d13.aarch64.yml
Ubuntu 22.04 u22.x86_64.yml u22.aarch64.yml
Ubuntu 24.04 u24.x86_64.yml u24.aarch64.yml

Reference

Use these playbook tasks to manage local package repositories (YUM/APT) on Infra nodes:

./infra.yml -t repo              # Create local repo from internet or offline packages

./infra.yml -t repo_dir          # Create local repo directory
./infra.yml -t repo_check        # Check if local repo exists
./infra.yml -t repo_prepare      # Use existing local repo if available
./infra.yml -t repo_build        # Build local repo from upstream if not exists
./infra.yml     -t repo_upstream     # Add upstream repo/list files
./infra.yml     -t repo_remove       # Remove existing repo files if repo_remove=true
./infra.yml     -t repo_add          # Add upstream repo files to /etc/yum.repos.d (or apt)
./infra.yml     -t repo_url_pkg      # Download packages defined in repo_url_packages
./infra.yml     -t repo_cache        # Create metadata cache with yum makecache / apt update
./infra.yml     -t repo_boot_pkg     # Install bootstrap packages (createrepo_c, yum-utils, etc)
./infra.yml     -t repo_pkg          # Download packages & deps from upstream
./infra.yml     -t repo_create       # Create local repo with createrepo_c / dpkg-dev
./infra.yml     -t repo_use          # Add new repo to /etc/yum.repos.d | apt sources
./infra.yml -t repo_nginx        # Start nginx as file server if not running

Commonly used commands:

./infra.yml     -t repo_upstream     # Add upstream repos defined in repo_upstream
./infra.yml     -t repo_pkg          # Download packages and their dependencies
./infra.yml     -t repo_create       # Create/update local yum/apt repo

5 - DNS Domain

Setup domain names for Web Services

After installing Pigsty, users can access most Infra components’ web interfaces via IP + Port.

Let’s say your node’s internal IP is 10.10.10.10, then by default:

While IP + Port works fine for dev/test environments (hey, we’re all lazy sometimes!), for more serious deployments, I strongly recommend accessing these services via domain names.

Using domains has numerous advantages, doesn’t cost extra, and requires just one simple config line.

Let’s dive into these topics:


TL;DR

Add this static resolution record to your /etc/hosts (Linux/MacOS) or C:\Windows\System32\drivers\etc\hosts (Windows):

sudo tee -a /etc/hosts <<EOF
10.10.10.10 h.pigsty g.pigsty p.pigsty a.pigsty
EOF

Replace placeholder IP 10.10.10.10 with your Pigsty node’s IP (public/private, as long as it’s reachable).

If you modified default domains in infra_portal, replace them with your custom domains.


Why Use Domains?

Pigsty strongly recommends using domains instead of direct IP+Port access for several reasons:

  • Domains are easier to remember (unless you’re a robot 🤖)
  • More flexible — point to different IPs without changing configs
  • Consolidate all services behind Nginx for better management, auditing, and reduced attack surface
  • Enable HTTPS encryption to prevent traffic snooping
  • In China, HTTP access to unregistered domains gets hijacked by ISPs, but HTTPS doesn’t
  • Access services bound to 127.0.0.1 or internal Docker networks via Nginx proxy

Pigsty uses internal static domains by default — just add DNS records locally, no need to register real domains.

For internet-facing deployments, consider using real domains with free HTTPS certs.


How DNS Works

If you’re not familiar with HTTP/DNS protocols, here’s a quick primer on how Nginx serves multiple domains on a single port (80 + HTTPS 443):

DNS Protocol

HTTP Protocol

  • HTTP requests (HTTP/1.1+) include a Host header with the requested domain
  • This Host header is crucial — HTTP/1.1 spec requires clients to include it
  • Nginx uses the Host header to match and route requests to different sites
  • Thus, one port can serve different content based on the Host value

Pigsty Default Domains

Pigsty configures these four internal domains by default:

Domain Name Port Component Description
h.pigsty home 80/443 Nginx Default server, local repo
g.pigsty grafana 3000 Grafana Monitoring & visualization
p.pigsty prometheus 9058 Prometheus Time series DB
a.pigsty alertmanager 9059 AlertManager Alert aggregation & routing

Since these domains don’t use TLDs, you’ll need local static or internal dynamic resolution.

Don’t worry — it’s just one config line away! 🚀


Local Static Resolution

Assuming Pigsty’s internal IP is 10.10.10.10, add this to your client machine’s hosts file:

# Pigsty core components & default domains
10.10.10.10 h.pigsty g.pigsty p.pigsty a.pigsty

Adding Resolution

The client machine is where you browse Pigsty services — your laptop, desktop, VM, etc.

For Linux / macOS: sudo nano /etc/hosts For Windows: Run notepad as admin, edit C:\Windows\System32\drivers\etc\hosts

After adding the record, you can access Pigsty web services via these domains.

Custom Domains

Not a fan of default domains? Modify them in infra_portal before installation:

infra_portal:
  home         : { domain: h.pigsty.xxx }
  grafana      : { domain: g.pigsty.xxx ,endpoint: "${admin_ip}:3000" ,websocket: true }
  prometheus   : { domain: p.pigsty.xxx ,endpoint: "${admin_ip}:9058" }
  alertmanager : { domain: a.pigsty.xxx ,endpoint: "${admin_ip}:9059" }
  blackbox     : { endpoint: "${admin_ip}:9115" }
  loki         : { endpoint: "${admin_ip}:3100" }

Then update your hosts file accordingly:

10.10.10.10 h.pigsty.xxx g.pigsty.xxx p.pigsty.xxx a.pigsty.xxx

Use any domain you like — real or made-up - as long as it resolves to Pigsty’s IP via local, internal, or public DNS.

Additional Records

Running other Pigsty extensions? Add these records too:

# Pigsty extension tools & default domains
10.10.10.10 adm.pigsty   # pgAdmin GUI
10.10.10.10 ddl.pigsty   # Bytebase DDL management
10.10.10.10 cli.pigsty   # pig CLI reserved
10.10.10.10 api.pigsty   # Pigsty API reserved
10.10.10.10 lab.pigsty   # JupyterLab reserved
10.10.10.10 git.pigsty   # Gitea reserved
10.10.10.10 wiki.pigsty  # Wiki.js reserved
10.10.10.10 noco.pigsty  # NocoDB reserved
10.10.10.10 supa.pigsty  # Supabase reserved
10.10.10.10 dify.pigsty  # Dify reserved
10.10.10.10 odoo.pigsty  # Odoo reserved
10.10.10.10 mm.pigsty    # MinIO reserved

Public IP Resolution

For cloud deployments, resolve to your public IP, not internal IP.

If your server has internet access, it typically has two NICs - one for internet (public IP) and one for internal network (private IP).

Example: If your cloud server’s public IP is 1.2.3.4 and VPC IP is 10.10.10.10:

# For cloud deployments, resolve to public IP! Just change the IP part:
1.2.3.4 h.pigsty g.pigsty p.pigsty a.pigsty

Internal Dynamic Resolution

Want your office colleagues to access Pigsty via domains? Use internal dynamic resolution.

The simplest way: Ask your network admin to add the DNS records to your internal DNS server.

Using Internal DNS

If your internal DNS server is 192.168.1.1, on Linux/MacOS edit /etc/resolv.conf:

nameserver 192.168.1.1

On Windows: Network Settings → Network Adapter → TCP/IPv4 Properties → DNS config

Test internal DNS resolution:

dig h.pigsty @192.168.1.1

Using Pigsty’s DNS

Pigsty Infra module includes DNS server (port 53).

⚠️ Warning for China deployments: Public servers typically cannot run DNS services (port 53)!


Local HTTPS Access

HTTP access to Pigsty shows “Not Secure” - it’s plaintext, susceptible to MITM attacks.

By default, Pigsty uses a local self-signed CA to issue certs for all Nginx virtual hosts.

HTTPS access shows “Certificate Error” - these are self-signed certs, not from a trusted CA.

Your options:

  • Ignore it, use HTTP or IP+Port (it’s internal anyway, right? 😅)
  • Use HTTPS, click “Advanced → Proceed anyway”
  • Chrome users: Type thisisunsafe when warned (magic words!)
  • Trust the self-signed certs by adding Pigsty’s CA to your browser/OS
  • Use a real CA cert for Pigsty
  • Use real domains with proper HTTPS certs

For internal access needing HTTPS without constant warnings, trust Pigsty’s self-signed CA.

For production, we recommend using public domains with free HTTPS certs via certbot.


Trust Self-signed CA

Pigsty generates a self-signed CA in the admin node source directory (~/pigsty) during init.

To use HTTPS, distribute Pigsty’s CA cert to client trust stores (or use real CAs — expensive!).

Pigsty-managed Linux nodes auto-trust the CA. For other Linux systems:

  • Trust CA Cert
  • EL
  • Debian / Ubuntu
rm -rf /etc/pki/ca-trust/source/anchors/ca.crt
ln -s /etc/pki/ca.crt /etc/pki/ca-trust/source/anchors/ca.crt
/bin/update-ca-trust

MacOS: Double-click ca.crt, add to Keychain, search pigsty-ca, open and “Trust” the root cert.

Windows: Add ca.crt to “Trusted Root Certification Authorities”.

After trusting Pigsty’s CA, no more “untrusted certificate” warnings! 🎉


Public Domain Resolution

Use DNS providers like Cloudflare, Godaddy, Aliyun, or Tencent Cloud DNSPod.

Requires purchasing a domain - basic ones cost ~$10/year.

Add DNS records via provider’s console/API to point domains to Pigsty’s public IP.

Example: With domain pigsty.xxx, add wildcard * A record or individual A records:

  • h.pigsty.xxx → 1.2.3.4
  • a.pigsty.xxx → 1.2.3.4
  • p.pigsty.xxx → 1.2.3.4
  • g.pigsty.xxx → 1.2.3.4

Pigsty includes Certbot support for free HTTPS certs (renew every 3 months).


Further Reading

For more advanced configurations, check the Pigsty documentation for DNS, Nginx, and HTTPS certificate management.

6 - SSL Certs

Configure real & self-signed HTTPS certs

Pigsty comes with Certbot pre-installed on the Infra node, enabling you to obtain free Let’s Encrypt HTTPS certificates for Nginx servers and public domains.


Prerequisites

Before obtaining Let’s Encrypt certificates, ensure you have:

  • A public domain name
  • DNS records pointing to your server’s public IP
  • Nginx properly configured with your domains

Step 1: Determine Which Domains Need Certificates

First, identify which upstream services require public certificates by configuring domains in your infra_portal:

infra_portal:
  home         : { domain: h.pigsty.cc }
  grafana      : { domain: g.pigsty.cc, endpoint: "${admin_ip}:3000", websocket: true }
  prometheus   : { domain: p.pigsty.cc, endpoint: "${admin_ip}:9058" }
  alertmanager : { domain: a.pigsty.cc, endpoint: "${admin_ip}:9059" }
  minio        : { domain: m.pigsty.cc, endpoint: "${admin_ip}:9001", scheme: https, websocket: true }
  web          : { domain: pigsty.cc, path: "/www/web.cc" }
  repo         : { domain: repo.pigsty.cc, path: "/www/repo" }

Step 2: Point Domains to Your Server

Configure DNS A records to point all your domains to your server’s public IP address:

# Example DNS configuration
47.83.172.23 pigsty.cc
47.83.172.23 h.pigsty.cc
47.83.172.23 g.pigsty.cc
47.83.172.23 p.pigsty.cc
47.83.172.23 a.pigsty.cc
47.83.172.23 m.pigsty.cc
47.83.172.23 repo.pigsty.cc

Verify that your domains are properly pointing to your server:

# Test domain resolution
nslookup pigsty.cc
dig g.pigsty.cc

Step 3: Request Certificates with Certbot

Use Certbot to request Let’s Encrypt certificates for your domains:

Interactive Method (First Time)

certbot --nginx -d pigsty.cc -d repo.pigsty.cc -d g.pigsty.cc -d p.pigsty.cc -d a.pigsty.cc

During the first run, you’ll be prompted to:

  • Provide an email address for Let’s Encrypt account registration
  • Agree to the Terms of Service
  • Choose whether to share your email with the Electronic Frontier Foundation

Non-Interactive Method

For automated deployments, use the non-interactive mode:

certbot --nginx --agree-tos --email [email protected] -n -d your-domain.com

Example for multiple domains:

certbot --nginx --agree-tos --email [email protected] -n \
  -d pigsty.cc \
  -d g.pigsty.cc \
  -d p.pigsty.cc \
  -d a.pigsty.cc \
  -d repo.pigsty.cc

Step 4: Update Nginx Configuration

After successfully obtaining certificates, update your infra_portal configuration to use them by adding the certbot: true parameter:

infra_portal:
  grafana: { domain: g.pigsty.cc, endpoint: "${admin_ip}:3000", websocket: true, certbot: true }
  prometheus: { domain: p.pigsty.cc, endpoint: "${admin_ip}:9058", certbot: true }
  alertmanager: { domain: a.pigsty.cc, endpoint: "${admin_ip}:9059", certbot: true }
  web: { domain: pigsty.cc, path: "/www/web.cc", certbot: true }
  repo: { domain: repo.pigsty.cc, path: "/www/repo", certbot: true }

Then regenerate the Nginx configuration and restart the service:

./infra.yml -t nginx_config,nginx_launch

Step 5: Configure Certificate Renewal

Let’s Encrypt certificates expire every 90 days. Set up automatic renewal to ensure continuous HTTPS coverage:

Test Renewal (Dry Run)

Before setting up automatic renewal, test the process:

certbot renew --dry-run

Manual Renewal

To manually renew all certificates:

certbot renew

To renew a specific certificate:

certbot renew --cert-name your-domain.com

Automatic Renewal

Set up a monthly cron job for automatic renewal:

# Add to crontab
crontab -e

# Add this line for monthly renewal at 2 AM on the 1st day
0 2 1 * * certbot renew --quiet

Alternatively, use a systemd timer if available:

# Enable certbot timer
systemctl enable certbot.timer
systemctl start certbot.timer

Certificate Management Commands

Here are useful Certbot commands for managing your certificates:

# List all certificates
certbot certificates

# View certificate details
certbot certificates --cert-name your-domain.com

# Renew specific certificate
certbot renew --cert-name your-domain.com

# Delete certificate
certbot delete --cert-name your-domain.com

# Expand certificate to include new domains
certbot --nginx -d existing-domain.com -d new-domain.com

# Revoke certificate
certbot revoke --cert-path /etc/letsencrypt/live/your-domain.com/cert.pem

Troubleshooting

Common Issues

  1. Domain not accessible: Ensure DNS records are properly configured and propagated
  2. Port 80 blocked: Let’s Encrypt requires port 80 for domain validation
  3. Rate limits: Let’s Encrypt has rate limits; avoid requesting too many certificates quickly
  4. Firewall issues: Ensure ports 80 and 443 are open in your firewall

Verification Commands

# Check certificate expiration
openssl x509 -in /etc/letsencrypt/live/your-domain.com/cert.pem -text -noout | grep "Not After"

# Test SSL configuration
openssl s_client -connect your-domain.com:443 -servername your-domain.com

# Check Nginx configuration
nginx -t

# Reload Nginx
nginx -s reload

Best Practices

  1. Use wildcard certificates for multiple subdomains when appropriate
  2. Monitor certificate expiration with automated alerts
  3. Test renewal process regularly with dry runs
  4. Keep backups of your certificate files
  5. Use staging environment for testing before production deployment
  6. Set up monitoring for certificate expiration dates
  7. Document your domain configuration for team reference

Security Considerations

  • Protect private keys: Ensure certificate private keys have restricted permissions
  • Use strong SSL configuration: Configure Nginx with modern SSL settings
  • Enable HTTP to HTTPS redirection: Force secure connections
  • Implement HSTS: Add HTTP Strict Transport Security headers
  • Regular security audits: Test your SSL configuration with tools like SSL Labs