Nextcloud: The Master-Slave Guide

Nextcloud: The Master-Slave Guide

Nextcloud manual setup steps

  • Update and Install Dependencies

We need the web server and all PHP modules required by Nextcloud.
Run this on Server 1 AND Server 2:

sudo apt update

sudo apt install apache2 php libapache2-mod-php php-mysql php-common php-gd php-curl php-imagick php-mbstring php-xml php-zip php-intl php-bcmath php-gmp unzip -y
  • Enable Required Apache Modules

Run this on Server 1 AND Server 2:

sudo a2enmod rewrite headers env dir mime
sudo systemctl restart apache2
  • Create the Directory Structure

Run this on Server 1 AND Server 2:

sudo mkdir -p /var/www/html/nextcloud
sudo mkdir -p /var/www/html/nextcloud/data
  • Set Permissions

Apache (www-data) must own these folders to write files.
Run this on Server 1 AND Server 2:

sudo chown -R www-data:www-data /var/www/html/nextcloud
sudo chmod -R 755 /var/www/html/nextcloud
  • Download and Unzip

Run this on Server 1 AND Server 2:

cd /var/www/html
sudo wget https://download.nextcloud.com/server/releases/latest.zip
sudo unzip latest.zip

unzip will extract everything into the nextcloud folder we created

  • Final Permission Fix

Ensure the new files are owned by the web server.

sudo chown -R www-data:www-data /var/www/html/nextcloud
  • Configure Apache

Run this on Server 1 AND Server 2 to create the web config:

sudo nano /etc/apache2/sites-available/nextcloud.conf

Paste this content:

<VirtualHost *:80>
    DocumentRoot /var/www/html/nextcloud
    
    <Directory /var/www/html/nextcloud>
        Require all granted
        AllowOverride All
        Options FollowSymLinks MultiViews
    </Directory>
</VirtualHost>

Enable the site:

sudo a2ensite nextcloud.conf
sudo a2enmod rewrite
sudo systemctl restart apache2

Database setup (Master slave replication)

  • Set up the Master (Server 1 Only)
  1. Secure the installation:
sudo mysql\_secure\_installation
  1. Create the Database:
sudo mysql -u root -p
CREATE DATABASE nextcloud;
CREATE USER 'nc\_admin'@'localhost' IDENTIFIED BY '12345';
GRANT ALL PRIVILEGES ON nextcloud.\* TO 'nc\_admin'@'localhost';

-- Create the User for Server 2 to copy data

CREATE USER 'replicator'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON \*.\* TO 'replicator'@'%';
FLUSH PRIVILEGES;
  1. Enable Binary Logging: Edit /etc/mysql/mariadb.conf.d/50-server.cnf:
bind-address = 0.0.0.0
server-id    = 1
log\_bin      = /var/log/mysql/mysql-bin.log
binlog\_do\_db = nextcloud

Restart & Get Coordinates:

sudo systemctl restart mysql
sudo mysql -u root -p -e "SHOW MASTER STATUS;"
  • Set up the Slave (Server 2 Only)
  1. Do NOT create a database. (It will copy Server 1's DB).

  2. Configure Config File: Edit /etc/mysql/mariadb.conf.d/50-server.cnf:

bind-address = 0.0.0.0
server-id    = 2
log\_bin      = /var/log/mysql/mysql-bin.log
binlog\_do\_db = nextcloud
  1. Restart:
sudo systemctl restart mysql
  • Connect Slave to Master
  1. Run on Server 2: Note: If servers are on different networks (192.168 vs 10.10), open the SSH tunnel first.
STOP SLAVE;
CHANGE MASTER TO
MASTER\_HOST='192.168.0.135', -- Or '127.0.0.1' if using Tunnel
MASTER\_USER='replicator',
MASTER\_PASSWORD='password',
MASTER\_LOG\_FILE='mysql-bin.000001', -- From Phase 2, Step 1
MASTER\_LOG\_POS=123;                 -- From Phase 2, Step 1
START SLAVE;
  1. Copy Config to Server 2:

On Server 1: Open /var/www/html/nextcloud/config/config.php and copy the text.

sudo nano /var/www/html/nextcloud/config/config.php

On Server 2: Create the file:
Paste the text.

sudo nano /var/www/html/nextcloud/config/config.php

Important Change: Find the line 'dbhost' => 'localhost', and ensure it stays localhost (so Server 2 reads its own replica DB).


File Synchronization (Unison)

  • Install Unison (Both Servers)
sudo apt install unison -y
  • Configure SSH Key (Server 2 -> Server 1)
ssh-keygen -t ed25519
ssh-copy-id gyriexp@192.168.0.135
  • Create Sync Profile (Server 2)
    Create ~/.unison/default.prf:
root = /var/www/html/nextcloud/data
root = ssh://gyriexp@192.168.0.135//var/www/html/nextcloud/data
auto = true
batch = true
prefer = newer
perms = 0     # Ignore permissions
  • Running the Sync

Run this sequence whenever you want to backup files:

  1. On Server 1 (Unlock):
sudo chown -R gyriexp:gyriexp /var/www/html/nextcloud/data
  1. On Server 2 (Sync):
unison default
  1. On Server 1 (Lock):
sudo chown -R www-data:www-data /var/www/html/nextcloud/data

Special conditions

Server 1 Fails → Make Server 2 Master → Restore Server 1 as Slave

  • Promote Server 2

Run these on Server 2 to make it the independent Master.

1.Stop it from looking for the dead master:

sudo mysql -u root -p -e "STOP SLAVE; RESET SLAVE ALL;"

2.Enable Writes (if Read-Only was on)

sudo mysql -u root -p -e "SET GLOBAL read\_only = OFF;"
  1. Update Nextcloud Config: Ensure config.php points to localhost.
sudo nano /var/www/html/nextcloud/config/config.php

Ensure: 'dbhost' => 'localhost',

  • Server 1 is Back (Make it the Slave)
  1. Create Backup on Server 2:

Run on Server 2

sudo mysqldump -u root -p --all-databases --master-data > production\_backup.sql
  1. Send Backup to Server 1:

Run on Server 2

scp production\_backup.sql user@server1\_ip:/home/user/
  1. Import & Configure Slave on Server 1:

Run on Server 1

sudo mysql -u root -p < /home/user/production\_backup.sql
  1. Start Replication on Server 1:

Run on server 2

sudo mysql -u root -p -e "SHOW MASTER STATUS;"

Run on server 1

sudo mysql -u root -p
STOP SLAVE;
CHANGE MASTER TO
MASTER\_HOST='Server2\_IP',
MASTER\_USER='replicator',
MASTER\_PASSWORD='password',
MASTER\_LOG\_FILE='mysql-bin.00000X',  -- Value from Server 2
MASTER\_LOG\_POS=1234;                 -- Value from Server 2
START SLAVE;
  • Correct Unison File Sync

Since Unison is bidirectional, you usually don't need to change the command if the config is on Server 2. It will detect Server 2 has "New files" and Server 1 is empty/old, and it will push them automatically.

\# Unlock Server 1
ssh user@server1\_ip "sudo chown -R user:user /var/www/html/nextcloud/data"

\# Run Sync (Pushes S2 data to S1)
unison default

\# Lock Server 1
ssh user@server1\_ip "sudo chown -R www-data:www-data /var/www/html/nextcloud/data"

Normal chain is S1 → S2 → S3. Server 2 dies. You need S1 to sync directly to S3. When S2 returns, S3 updates S2.

  • Bypass Server 2 (S2 is Down)
  1. Create a "Bypass Profile" on Server 3:
nano ~/.unison/bypass.prf

Paste this:

\# Sync Local (S3) with Server 1 (Skipping S2)
root = /var/www/html/nextcloud/data
root = ssh://user@server1\_ip//var/www/html/nextcloud/data
auto = true
batch = true
prefer = newer
perms = 0
  1. Run the Bypass Sync: Run this on Server 3 whenever S2 is down.
\# 1. Unlock Server 1
ssh user@server1\_ip "sudo chown -R user:user /var/www/html/nextcloud/data"

\# 2. Sync S3 <-> S1
unison bypass

\# 3. Lock Server 1
ssh user@server1\_ip "sudo chown -R www-data:www-data /var/www/html/nextcloud/data"
  • Server 2 is Back (Restore & Fill Gaps)
  1. Sync S3 → S2 (Run on Server 3): We create a temporary profile to push data back to the recovered Server 2.
nano ~/.unison/restore\_s2.prf
\# Sync Local (S3) to Server 2
root = /var/www/html/nextcloud/data
root = ssh://user@server2\_ip//var/www/html/nextcloud/data
auto = true
batch = true
prefer = newer
perms = 0
  1. Run the Restore Sync:
\# 1. Unlock Server 2 (The recovered server)
ssh user@server2\_ip "sudo chown -R user:user /var/www/html/nextcloud/data"

\# 2. Sync S3 -> S2
unison restore\_s2

\# 3. Lock Server 2
ssh user@server2\_ip "sudo chown -R www-data:www-data /var/www/html/nextcloud/data"
  1. Resume Normal Operations: Now that S2 is up-to-date, you can go back to your original setup (S1 syncing to S2, and S2 syncing to S3).
  • step 1: Verify Server 2 is "Clean"

Run on Server 2:

ls -l /var/www/html/nextcloud/data/
  • Step 2: Resume Server 1 → Server 2 Sync
  1. Unlock Server 2
    Run on Server 1
ssh user@server2_ip "sudo chown -R user:user /var/www/html/nextcloud/data"
  1. ssh user@server2_ip "sudo chown -R user:user /var/www/html/nextcloud/data"
unison default
  1. Lock Server 2:
ssh user@server2_ip "sudo chown -R www-data:www-data /var/www/html/nextcloud/data"
  • Step 3: Resume Server 2 → Server 3 Sync

Now that S2 is updated by S1, it passes those updates down to S3.
Run on Server 2: (Assuming you have a profile named sync_to_s3 that points to S3).

Unlock Server 3:

ssh user@server3_ip "sudo chown -R user:user /var/www/html/nextcloud/data"

Run the Standard Sync:

unison sync_to_s3

Lock Server 3:

ssh user@server3_ip "sudo chown -R www-data:www-data /var/www/html/nextcloud/data"

Read more