VPS पर Nextcloud कैसे चलाएं Docker के साथ
Docker Compose, Postgres और Redis का उपयोग करके VPS पर Nextcloud सेटअप करें। इसमें TLS और सुरक्षित backup के लिए सटीक निर्देश दिए गए हैं।
आप वास्तव में क्या बना रहे हैं
यह गाइड Docker Compose के साथ VPS पर Nextcloud चलाती है, इसके आगे Let's Encrypt TLS लगाती है, और एक ऐसा backup सेटअप करती है जो वास्तव में restore हो सके। इसमें चार containers और एक proxy शामिल हैं: loopback पर listening करने वाला official nextcloud image, file metadata रखने वाला Postgres, file locks रखने वाला Redis, cron loop चलाने वाला Nextcloud image का दूसरा copy, और host पर nginx जो सभी के आगे TLS terminate करता है। installation में बीस मिनट लगते हैं, लेकिन वह सबसे महत्वपूर्ण हिस्सा नहीं है। पहले घंटे में लिए गए दो निर्णय यह तय करेंगे कि क्या एक साल बाद भी आपके पास आपकी files होंगी: SQLite के बजाय एक real database, और एक ऐसा backup जो data directory, database और config.php को एक consistent set के रूप में capture करता है।
यह Ubuntu 24.04 LTS या Debian 13, Docker Engine (जिसमें Docker के अपने repository से installed Compose v2 plugin हो), और एक DNS A record (और यदि आपके पास IPv6 है तो AAAA) को पहले से ही VPS पर cloud.example.com point करने का अनुमान लगाता है। इसके लिए एक ऐसे server की आवश्यकता है जिसे आप control करते हों — किसी अन्य के SaaS पर TLS termination और database dump करने का कोई तरीका नहीं है।
Sizing: memory का वास्तविक उपयोग
Nextcloud का memory उपयोग मुख्य रूप से तीन चीजों पर निर्भर करता है, और इनमें से कोई भी स्वयं "Nextcloud" नहीं है।
PHP workers. -apache image प्रत्येक concurrent request को एक worker process से serve करती है, जिसमें PHP interpreter होता है। PHP द्वारा request को terminate करने से पहले प्रत्येक worker PHP_MEMORY_LIMIT तक बढ़ सकता है। आपका worst-case resident memory लगभग concurrent requests × memory limit के बराबर होता है, और एक desktop sync client प्रति user कई parallel connections खोलता है। User count के बजाय concurrency, memory की सीमा (ceiling) तय करती है।
The database. Postgres प्रत्येक connection के लिए एक backend fork करता है और shared buffers को resident रखता है। इसका working set bytes की संख्या के बजाय files की संख्या के साथ बढ़ता है: oc_filecache में प्रति file प्रति user एक row होती है। एक लाख छोटी files का database, सौ बड़ी files के database से अधिक भारी होता है।
Preview generation. Thumbnail generate करने के लिए source image को full resolution में memory में decode किया जाता है। Video previews के लिए ffmpeg का उपयोग किया जाता है। occ preview:generate-all चलाने पर यह spike बार-बार होता है, जिससे एक छोटा VPS आसानी से OOM killer का शिकार हो जाता है।
Redis तुलनात्मक रूप से सस्ता है। बाद में जो भी आप जोड़ते हैं — जैसे Collabora, full-text search, या antivirus scanner — वे अपने स्वयं के footprint के साथ अलग resident service होते हैं, और उन्हें enable करने से पहले आपके sizing plan में शामिल किया जाना चाहिए।
यदि आपके पास RAM कम है, तो ये विकल्प अपनाएं: PHP_MEMORY_LIMIT को कम करें, preview_max_x / preview_max_y / preview_max_filesize_image को limit करें, enabledPreviewProviders को केवल उन्हीं formats तक सीमित रखें जिन्हें आप वास्तव में browse करते हैं, और trashbin_retention_obligation एवं versions_retention_obligation को इस तरह सेट करें कि data directory आपके files के आकार से कई गुना बड़ी न हो जाए। एक swap file जोड़ें। Swap धीमा होता है, और upgrade के दौरान OOM kill होना उससे भी बुरा है।
SQLite क्यों विफल होता है
Nextcloud में SQLite का सपोर्ट मिलता है और official image इसका उपयोग कर सकती है। ऐसा न करें। SQLite पूरे database के लिए एक lock का उपयोग करता है: एक समय में केवल एक ही writer पूरे file पर काम कर सकता है। Nextcloud लगातार writes करता है — जैसे file locks, activity rows, cache entries, और job state — और एक single desktop client directory tree को sync करते समय कई parallel requests भेजता है। इस pattern के कारण आपको SQLSTATE[HY000]: General error: 5 database is locked और HTTP 500 errors मिलते हैं, और यह failure तब आता है जब instance उपयोगी होना शुरू होता है।
बाद में occ db:convert-type के साथ conversion संभव है, लेकिन live dataset पर यह एक लंबी और जटिल migration प्रक्रिया है। Postgres या MariaDB से शुरुआत करें।
The Compose file
Put this in /srv/nextcloud/compose.yaml, with secrets in a sibling .env file at mode 600.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- db:/var/lib/postgresql/data
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
app:
image: nextcloud:31-apache
restart: unless-stopped
depends_on: [db, redis]
ports:
- "127.0.0.1:8080:80"
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com
TRUSTED_PROXIES: 172.16.0.0/12
OVERWRITEPROTOCOL: https
OVERWRITECLIURL: https://cloud.example.com
APACHE_DISABLE_REWRITE_IP: "1"
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 10G
cron:
image: nextcloud:31-apache
restart: unless-stopped
entrypoint: /cron.sh
depends_on: [db, redis]
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
volumes:
db:
html:Pin the major tag and check the current one on Docker Hub before you copy 31 verbatim. latest will roll you across a major boundary on some future docker compose pull, and Nextcloud does not support that.
The data directory is a bind mount, not a named volume, on purpose: a path you can point a backup tool at directly is worth more than tidiness. Create it with the image's www-data UID and the permissions Nextcloud demands:
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sudo chmod 0770 /srv/nextcloud/dataNote the port publish: 127.0.0.1:8080:80. Docker publishes ports by writing DNAT rules that are evaluated before ufw's INPUT chain ever sees the packet — a bare 8080:80 puts an unencrypted Nextcloud on the public internet no matter what ufw says. Binding to loopback keeps it off the public interface. Then the firewall only has to allow the proxy — and if you would rather not leave SSH open to the whole internet, reaching the VPS over a self-hosted WireGuard VPN lets you drop port 22 from the public rules entirely:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableBring it up with docker compose up -d, then watch docker compose logs -f app. First boot copies the whole application tree into the volume and runs the installer; the container answers nothing until that finishes.
TLS और reverse proxy
Distro से nginx और certbot install करें। सही server_name के साथ एक plain port-80 server block बनाएँ, फिर certbot को इसे rewrite करने दें। HTTP-01 challenge की mechanics, renewal timer और failure modes का पूरा विवरण issuing Let's Encrypt certificates with certbot and nginx on Ubuntu 24.04 में दिया गया है:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.comCertbot ssl_certificate lines और :80 → :443 redirect जोड़ता है। यह 90-day certificate को renew करने के लिए एक systemd timer install करता है। systemctl list-timers | grep certbot से इसकी पुष्टि करें — यदि renewal timer enable नहीं है, तो certificate 90 दिनों में expire हो जाएगा।
Proxy block:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name cloud.example.com;
# certbot manages ssl_certificate / ssl_certificate_key here
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
client_max_body_size 10G;
client_body_timeout 300s;
location = /.well-known/carddav { return 301 /remote.php/dav; }
location = /.well-known/caldav { return 301 /remote.php/dav; }
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}nginx 1.25 और उसके बाद के versions में, http2 on; जोड़ें। Ubuntu 24.04 में पुराना build है जहाँ equivalent listen 443 ssl http2; है। nginx -t आपको बताएगा कि आपका build किसे accept करता है।
client_max_body_size और long read timeouts बड़े uploads को बीच में fail होने से रोकते हैं। proxy_request_buffering off पूरी file को proxy के disk पर spool करने के बजाय upload को stream करता है।
Host पर nginx एक single app के लिए सबसे सरल समाधान है। यदि Nextcloud को VPS पर अन्य containers के साथ share करना है, तो running Traefik as a Docker Compose reverse proxy for multiple apps routing और certificate issuance को container labels में स्थानांतरित कर देता है। वहाँ भी client_max_body_size और timeout से जुड़ी समस्याएँ middleware और transport settings के रूप में आती हैं।
trusted_proxies और overwriteprotocol
अधिकांश self-hosted Nextcloud instances में यहीं समस्या आती है, और इसके लक्षण कारण से अलग दिखाई देते हैं।
X-Forwarded-Proto: https केवल तभी मान्य होता है जब request trusted_proxies में सूचीबद्ध address से आती है। जब यह मान्य नहीं होता, तो Nextcloud को लगता है कि request plain HTTP है और वह http:// URLs भेजता है; proxy उन्हें HTTPS पर redirect करता है; browser उसका पालन करता है; Nextcloud फिर से http:// भेजता है। यही redirect loop है। OVERWRITEPROTOCOL: https scheme को स्थिर रखता है।
TRUSTED_PROXIES में समस्या यह है कि Nextcloud को दिखने वाला address 127.0.0.1 नहीं है। nginx host पर चलता है और एक published port से connect करता है, इसलिए container को Docker bridge gateway दिखाई देता है — जो 172.x में होता है। वास्तविक subnet का पता लगाएँ:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'उस CIDR (या covering 172.16.0.0/12) को TRUSTED_PROXIES में डालें। यदि इसे बहुत विस्तृत (wide) सेट किया गया, तो कोई भी client X-Forwarded-For को spoof कर सकता है; यदि इसे गलत सेट किया गया, तो हर login gateway address से आता हुआ दिखाई देगा, brute-force protection आपके पूरे instance को एक साथ block कर देगा, और admin overview में "The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy." दिखाई देगा।
cron container के लिए OVERWRITECLIURL महत्वपूर्ण है, क्योंकि उसके पास hostname का अनुमान लगाने के लिए कोई incoming request नहीं होती है। इसके बिना, background jobs localhost के links बनाते हैं और email notifications में unusable URLs भेजे जाते हैं।
Background jobs: cron, AJAX नहीं
Nextcloud का default job runner AJAX है: jobs तब execute होते हैं जब कोई page load करता है। 04:00 बजे कोई browsing नहीं करता, इसलिए trash expiry, versions cleanup, previews और federated retries रुक जाते हैं। इसका पहला लक्षण यह है कि data directory लगातार बढ़ती रहती है। ऊपर दिया गया cron service उन्हीं volumes पर official /cron.sh loop चलाता है। Nextcloud को इसके लिए तैयार रहने के लिए यह command दें:
docker compose exec -u www-data app php occ background:cronहर occ command इस format में होता है: docker compose exec -u www-data app php occ <command>। इसे alias बनाना बेहतर है।
Backups: तीन चीजें, या कुछ भी नहीं
केवल filesystem का backup लेने से broken instance में restore नहीं होगा। data directory में bytes होते हैं; Postgres में file cache, shares, users, और app state होता है; config.php में database credentials, instance ID, और password salt होता है। यदि आप database के बिना files restore करते हैं, तो Nextcloud उन्हें नहीं देख पाएगा। यदि आप config.php के बिना database restore करते हैं, तो वह database को open नहीं कर पाएगा। यदि आप पुराने database को नए data directory के साथ restore करते हैं, तो shares उन files को point करेंगे जो अब अपनी जगह पर नहीं हैं।
एक quiesced instance से इन तीनों का backup लें:
#!/usr/bin/env bash
set -euo pipefail
cd /srv/nextcloud
DEST="/var/backups/nextcloud/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$DEST"
occ() { docker compose exec -T -u www-data app php occ "$@"; }
occ maintenance:mode --on
trap 'occ maintenance:mode --off' EXIT
docker compose exec -T db \
pg_dump -U nextcloud --clean --if-exists nextcloud | gzip > "$DEST/db.sql.gz"
docker compose exec -T app \
tar -C /var/www/html -cf - config custom_apps themes > "$DEST/app.tar"
rsync -a --delete /srv/nextcloud/data/ /var/backups/nextcloud/data/Maintenance mode यह सुनिश्चित करता है कि dump और file copy एक-दूसरे के साथ sync में रहें। यदि आप इसे skip करते हैं, तो अंततः आपके पास ऐसा database होगा जो ऐसी file को reference करेगा जिसे rsync ने अभी तक copy नहीं किया है। ध्यान दें कि script timestamped database dumps रखती है, लेकिन data directory का केवल एक ही rolling mirror रखती है — rsync --delete हर run पर इसे overwrite कर देता है — इसलिए केवल नवीनतम dump ही file copy के साथ मेल खाएगा।
इसके बाद backup को server से बाहर निकालें। यदि backup उसी VPS पर है जिसे वह back up कर रहा है, तो वह केवल एक copy है, backup नहीं। Object storage या दूसरे host पर restic करना सबसे अच्छा तरीका है; इसका deduplication, nightly tarball की तुलना में data directory को बेहतर तरीके से handle करता है। Repository init से लेकर nightly timer और restore drill तक का पूरा setup, off-box VPS backups with restic में दिया गया है।
Restore करना केवल प्रक्रिया को उल्टा करना नहीं है। एक नया stack installer चलाता है और एक नया config.php — एक नया instance ID और password salt — लिखता है। उस नई identity पर dump import करने से broken sessions और share tokens मिलते हैं। पहले पुरानी identity को इस क्रम में वापस लाएं:
docker compose up -d && docker compose stop app cron # create the volumes, then halt the app
sudo rsync -a --delete /var/backups/nextcloud/data/ /srv/nextcloud/data/
docker compose run --rm -T --entrypoint "" app \
tar -C /var/www/html -xf - < app.tar # the original config.php returns
gunzip -c db.sql.gz | docker compose exec -T db psql -U nextcloud -d nextcloud
docker compose start app cron
docker compose exec -T -u www-data app php occ maintenance:mode --off
docker compose exec -T -u www-data app php occ files:scan --allfiles:scan file cache को disk पर मौजूद वास्तविक files के साथ reconcile करता है। इसकी आवश्यकता पड़ने से पहले, एक spare VPS पर इसका अभ्यास एक बार अवश्य करें।
Upgrades: एक बार में केवल एक major version
Nextcloud एक बार में केवल एक major version upgrade का समर्थन करता है। 29 से 31 पर सीधे जाना सही ढंग से काम नहीं करता है — यह Exception: Updates between multiple major versions and downgrades are unsupported. के साथ fail हो जाता है और आपको maintenance mode में छोड़ देता है।
Docker upgrade की प्रक्रिया यह है: backup लें, app और cron दोनों services में tag को 31 से बदलकर 32 करें, फिर docker compose pull && docker compose up -d करें, और फिर docker compose logs -f app करें। Image entrypoint मौजूदा data के विरुद्ध नए code का पता लगाता है और स्वयं occ upgrade चलाता है। इसे बीच में न रोकें। जब logs शांत हो जाएं, तो docker compose exec -u www-data app php occ status चलाएं और versionstring तथा apps के enabled होने की जांच करें।
दो नियम जो आपकी मदद करेंगे: पहले एक major version बढ़ाएं, verify करें, फिर अगला बढ़ाएं। और cron को app के समान बनाए बिना कभी भी app service का tag edit न करें — एक ही database के विरुद्ध दो अलग-अलग Nextcloud versions डेटा corruption का कारण बन सकते हैं।
आपको वास्तव में दिखने वाली त्रुटियाँ
"Your data directory is readable by other users. Please change the permissions to 0770." Bind-mounted directory में group या world read bits सेट हैं। sudo chmod 0770 /srv/nextcloud/data और sudo chown -R 33:33 /srv/nextcloud/data।
"Your data directory is invalid. Ensure there is a file called .ocdata in the root." Bind mount उस स्थान पर पॉइंट कर रहा है जिसे Nextcloud ने कभी initialize नहीं किया — path में typo है, या working instance की जगह एक नया खाली directory डाल दिया गया है। Check करें कि host path, volume line से मेल खाता है या नहीं।
"Access through untrusted domain." Request में दिया गया hostname trusted_domains में नहीं है। NEXTCLOUD_TRUSTED_DOMAINS केवल पहली बार install करते समय लागू होता है; उसके बाद इसे live set करें: occ config:system:set trusted_domains 1 --value=cloud.example.com।
502 Bad Gateway, जिसमें /var/log/nginx/error.log में connect() failed (111: Connection refused) while connecting to upstream है। nginx, 127.0.0.1:8080 पर किसी से नहीं जुड़ पाया। या तो container अभी initialize हो रहा है (docker compose logs app चेक करें), या वह exit हो गया है (docker compose ps), या publish line, proxy_pass port से मेल नहीं खाती। ss -ltnp | grep 8080 से इसकी पुष्टि करें।
A redirect loop, या admin overview में "insecure" warnings। OVERWRITEPROTOCOL: https गायब है, या TRUSTED_PROXIES में Docker gateway subnet शामिल नहीं है। ऊपर दिया गया proxy section देखें।
LockedException: "files/..." is locked। यदि REDIS_HOST सेट है, तो image Redis को locking backend के रूप में configure करती है और stale locks की समस्या कम होती है। इसके बिना, locks, database table oc_file_locks में रहते हैं और write के बीच में बाधित हुआ request rows छोड़ देता है। मैन्युअल रूप से lock rows clear करने से पहले, यह पुष्टि करें कि Redis वास्तव में उपयोग में है — occ config:system:get memcache.locking को Redis class return करना चाहिए।
"The PHP memory limit is below the recommended value of 512MB." PHP_MEMORY_LIMIT बढ़ाएं और container को फिर से बनाएँ। याद रखें कि इससे आपकी maximum ceiling पर क्या प्रभाव पड़ता है।
Scale पर क्या समस्याएँ आती हैं
पहली समस्या तब आती है जब data directory volume से बड़ी हो जाती है। VPS पर volume को बढ़ाना resize और filesystem grow करने जैसा है। जब disk 100% full हो जाए, तब इसे संभालना कठिन होता है — इसलिए disk usage पर अभी alert सेट करें, बाद में नहीं।
दूसरी समस्या oc_filecache है। Row count बढ़ने पर file listings और sync scans धीमे हो जाते हैं। इसका समाधान database management में है: Postgres को fast storage पर रखें, उसे पर्याप्त shared memory दें, और retention settings का उपयोग करके पुराने data और versions को prune करें ताकि वे जमा न हों।
तीसरी समस्या preview generation है जो अन्य सभी processes के साथ compete करती है। छोटे server पर, preview providers को सीमित रखें और working hours के दौरान कभी भी occ preview:generate-all न चलाएं।
इसके अलावा, सही उत्तर यह है कि extra services के लिए अलग machine होनी चाहिए। Collabora और full-text search अलग resident services हैं जिनके अपने memory profiles होते हैं। उन्हें उसी box पर चलाने से जहाँ आपकी files का एकमात्र copy मौजूद है, failure domain बढ़ जाता है और कोई लाभ नहीं होता। जब volume पर्याप्त न रहे, तो file storage को S3-compatible primary storage पर move कर दें — ध्यान रखें कि इससे backups कठिन हो जाते हैं, आसान नहीं: metadata अभी भी database में रहता है, और इसे bucket के साथ ही dump करना होगा।
जब instance वास्तविक users को serve करने लगे, तो इसके आगे Uptime Kuma लगाएं ताकि sync clients से पहले आपको downtime का पता चल सके। Private cloud your own mail server के साथ अच्छा काम करता है, और यदि आप services को मैन्युअल रूप से connect नहीं करना चाहते, तो Cloudron, CasaOS and Coolify उन platforms की तुलना करते हैं जो यह आपके लिए करते हैं।
FAQ
क्या मैं Postgres के बजाय SQLite पर Nextcloud चला सकता हूँ?
आप चला सकते हैं, और official image इसकी अनुमति देगी, लेकिन यदि एक single desktop sync client parallel requests भेजता है, तो SQLSTATE[HY000]: General error: 5 database is locked और HTTP 500 errors आएंगे। SQLite पूरे database पर write lock लगा देता है, जबकि Nextcloud लगातार writes करता है — जैसे file locks, activity rows, और job state। Postgres या MariaDB से शुरुआत करें; occ db:convert-type उपलब्ध है, लेकिन live data के लिए यह एक लंबी और कठिन migration प्रक्रिया है।
Nextcloud VPS को वास्तव में कितने RAM की आवश्यकता होती है?
यह user count के बजाय concurrency (एक साथ होने वाले कार्यों) पर निर्भर करता है। Worst-case resident memory लगभग concurrent requests की संख्या को PHP_MEMORY_LIMIT से गुणा करने पर प्राप्त होती है, साथ ही Postgres shared buffers, प्रत्येक connection के लिए एक backend, और preview generation के दौरान होने वाले spikes को भी जोड़ें। यदि आप previews को limit करते हैं और swap जोड़ते हैं, तो 2 GB का box एक छोटे household instance के लिए पर्याप्त है; यदि आप Collabora या full-text search जोड़ते हैं, तो आपको resident services का एक दूसरा set भी ध्यान में रखना होगा।
nginx reverse proxy के पीछे बड़े uploads क्यों fail हो जाते हैं?
इसके लिए proxy की दो settings जिम्मेदार होती हैं: यदि client_max_body_size default 1 MB पर है, तो request बीच में ही कट जाएगी, और छोटे proxy_read_timeout / proxy_send_timeout values लंबे transfers को बीच में ही रोक देते हैं। दोनों को पर्याप्त मात्रा में set करें, proxy_request_buffering off को spool के बजाय stream पर सेट करें, और app container पर PHP_UPLOAD_LIMIT को भी उसी के अनुसार बढ़ाएं।
Nextcloud redirect loop में क्यों फंस जाता है या reverse proxy के बारे में चेतावनी क्यों देता है?
Container को 127.0.0.1 पर nginx दिखाई नहीं देता — उसे 172.x के बीच में स्थित Docker bridge gateway दिखाई देता है। जब वह address TRUSTED_PROXIES में मौजूद नहीं होता, तो X-Forwarded-Proto: https header को ignore कर दिया जाता है, Nextcloud http:// URLs जनरेट करता है, और proxy उन्हें वापस redirect कर देता है। TRUSTED_PROXIES को real bridge subnet पर set करें और OVERWRITEPROTOCOL: https को pin करें।
क्या मैं Nextcloud को 29 से सीधे 31 पर upgrade कर सकता हूँ?
नहीं। Nextcloud प्रत्येक upgrade में केवल एक major version का समर्थन करता है। version skip करने पर Updates between multiple major versions and downgrades are unsupported. पर प्रक्रिया रुक जाएगी, जिससे instance maintenance mode में चला जाएगा। Backup लें, app और cron services दोनों पर tag को एक major version बढ़ाएं, docker compose pull && docker compose up -d करें, occ status के साथ verify करें, और फिर यही प्रक्रिया दोहराएं।