Run a server
Storage, backups & limits
Every Oleafly Server setting, storing files on disk or in an S3 bucket, running behind a proxy, limits for classes on one network, logs, backups, restores and updates.
이 콘텐츠는 아직 번역되지 않았습니다.
This page covers running Oleafly Server day to day. To install it, start with Run a collaboration server.
Settings
Section titled “Settings”The server reads its settings from environment variables. A variable that is set but empty counts as not set. If a setting is missing or malformed, the server doesn’t start, and its log says which one.
| Variable | What it does | Default |
|---|---|---|
OLEAFLY_PUBLIC_URL | The HTTPS address people enter in Oleafly. It can include a path, such as https://www.cs.example.edu/oleafly. Required. The Compose and Coolify files set it for you. | None |
OLEAFLY_BIND | The address and port the server listens on. | 0.0.0.0:8080 |
OLEAFLY_DATA_DIR | The folder for the database and stored files. | /data |
OLEAFLY_SERVER_NAME | The name people see in Oleafly, such as Smith Lab. | Oleafly Server |
OLEAFLY_SERVER_ICON_URL | The HTTPS address of a square image shown next to the name. | None |
OLEAFLY_SETUP_CODE | Your own one-time setup code: at least 12 letters or digits, with dashes or spaces if you like. Without it, the server makes one. | Generated |
OLEAFLY_GITHUB_CLIENT_ID, OLEAFLY_GITHUB_CLIENT_SECRET | Turn on sign-in with GitHub. | Off |
OLEAFLY_GITHUB_URL | The address of a GitHub Enterprise Server. | https://github.com |
OLEAFLY_GITHUB_API_URL | The GitHub API address, if yours is unusual. | https://api.github.com, or /api/v3 under OLEAFLY_GITHUB_URL |
OLEAFLY_GITHUB_LABEL | The text on the GitHub sign-in button. | GitHub |
OLEAFLY_OIDC_<NAME>_ISSUER, OLEAFLY_OIDC_<NAME>_CLIENT_ID, OLEAFLY_OIDC_<NAME>_CLIENT_SECRET | Turn on an OpenID Connect provider called <NAME>. | Off |
OLEAFLY_OIDC_<NAME>_LABEL | The text on its sign-in button, such as University login. | <NAME> |
OLEAFLY_OIDC_<NAME>_TRUST_EMAIL | Treat every email address from this provider as verified. Read Verified email addresses first. | false |
OLEAFLY_SMTP_URL, OLEAFLY_MAIL_FROM | Email. Read Email. | Off |
OLEAFLY_BLOB_STORE | Where files such as figures and PDFs are stored. fs keeps them in OLEAFLY_DATA_DIR. An address such as s3://lab-bucket or s3://lab-bucket/oleafly keeps them in a bucket. | fs |
OLEAFLY_S3_ENDPOINT | The address of an S3-compatible store other than Amazon S3, such as MinIO or Cloudflare R2. Leave it empty for Amazon S3. | Amazon S3 |
OLEAFLY_S3_REGION | The bucket’s region. | us-east-1 |
OLEAFLY_S3_ACCESS_KEY_ID, OLEAFLY_S3_SECRET_ACCESS_KEY | The key the server uses for the bucket. Required with an s3:// address. | None |
OLEAFLY_MAX_PROJECT_MB | The largest project the server accepts, in megabytes. | 200 |
OLEAFLY_MAX_FILE_MB | The largest single file, in megabytes. | 50 |
OLEAFLY_MAX_MEMBERS_PER_PROJECT | The most people on one project. | 20 |
OLEAFLY_SIGN_IN_BURST | How many sign-in requests one network address can make in a burst. A sign-in takes about six, so the default covers 50 people at one address signing in at once. | 300 |
OLEAFLY_SIGN_IN_PER_MINUTE | How many sign-in requests one network address gets back each minute after the burst. | 120 |
OLEAFLY_EMAIL_LINKS_PER_IP | How many sign-in emails the server sends to people at one network address in 15 minutes. | 100 |
OLEAFLY_EMAIL_LINKS_PER_ADDRESS | How many sign-in emails one email address can get in 15 minutes. It can’t be more than OLEAFLY_EMAIL_LINKS_PER_IP. | 3 |
OLEAFLY_DEVICE_CODES_PER_IP | How many sign-in codes people at one network address can ask for in 10 minutes. | 100 |
OLEAFLY_SNAPSHOT_MEMORY_MB | How much memory, in megabytes, the server may use to build project snapshots. | Half the container’s memory limit, or 1024 without a limit |
OLEAFLY_BEHIND_PROXY | Take each person’s address from the X-Forwarded-For header your proxy adds. The Compose, Coolify and Render files turn it on. | false |
OLEAFLY_PROXY_HOPS | How many proxies every request passes through before it reaches the server. It needs OLEAFLY_BEHIND_PROXY=true. | 1 |
OLEAFLY_LOG_LEVEL | How much the server logs: error, warn, info, debug or trace. Libraries the server uses only log warnings unless you pick debug or trace. | info |
OLEAFLY_SECURITY_LOG_DAYS | How many days to keep security log entries, project access log entries and answered or expired guest invitations. | 365 |
OLEAFLY_ARCHIVE_DAYS | How many days to keep a project after its owner stops sharing it. | 30 |
OLEAFLY_POLL_HOLD_SECONDS | How long the server keeps a long-polling request open when no edits are waiting, from 1 to 40 seconds. Keep it a few seconds under the idle timeout of any proxy in front of the server. | 25 |
In the Compose .env file, put a value in single quotes if it contains $ or #. Settings that hold secrets can also be read from files. Read Keep secrets out of .env.
Storage
Section titled “Storage”By default the server keeps everything in OLEAFLY_DATA_DIR: the database, the files people share, and project snapshots. Snapshots are saved copies of each project that let people join and catch up quickly.
Files in a bucket
Section titled “Files in a bucket”The server can keep files and snapshots in Amazon S3 instead, or in another store with an S3-compatible API, such as MinIO or Cloudflare R2. The database stays in OLEAFLY_DATA_DIR either way, so the server still needs its data folder.
-
Create a bucket and block public access to it.
-
Create a key that can read, write and delete objects in that bucket and nothing else. On Amazon S3 that means
s3:GetObject,s3:PutObjectands3:DeleteObjectonarn:aws:s3:::lab-bucket/*, or onarn:aws:s3:::lab-bucket/oleafly/*if you use a folder. -
Set the variables, for example in
.env:Terminal window OLEAFLY_BLOB_STORE=s3://lab-bucket/oleaflyOLEAFLY_S3_REGION=eu-west-1OLEAFLY_S3_ACCESS_KEY_ID=your-access-key-idOLEAFLY_S3_SECRET_ACCESS_KEY=your-secret-access-key
For a store other than Amazon S3, also set OLEAFLY_S3_ENDPOINT to its address, such as https://minio.example.org:9000 or https://<account-id>.r2.cloudflarestorage.com, and set OLEAFLY_S3_REGION to the region it expects (auto for R2). Plain http:// works too, but use it only when the store sits on the same private network as the server.
The part after the bucket name is an optional folder. Each file is named after its SHA-256 hash and sits under the first two characters of that hash, so a file whose hash starts with 3f9a is stored as oleafly/3f/3f9a.... Snapshots have their own snapshots folder with a folder for each project. When the server reads a file or snapshot back, it checks the bytes against the hash and refuses one that doesn’t match. Without a bucket, the same layout is in the blobs folder inside OLEAFLY_DATA_DIR.
If the bucket refuses a request, that upload or download fails, and the server log shows what the bucket said, such as 403 Forbidden (AccessDenied). A server error, a timeout or a dropped connection is different: the server tries up to three times, with a short random pause in between. If it can’t delete an object, it notes that and tries again at each maintenance pass, every 6 hours, so an outage doesn’t leave objects behind.
Snapshots and memory
Section titled “Snapshots and memory”When a project is shared, the owner’s app uploads its first snapshot and signs it with that device’s key. From then on the server builds every snapshot itself, from the previous snapshot and the changes people sent since. A new snapshot is built once a project has 1,000 changes past the last one. The server always keeps at least the last 2,000 changes, so a device that was away for a short time catches up from those and doesn’t download the whole project again.
Building a snapshot needs about ten times the size of the previous snapshot plus the changes since it. The server only starts a build that fits in OLEAFLY_SNAPSHOT_MEMORY_MB, and builds running at the same time share that amount. If a build doesn’t fit, the server skips it, logs how much memory it needs and keeps all the project’s changes. Devices then catch up from those changes a few megabytes at a time. Raise the setting and the next snapshot gets built. The server won’t store a snapshot larger than OLEAFLY_MAX_PROJECT_MB.
Behind a reverse proxy
Section titled “Behind a reverse proxy”The server speaks plain HTTP, so something in front of it handles HTTPS: Caddy in the Compose setup, Coolify’s proxy, or a web server you already run, such as your university’s. Whatever sits in front has to:
- accept requests as large as
OLEAFLY_MAX_PROJECT_MB - add the client’s address to
X-Forwarded-For
It should also pass WebSocket upgrades through to /ws and keep those connections open for at least an hour. Live editing uses them when it can.
Run the server where only the proxy can reach it. On the same machine, set OLEAFLY_BIND=127.0.0.1:8080. Then set OLEAFLY_BEHIND_PROXY=true.
When WebSocket connections are blocked
Section titled “When WebSocket connections are blocked”Some networks block WebSocket connections, often a university or company network with a filtering proxy. Live editing still works there, more slowly. When two WebSocket attempts in a row fail while the server still answers over HTTPS, Oleafly switches to HTTP long-polling. It sends edits to /api/v1/projects/<project>/frames and waits for other people’s edits on /api/v1/projects/<project>/poll, holding each request open for up to OLEAFLY_POLL_HOLD_SECONDS. Every edit still arrives. Oleafly tries a WebSocket again every minute and goes back to it as soon as one connects.
Test connection in Oleafly and Connection checks in the admin console say when this happens: “Live edits take a slower route because this network blocks the usual one. They still arrive.”
If you run the proxy in front of the server, pass WebSocket upgrades through anyway. Long-polling works, but each batch of edits costs an extra request and a little more delay.
Some proxies close a request that stays quiet for less than 30 seconds, nginx with a short proxy_read_timeout for one. They answer long-polling requests with a 502 or 504 error, and edits arrive late. Set OLEAFLY_POLL_HOLD_SECONDS a few seconds under that timeout, such as 8 for a 10-second timeout.
What OLEAFLY_BEHIND_PROXY changes
Section titled “What OLEAFLY_BEHIND_PROXY changes”The server notes a client address in two places: the security log, and the limits on how often one address can start a sign-in or open a live connection.
Without the setting, the server uses the address of whatever connected to it. Behind a proxy that’s always the proxy, so everyone shares one limit and the security log shows only the proxy’s address.
With OLEAFLY_BEHIND_PROXY=true, the server reads the X-Forwarded-For header and uses the last address in it, which is the one your proxy added. If the header is missing or holds no valid address, the server falls back to the connecting address. Nothing else changes. The server ignores X-Forwarded-Proto, X-Forwarded-Host and Forwarded, and builds every address it hands out from OLEAFLY_PUBLIC_URL.
Turn it on only when every request comes through your proxy. If people can also reach the server directly, anyone can send a made-up X-Forwarded-For, put any address in the security log and get around the sign-in limit.
With two proxies in a row, for example Cloudflare in front of Coolify’s proxy, set OLEAFLY_PROXY_HOPS=2. The server then takes the second address from the end. Count only the proxies that every request goes through. A Cloudflare Tunnel that leads straight to the server counts as one.
To check the number, sign in from your own computer and open Security log in the admin console. The newest entry should show your public address, the one a site such as ifconfig.me reports. If it shows a private or Cloudflare address instead, raise OLEAFLY_PROXY_HOPS by one.
Caddy passes WebSocket connections and X-Forwarded-For through without extra settings, and gets the certificate itself. Put HTTPS in front has the whole Caddyfile.
Get a certificate for the domain first, for example with certbot. Then save this as /etc/nginx/conf.d/oleafly.conf and run sudo nginx -t && sudo systemctl reload nginx:
map $http_upgrade $connection_upgrade { default upgrade; '' close;}
server { listen 443 ssl; server_name collab.example.org; ssl_certificate /etc/letsencrypt/live/collab.example.org/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/collab.example.org/privkey.pem;
location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Forwarded-For $remote_addr; proxy_read_timeout 1h; proxy_send_timeout 1h; client_max_body_size 200m; }}client_max_body_size matches the default OLEAFLY_MAX_PROJECT_MB of 200. If you raise one, raise the other.
Apache
Section titled “Apache”You need Apache 2.4.47 or newer, which Debian 12 and Ubuntu 22.04 and later have. Turn on the modules:
sudo a2enmod proxy proxy_http sslSave this as /etc/apache2/sites-available/oleafly.conf, then run sudo a2ensite oleafly && sudo systemctl reload apache2:
<VirtualHost *:443> ServerName collab.example.org SSLEngine on SSLCertificateFile /etc/letsencrypt/live/collab.example.org/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/collab.example.org/privkey.pem
ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ upgrade=websocket timeout=3600 ProxyPassReverse / http://127.0.0.1:8080/</VirtualHost>upgrade=websocket passes WebSocket connections through and timeout=3600 keeps them open for an hour. Apache adds the client’s address to X-Forwarded-For by itself.
Under a path
Section titled “Under a path”If the server lives under a path, include the path in OLEAFLY_PUBLIC_URL, for example https://www.cs.example.edu/oleafly, and in the callback addresses you register with sign-in providers. The server answers both with and without that path, so your proxy can pass it on or strip it. With nginx, use location /oleafly/ { with the same lines inside, and keep proxy_pass http://127.0.0.1:8080; without a path so nginx passes the path on.
Limits for a class on one network
Section titled “Limits for a class on one network”A whole class often signs in from one network address, such as a university’s NAT. The defaults are set for that:
- Sign-ins: one address gets a burst of 300 sign-in requests, then two a second. A sign-in takes about six, so 50 people can sign in at once. Change these with
OLEAFLY_SIGN_IN_BURSTandOLEAFLY_SIGN_IN_PER_MINUTE. - Email links: 100 to one address in 15 minutes, and 3 to one email address. Change these with
OLEAFLY_EMAIL_LINKS_PER_IPandOLEAFLY_EMAIL_LINKS_PER_ADDRESS. - Sign-in codes: 100 codes, and 10 wrong codes, from one address in 10 minutes. Change this with
OLEAFLY_DEVICE_CODES_PER_IP. - Live connections have their own, larger limit, so a whole class behind one address can reconnect at once after a restart. Only connections that fail to prove their session use it up: a burst of 300, then ten a second. A connection that proves its session counts against its own device instead, which can reconnect 60 times in a burst, then once a second.
All IPv6 addresses in one /64 network count as one address. These limits only work per person when the server sees each person’s real address, so set up your proxy correctly.
The server pings each live connection every 30 seconds. It closes a connection that leaves those pings unanswered for 90 seconds, and one that stops reading what the server sends.
Project limits apply to everyone: OLEAFLY_MAX_PROJECT_MB for a whole project (200 MB by default), OLEAFLY_MAX_FILE_MB for one file (50 MB) and OLEAFLY_MAX_MEMBERS_PER_PROJECT for people on one project (20). The admin console’s Overview shows the current limits.
- The server log is what
docker compose logs oleafly-server, Coolify’s Logs orjournalctl -u oleafly-servershow.OLEAFLY_LOG_LEVELsets how much it says. - The security log records sign-ins and refused sign-ins, devices, people, roles, settings, projects and guests, each with the time and the IP address. Admins and maintainers read it under Security log in the admin console. Entries older than
OLEAFLY_SECURITY_LOG_DAYSdays are deleted. - Project access logs record who opened a project, joined it or downloaded a copy, with the device name and the time. A project’s owner turns one on, when Allow project access logs is on, and only that owner can read it. The same retention applies.
Backups
Section titled “Backups”What a full backup needs depends on where files are stored:
- Files on disk (
OLEAFLY_BLOB_STORE=fs, the default): the database, files and snapshots are all in the data folder. Back up the whole folder. - Files in a bucket: the data folder holds the database and the bucket holds files and snapshots. A copy of the database plus the bucket is a full backup. Turn on versioning for the bucket so an object deleted by mistake can be brought back.
Back up regularly and keep the copies private, since they hold every project. Your settings, such as .env, aren’t in the data folder, so keep a copy of them as well.
With Docker, the server stops for a few seconds while you copy the volume. Oleafly reconnects by itself. Run these commands in the server’s folder, /opt/oleafly-server if you used the installer.
cd /opt/oleafly-serversudo docker compose stop oleafly-serversudo docker run --rm -v oleafly-server_oleafly-data:/data:ro -v "$PWD":/backup debian:13.7-slim tar -C /data -czf /backup/oleafly-data-$(date +%F).tar.gz .sudo docker compose start oleafly-serverWith systemd:
sudo systemctl stop oleafly-serversudo tar -C /var/lib/private/oleafly-server -czf /root/oleafly-data-$(date +%F).tar.gz .sudo systemctl start oleafly-serverCopy the archive to another machine.
On Coolify, the volume’s name starts with the resource’s ID. Find it with docker volume ls --filter name=oleafly-data, use it in place of oleafly-server_oleafly-data, and stop and start the server from Coolify’s dashboard instead of with docker compose.
Restore drill
Section titled “Restore drill”A backup you’ve never restored is only a hope. This drill starts a second copy of the server from a backup, leaves the running one alone, and checks that both are the same server. Use the date of your own archive in place of 2026-10-11.
cd /opt/oleafly-serversudo docker volume create oleafly-restore-drillsudo docker run --rm -v oleafly-restore-drill:/data -v "$PWD":/backup:ro debian:13.7-slim tar -C /data -xzf /backup/oleafly-data-2026-10-11.tar.gzsudo docker run -d --name oleafly-restore-drill -v oleafly-restore-drill:/data -e OLEAFLY_PUBLIC_URL=https://restore-drill.invalid -e OLEAFLY_GITHUB_CLIENT_ID=restore-drill -e OLEAFLY_GITHUB_CLIENT_SECRET=restore-drill "$(sudo docker compose images -q oleafly-server)"sudo docker run --rm --network container:oleafly-restore-drill curlimages/curl:8.22.0 -fsS --retry 10 --retry-connrefused --retry-delay 1 http://127.0.0.1:8080/.well-known/oleafly-servercurl -fsS https://collab.example.org/.well-known/oleafly-serverThe server_id in the two answers must match. The drill copy has a placeholder GitHub sign-in that can’t sign anyone in, and no open port, so nobody can use it. Remove it when you’re done:
sudo docker rm -f oleafly-restore-drillsudo docker volume rm oleafly-restore-drillRestore
Section titled “Restore”To restore for real with Docker Compose, stop the server, replace the volume’s contents with the archive, and start it again:
cd /opt/oleafly-serversudo docker compose stop oleafly-serversudo docker run --rm -v oleafly-server_oleafly-data:/data -v "$PWD":/backup:ro debian:13.7-slim sh -c 'find /data -mindepth 1 -delete && tar -C /data -xzf /backup/oleafly-data-2026-10-11.tar.gz'sudo docker compose start oleafly-serverWith systemd:
sudo systemctl stop oleafly-serversudo find /var/lib/private/oleafly-server -mindepth 1 -deletesudo tar -C /var/lib/private/oleafly-server -xzf /root/oleafly-data-2026-10-11.tar.gzsudo systemctl start oleafly-serverA restored server is missing the changes people made after the backup. Each app notices when it reconnects, whether it stayed open or was opened later, and sends its own missing changes again. Nobody has to do anything for that. A change that builds on someone else’s missing change waits until that person opens the project, because only their app can send their changes. Ask everyone who was editing around the time of the failure to open the project once.
Continuous copies with Litestream
Section titled “Continuous copies with Litestream”An archive only holds what was there when you made it. Litestream (opens in a new tab) copies each change to the server’s database to an S3-compatible bucket about a second after it happens. The Compose file includes it as an optional service.
Litestream copies the database only. If files are in a bucket, the bucket already holds files and snapshots, so the Litestream copy and the bucket together can bring back a lost disk. If files are on disk, keep making archives of the volume as well, because Litestream doesn’t copy the blobs folder.
-
Create a bucket, or a folder in one, that only this server’s Litestream uses. Don’t share it with
OLEAFLY_BLOB_STORE. Give Litestream a key that can list the bucket and read, write and delete objects in it. -
Add the details to
.env:Terminal window LITESTREAM_REPLICA_URL=s3://lab-backups/oleafly-serverLITESTREAM_REGION=eu-west-1LITESTREAM_ACCESS_KEY_ID=your-access-key-idLITESTREAM_SECRET_ACCESS_KEY=your-secret-access-keyCOMPOSE_PROFILES=litestreamFor a store other than Amazon S3, also set
LITESTREAM_ENDPOINTto its address andLITESTREAM_REGIONto the region it expects (autofor R2).COMPOSE_PROFILESmakes everydocker composecommand include Litestream. -
Start it:
Terminal window sudo docker compose up -d -
Check that it copied the database. This prints a line with
snapshot complete:Terminal window sudo docker compose logs litestream | grep 'snapshot complete'
Litestream takes a full copy once a day and keeps a week of copies and the changes between them. The schedule is in litestream.yml.
Litestream restore drill
Section titled “Litestream restore drill”This drill restores the database from the bucket into a scratch volume, starts a second copy of the server on it, and checks that both are the same server. The running server isn’t touched.
cd /opt/oleafly-serversudo docker run --rm -v oleafly-litestream-drill:/data "$(sudo docker compose images -q oleafly-server)" --versionsudo docker compose run --rm --no-deps -v oleafly-litestream-drill:/restore litestream restore -config /etc/litestream.yml -o /restore/oleafly-server.sqlite3 /data/oleafly-server.sqlite3sudo docker run -d --name oleafly-litestream-drill -v oleafly-litestream-drill:/data -e OLEAFLY_PUBLIC_URL=https://restore-drill.invalid -e OLEAFLY_GITHUB_CLIENT_ID=restore-drill -e OLEAFLY_GITHUB_CLIENT_SECRET=restore-drill "$(sudo docker compose images -q oleafly-server)"sudo docker run --rm --network container:oleafly-litestream-drill curlimages/curl:8.22.0 -fsS --retry 10 --retry-connrefused --retry-delay 1 http://127.0.0.1:8080/.well-known/oleafly-servercurl -fsS https://collab.example.org/.well-known/oleafly-serverThe first command creates the scratch volume with the owner the server needs. The server_id in the last two answers must match. Remove the copy when you’re done:
sudo docker rm -f oleafly-litestream-drillsudo docker volume rm oleafly-litestream-drillRestore the database from Litestream
Section titled “Restore the database from Litestream”When the database file is damaged or gone but the rest of the data folder is fine, stop the server and Litestream, remove what’s left of the database, restore it and start again:
cd /opt/oleafly-serversudo docker compose stop oleafly-server litestreamsudo docker run --rm -v oleafly-server_oleafly-data:/data debian:13.7-slim rm -rf /data/oleafly-server.sqlite3 /data/oleafly-server.sqlite3-wal /data/oleafly-server.sqlite3-shm /data/.oleafly-server.sqlite3-litestreamsudo docker compose run --rm --no-deps litestream restore -config /etc/litestream.yml /data/oleafly-server.sqlite3sudo docker compose up -dAfter a lost disk with files in a bucket, run the commands above on the new, empty volume and keep the same bucket settings in .env. Every project comes back with its files and snapshots.
After a lost disk with files on disk, restore your newest archive and leave it at that. Don’t put a newer database from Litestream on top of an older archive. The database would point at files and snapshots the archive doesn’t have, and those projects wouldn’t open.
Updating
Section titled “Updating”Back up first. The server updates its database the first time a new release starts, so going back to an older release means restoring the backup you took before updating.
- One-command install: run
curl -fsSL https://oleafly.com/server/install.sh | sudo sh -s -- update. It keeps.env, gets the new release’s files and image, and restarts the server. - Docker Compose by hand: download the new release’s files into the server’s folder as in Docker Compose by hand, then run
sudo docker compose up -d. - Coolify: select Redeploy. With the published image, that pulls the newest release under the image’s tag.
- Render: open the service and start a manual deploy, which pulls the image again.
- Railway: deploy the service again from its menu. Railway can also update an image from GitHub’s registry by itself.
- systemd: install the new release as in Download the server, then run
sudo systemctl restart oleafly-server.
Oleafly checks the server’s version every time it connects. If the app and the server can’t work together, Oleafly says which one needs an update.