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)
- Secure the installation:
sudo mysql\_secure\_installation
- 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;
- 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)
-
Do NOT create a database. (It will copy Server 1's DB).
-
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
- Restart:
sudo systemctl restart mysql
- Connect Slave to Master
- 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;
- 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:
- On Server 1 (Unlock):
sudo chown -R gyriexp:gyriexp /var/www/html/nextcloud/data
- On Server 2 (Sync):
unison default
- 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;"
- 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)
- Create Backup on Server 2:
Run on Server 2
sudo mysqldump -u root -p --all-databases --master-data > production\_backup.sql
- Send Backup to Server 1:
Run on Server 2
scp production\_backup.sql user@server1\_ip:/home/user/
- Import & Configure Slave on Server 1:
Run on Server 1
sudo mysql -u root -p < /home/user/production\_backup.sql
- 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)
- 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
- 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)
- 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
- 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"
- 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
- Unlock Server 2
Run on Server 1
ssh user@server2_ip "sudo chown -R user:user /var/www/html/nextcloud/data"
- ssh user@server2_ip "sudo chown -R user:user /var/www/html/nextcloud/data"
unison default
- 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"