• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Setting up PostgreSQL master-slave replication on openSUSE Leap 15.5 for high-volume Laravel applications

Setting up PostgreSQL master-slave replication on openSUSE Leap 15.5 for high-volume Laravel applications

Prerequisites and Initial Setup

This guide assumes you have two openSUSE Leap 15.5 servers provisioned and accessible via SSH. One will serve as the PostgreSQL master, and the other as the slave. Both servers require a static IP address. For this setup, we’ll use 192.168.1.100 for the master and 192.168.1.101 for the slave. Ensure that the PostgreSQL packages are installed on both machines. If not, use zypper install postgresql-server postgresql-contrib.

On the master server (192.168.1.100), initialize the PostgreSQL cluster if it hasn’t been done already:

sudo systemctl enable postgresql
sudo systemctl start postgresql
sudo -u postgres /usr/lib/postgresql/15/bin/initdb --pgdata=/var/lib/pgsql/data

On the slave server (192.168.1.101), perform the same initialization steps.

Configuring the PostgreSQL Master

The master server needs to be configured to accept replication connections and to log write-ahead log (WAL) information in a format suitable for streaming replication. Edit the PostgreSQL configuration file, typically located at /var/lib/pgsql/data/postgresql.conf.

# In /var/lib/pgsql/data/postgresql.conf on the master

listen_addresses = '*' # Or specify master's IP: '192.168.1.100'
wal_level = replica
wal_sync_method = fsync
wal_compression = on
wal_buffers = 16MB
max_wal_senders = 5 # Number of concurrent replication connections
max_replication_slots = 5 # Number of replication slots
hot_standby = on # Allows read queries on the slave
archive_mode = on
archive_command = 'cp %p /var/lib/pgsql/wal_archive/%f' # Example: archive to a local directory

Next, configure client authentication in /var/lib/pgsql/data/pg_hba.conf to allow replication from the slave server. We’ll create a dedicated replication user.

# In /var/lib/pgsql/data/pg_hba.conf on the master

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    replication     repl_user       192.168.1.101/32        scram-sha-256
host    all             all             192.168.1.0/24          scram-sha-256 # For application access

After modifying these files, create the WAL archive directory and restart the PostgreSQL service on the master:

sudo mkdir -p /var/lib/pgsql/wal_archive
sudo chown postgres:postgres /var/lib/pgsql/wal_archive
sudo systemctl restart postgresql

Now, create the replication user and grant necessary privileges. Log in to PostgreSQL as the `postgres` user:

sudo -u postgres psql

Inside the `psql` prompt, execute the following SQL commands:

CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'your_strong_replication_password';
-- If you need to replicate a specific database, grant connect on that database
-- CREATE DATABASE my_laravel_db; -- if it doesn't exist
-- GRANT CONNECT ON DATABASE my_laravel_db TO repl_user;
-- For full replication, no specific database grants are strictly needed for the role itself,
-- but the user running the replication process needs to be able to connect.
\q

Configuring the PostgreSQL Slave

Before setting up replication, ensure the slave server has a clean PostgreSQL installation and is stopped. The replication process will overwrite its data directory.

sudo systemctl stop postgresql

On the slave, we need to perform an initial data synchronization from the master. The most robust method is using pg_basebackup. First, remove any existing data directory on the slave:

sudo rm -rf /var/lib/pgsql/data/*

Now, execute pg_basebackup from the slave server, connecting to the master. This command will download the entire data directory from the master.

sudo -u postgres pg_basebackup -h 192.168.1.100 -U repl_user -D /var/lib/pgsql/data -P -v -R

Explanation of flags:

  • -h 192.168.1.100: Hostname or IP of the master server.
  • -U repl_user: The replication user created on the master.
  • -D /var/lib/pgsql/data: The target data directory on the slave.
  • -P: Show progress.
  • -v: Verbose output.
  • -R: Create standby.signal and postgresql.auto.conf (or recovery.conf in older versions) to configure the server as a standby.

You will be prompted for the replication user’s password. If pg_basebackup -R was successful, it will create a standby.signal file in the data directory and a postgresql.auto.conf file with replication connection settings. Verify its content:

# Contents of /var/lib/pgsql/data/postgresql.auto.conf on the slave
primary_conninfo = 'user=repl_user password=your_strong_replication_password host=192.168.1.100 port=5432 sslmode=prefer sslcompression=0 gssencmode=prefer krbservice=postgres'
primary_slot_name = 'your_replication_slot_name' # Optional, but recommended

If you want to use a replication slot (highly recommended for preventing WAL file buildup on the master if the slave is down), create it on the master first:

sudo -u postgres psql
-- Inside psql
SELECT pg_create_physical_replication_slot('your_replication_slot_name');
\q

Ensure the primary_slot_name in postgresql.auto.conf on the slave matches the name created on the master. Also, ensure the PostgreSQL user on the slave has correct ownership of the data directory:

sudo chown -R postgres:postgres /var/lib/pgsql/data

Now, start the PostgreSQL service on the slave:

sudo systemctl start postgresql

Verification and Monitoring

Check the PostgreSQL logs on both the master and slave servers for any errors. On the master, you can check for active replication connections:

sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

On the slave, check the logs for messages indicating it’s connected to the master and streaming WAL. You can also query the slave to see if data is being replicated. If you created a database named my_laravel_db on the master, you should be able to connect to it on the slave and see its contents (assuming hot_standby = on and appropriate pg_hba.conf entries for read access).

# On the slave
sudo -u postgres psql -d my_laravel_db -c "SELECT count(*) FROM some_table;"

For Laravel applications, you’ll typically configure your database connection to use the master for writes and the slave for reads. This is usually managed within your config/database.php file.

/* In config/database.php */
'connections' => [
    'mysql' => [ // Assuming 'mysql' is your primary connection name, rename if needed
        'driver' => 'pgsql',
        'host' => env('DB_MASTER_HOST', '192.168.1.100'),
        'port' => env('DB_PORT', '5432'),
        'database' => env('DB_DATABASE', 'your_db_name'),
        'username' => env('DB_USERNAME', 'your_db_user'),
        'password' => env('DB_PASSWORD', 'your_db_password'),
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
    ],

    'pgsql_read' => [ // A new connection for read replicas
        'driver' => 'pgsql',
        'host' => env('DB_SLAVE_HOST', '192.168.1.101'),
        'port' => env('DB_PORT', '5432'),
        'database' => env('DB_DATABASE', 'your_db_name'),
        'username' => env('DB_USERNAME', 'your_db_user'), // Use a read-only user if possible
        'password' => env('DB_PASSWORD', 'your_db_password'),
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
    ],
],

/* In config/database.php - Replication configuration */
'redis' => [
    // ... other redis configs
],

'pgsql_replication' => [
    'read' => [
        '1' => [
            'host' => env('DB_SLAVE_HOST', '192.168.1.101'),
            'port' => env('DB_PORT', '5432'),
            'database' => env('DB_DATABASE', 'your_db_name'),
            'username' => env('DB_USERNAME', 'your_db_user'),
            'password' => env('DB_PASSWORD', 'your_db_password'),
            'charset' => 'utf8',
            'prefix' => '',
            'schema' => 'public',
            'sslmode' => 'prefer',
        ],
    ],
    'write' => [
        'host' => env('DB_MASTER_HOST', '192.168.1.100'),
        'port' => env('DB_PORT', '5432'),
        'database' => env('DB_DATABASE', 'your_db_name'),
        'username' => env('DB_USERNAME', 'your_db_user'),
        'password' => env('DB_PASSWORD', 'your_db_password'),
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
    ],
],

Ensure your .env file is updated with the correct master and slave IP addresses:

DB_MASTER_HOST=192.168.1.100
DB_SLAVE_HOST=192.168.1.101
DB_PORT=5432
DB_DATABASE=your_db_name
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password

Advanced Considerations and Troubleshooting

Replication Lag: Monitor replication lag using pg_stat_replication on the master and by checking the slave’s logs. Tools like PMM (Percona Monitoring and Management) or custom scripts can help automate this. If lag is consistently high, investigate network latency, slave I/O performance, or if the slave is overloaded with read queries.

Failover: This setup is for replication, not automatic failover. For high availability, consider tools like Patroni, repmgr, or Pacemaker. Manual failover involves stopping writes to the master, promoting the slave (using pg_ctl promote or pg_promote()), and reconfiguring other slaves and applications to point to the new master.

WAL Archiving: The archive_command on the master is crucial for point-in-time recovery and for slaves that might fall far behind. Ensure the archive destination is reliable and has sufficient space. If using pg_basebackup -R, it might configure restore_command on the slave automatically. If not, you’ll need to configure it manually in postgresql.conf or postgresql.auto.conf to allow the slave to fetch archived WAL files.

Security: Use strong passwords for replication users. Consider using SSL for replication connections by setting ssl = on in postgresql.conf on the master and configuring sslmode appropriately in pg_hba.conf and the client connection strings.

Resource Allocation: Ensure both master and slave servers have adequate CPU, RAM, and fast I/O (SSDs are highly recommended for database workloads). Tune PostgreSQL parameters like shared_buffers, work_mem, and checkpoint settings based on your server’s resources and workload.

Laravel Specifics: For read/write splitting in Laravel, you can leverage the pgsql_replication configuration array and use the DB::connection('pgsql_replication') facade. For more advanced scenarios, consider packages like spatie/laravel-db-pure-php or custom query builders that can intelligently route read queries to replicas.

Reader Interactions

Leave a Reply Cancel reply

You must be logged in to post a comment.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store
  • How to refactor legacy event ticket registers queries using modern WP_Query and custom Transient caching
  • Step-by-Step Guide: Offloading high-frequency member profile directories metadata writes to a Redis KV store

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (662)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • PHP (5)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (647)
  • SEO & Growth (492)
  • Server (118)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (726)
  • WordPress Theme Development (357)

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (726)
  • Debugging & Troubleshooting (662)
  • Security & Compliance (647)
  • SEO & Growth (492)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala