Hosting runbook

Set up Quorla on app.quorlasocial.com

This moves the social media dashboard from Manesh's Windows PC to a Linux server, so the whole team can use it from anywhere over HTTPS. Follow the steps in order. Commands are copy-and-paste; anything in CAPITALS is something you replace.

Time: about 1½–2 hours Downtime: about 15 minutes (step 6 to step 9) Skills: SSH and basic Linux commands

Caddy gets and renews the HTTPS certificate automatically. The app container also runs the publishing queue every 2 minutes, so nothing else needs scheduling.

1Before you start

Who: you, with Manesh for the items marked ★

2Point the domain at the server

Where: the DNS settings for quorlasocial.com

Add one record. Do this first, because it can take a few minutes to an hour to spread.

TypeName / HostValueTTL
AappSERVER_IP300 (or Auto)
If the DNS is on Cloudflare

Set the record to DNS only (grey cloud) for now. Caddy needs to reach the server directly to issue the certificate.

Check it from your own computer. It should print the server's IP:

Your computer
nslookup app.quorlasocial.com

3Prepare the server

Where: SSH into the server as root

3a. Updates, a working user, and the firewall

Server · root
ssh root@SERVER_IP

apt update && apt -y upgrade
apt -y install git ufw unattended-upgrades
timedatectl set-timezone UTC

# A normal user to run Quorla (replace YOURNAME)
adduser YOURNAME
usermod -aG sudo YOURNAME

# Firewall: only SSH and web traffic
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 443/udp
ufw --force enable
SSH keys

If you log in with a password, add your SSH key now (ssh-copy-id YOURNAME@SERVER_IP from your computer) and then turn off password logins in /etc/ssh/sshd_config (PasswordAuthentication no, then systemctl restart ssh).

3b. Install Docker

Server · root
curl -fsSL https://get.docker.com | sh
usermod -aG docker YOURNAME
docker --version
docker compose version

Both version commands should print a version number. Log out, then log back in as your user for the rest of the guide:

Your computer
ssh YOURNAME@SERVER_IP

4Get the code

Where: server, as your user

Server · your user
sudo mkdir -p /opt/quorla
sudo chown $USER:$USER /opt/quorla
git clone https://git.metatroncube.in/MetatroncubeSoftwareSolutions/quorlasocial.git /opt/quorla
cd /opt/quorla
ls

You should see Dockerfile, docker-compose.yml, deploy/, dashboard/ and connector/. Git asks for your git.metatroncube.in username and password (or an access token) when cloning.

The repository contains only the program. Client files, logins, uploads and secrets are deliberately left out of Git; they come across in steps 5 and 6.

5Add the settings file

Where: server, in /opt/quorla

Put Manesh's .env file in /opt/quorla/.env (for example with scp .env YOURNAME@SERVER_IP:/opt/quorla/ from the computer where you received it). Then lock it down and open it:

Server · your user
cd /opt/quorla
chmod 600 .env
sed -i 's/\r$//' .env        # removes Windows line endings, if any
nano .env

Check or add these lines. Leave everything else as it is.

SettingValueWhy
APP_DOMAINapp.quorlasocial.comThe address Caddy gets a certificate for.
ACME_EMAILsupport@quorlasocial.comCertificate expiry notices.
DASHBOARD_SECRETkeep the existing value; if empty, run openssl rand -hex 32 and paste the resultKeeps people signed in across restarts. Changing it signs everyone out.
ANTHROPIC_API_KEYthe key from step 1AI runs. Without it, audits and plans fail on the server.
ALLOW_PUBLISHfalse for nowYou turn it on in step 9, after the PC is switched off.
No spaces after the = sign

Write KEY=value, never KEY= value. A stray space or tab becomes part of the value and breaks tokens. Save in nano with Ctrl+O, Enter, then Ctrl+X.

You don't need to change SCHEDULER_ENABLED, DASHBOARD_HOST or DASHBOARD_COOKIE_SECURE; Docker sets those for the server.

6Move the data from the PC

Who: Manesh on the PC, then you on the server. Downtime starts here.

6a. On Manesh's PC: stop the dashboard and pack the data

Stop the dashboard (close its terminal window, or press Ctrl+C in it), then in PowerShell:

Windows PC · PowerShell
cd D:\MCS_Repos\2026\claude_Metatron_Social_Media_Manager
tar -czf quorla-data.tar.gz data clients team reports branding
scp quorla-data.tar.gz YOURNAME@SERVER_IP:/opt/quorla/

This archive holds client files and everyone's (hashed) logins. Delete it from the PC once step 8 has passed.

6b. On the server: unpack it

Server · your user
cd /opt/quorla
tar -xzf quorla-data.tar.gz
sudo chown -R 1000:1000 data clients team reports branding
rm quorla-data.tar.gz
ls data   # should list: dashboard  library  schedule  publish-log.jsonl ...

The chown matters: the app inside Docker runs as user 1000 and must be able to write to these folders.

7Start Quorla

Where: server, in /opt/quorla

Server · your user
cd /opt/quorla
docker compose up -d --build

The first build takes 3–6 minutes. Then fix the stored file locations (the PC used Windows paths like D:\…). Run it once to preview, then again with --write:

Server · your user
docker compose exec app node connector/scripts/relocate-paths.js
docker compose exec app node connector/scripts/relocate-paths.js --write

The last line should say 0 file(s) not found. Then check both containers are running and watch the log for a moment:

Server · your user
docker compose ps
docker compose logs -f --tail=50

app should show healthy after about 30 seconds, and the Caddy log should mention certificate obtained successfully. Press Ctrl+C to stop watching the log (Quorla keeps running).

8Check everything works

Where: your browser, signed in as an admin

Open https://app.quorlasocial.com. Everyone's existing logins came across with the data, so Manesh signs in with his usual email and password.

You can also check the Meta connection from the server:

Server · your user
docker compose exec app node connector/scripts/test-meta.js

9Switch over

Who: Manesh on the PC, then you on the server

Only one place may publish

If the PC and the server both run the queue, approved posts can go out twice. Finish 9a before 9b.

9a. On the PC: make sure nothing there can post

  • In the PC's .env, set ALLOW_PUBLISH=false.
  • Don't start the dashboard on the PC again (no npm start).
  • Check that no Windows scheduled task exists for the queue; this should say the task cannot be found:
Windows PC · PowerShell
schtasks /query /tn "SocialManagerScheduler"
# Only if it exists:
schtasks /delete /tn "SocialManagerScheduler" /f

9b. On the server: turn publishing on

Server · your user
cd /opt/quorla
sed -i 's/^ALLOW_PUBLISH=.*/ALLOW_PUBLISH=true/' .env
docker compose up -d

In Settings → Connections, Publishing now says On. Every post still needs an admin's approval before it goes out. Downtime ends here.

9c. Tell the team

Send everyone the new address, https://app.quorlasocial.com. Their email and password are unchanged. The India team needs nothing extra: no VPN, just the browser.

10Set up daily backups

Where: server, as your user

deploy/backup.sh packs the settings, logins, uploads, queue, client files and reports into /opt/quorla/backups/ and keeps the newest 14. Run it once by hand, then schedule it for 02:30 UTC every night:

Server · your user
cd /opt/quorla
sudo sh deploy/backup.sh
( crontab -l 2>/dev/null; echo "30 2 * * * cd /opt/quorla && sh deploy/backup.sh >> backups/backup.log 2>&1" ) | sudo crontab -
Copy backups off the server

A backup on the same server doesn't survive the server being lost. Copy backups/ somewhere else weekly (another server, or encrypted cloud storage). The backups contain the .env with the Meta token and API keys, so keep them private and encrypted.

Restoring a backup

Server · your user
cd /opt/quorla
docker compose down
sudo tar -xzf backups/quorla-YYYY-MM-DD-HHMM.tar.gz
sudo chown -R 1000:1000 data clients team reports branding
docker compose up -d

Updating Quorla

When a new version is pushed to Git:

Server · your user
cd /opt/quorla
sudo sh deploy/backup.sh
git pull
docker compose up -d --build
docker compose ps        # app should be "healthy" again within a minute

To roll back, run git log --oneline, pick the previous version, then git checkout THAT_ID and docker compose up -d --build. Your data isn't touched by updates or rollbacks.

Avoid updating while a post is due in the next few minutes; the queue pauses for about a minute during the restart, and anything due in that time goes out right after.

Everyday commands

Run these from /opt/quorla.

To…Run
See if it's runningdocker compose ps
Read recent app logsdocker compose logs --tail=100 app
Restart after changing .envdocker compose up -d
Restart without changesdocker compose restart app
Stop everythingdocker compose down
Check the Meta connectiondocker compose exec app node connector/scripts/test-meta.js
Recover admin access if nobody can sign indocker compose exec app node dashboard/server/scripts/add-user.js EMAIL "Name" admin (prints a new password once)
See disk spacedf -h / and du -sh data clients backups

Adding teammates, resetting passwords and changing roles are done in the dashboard under Settings → Team members, not on the server.

Troubleshooting

What you seeLikely causeFix
Browser warns about the certificate, or the site doesn't loadDNS not pointing at the server yet, or ports 80/443 blockedCheck step 2 with nslookup; check sudo ufw status and the hosting provider's own firewall panel; then docker compose restart caddy and read docker compose logs caddy.
"502 Bad Gateway"The app container isn't updocker compose logs --tail=100 app; usually a missing or mistyped line in .env.
docker compose says Set APP_DOMAIN or Set ACME_EMAILThose lines are missing from .envAdd them (step 5).
Settings shows Meta "Invalid OAuth access token"A space or tab after =, or the token was revokedFix the META_SYSTEM_USER_TOKEN line, then docker compose up -d. If it still fails, Manesh generates a new token in Meta Business Settings.
Signing in works but you're sent back to the sign-in pageNot on HTTPS, or DASHBOARD_SECRET empty or changedAlways use https://; set DASHBOARD_SECRET once and don't change it.
Uploads or saving fail with "permission denied" in the logData folders not owned by user 1000sudo chown -R 1000:1000 data clients team reports branding
AI runs fail straight awayNo API key, no credit, or a model name the key can't useCheck ANTHROPIC_API_KEY and the balance at console.anthropic.com; try DASHBOARD_AI_MODEL=claude-sonnet-5-5 in .env, then docker compose up -d.
Library thumbnails or scheduled posts say "file not found"Paths not relocated after the moveRun the two relocate-paths.js commands from step 7.
The disk is filling upVideo uploads and backupsdu -sh data/library backups; archive old library months elsewhere, or move to a bigger disk.
Keep port 4310 private

The app listens only inside Docker; the team always comes in through Caddy on HTTPS. Don't publish port 4310 in docker-compose.yml or open it in the firewall.