1. What is the issue? Please be detailed.
I'm self hosting ODK Central on a DigitalOcean Droplet and in the last week or so, ODK Central has gone offline twice. When I say "has gone offline" I mean I cannot access ODK Central to login via a web browser with an error "This site can’t be reached" and ODK Collect doesn't seem to have any successful communication with Central.
2. What steps can we take to reproduce this issue?
Not sure...
3. What have you tried to fix the issue?
When this happened a few days ago, I did a hard reset on my droplet and after a few minutes ODK Central was back up, no problems. Now, a few days later, ODK Central has gone offline again. Note, I have NEVER had this issue before and there haven't been any active submissions/admin activity/etc. in the last several days until noticing this issue.
In ODK Collect if I try to submit a survey, sending fails, pressing the refresh icon in the "Start New Form" Screen has a ! inside the refresh button and a "Form Update Failed" Notification pushes.
I've logged into DigitalOcean to verify the machine is running as I can see Activity in CPU %, Memory %, Bandwidth, etc. I can ping the server IP from my machine successfully AND successfully ping the exact website URL I'd put in a web browser. These two things lead me to believe this is an ODK Central Issue, not a Digital Ocean issue.
From Digital Oceans Web Console I opened the linux command line and ran:
docker compose stop && docker compose up -d and while that completed successfully, that didn't fix my problem.
htop and there were a couple alternating processes that were showing activity seen in the screen shots below:
I'd like to find the underlying problem here ASAP instead of just power cycling to put a bandaid on what might be a bigger issue.
4. Upload any forms or screenshots you can share publicly below.
I'm sorry you are having these issues! Could you add a few more details:
What ODK Central version are you running? How long since your last update?
How much free space is left on your machine (df -h)?
Where is your domain hosted - on Digital Ocean or on an external provider (e.g. Cloudflare)?
You might try using a combination of traceroute and curl to make sure you are actually reaching your server.
To further narrow down if it is ODK or a machine issue, you could see if you can access something else over the web on your server that is not ODK. The quickest way I can think of is using a one-line python script to serve a directory on your machine, such as python -m http.server --directory YOUR_DIRECTORY_NAME.
After about 20min with AI this is what I arrived at:
So the problem is not ODK Central, Sentry, or DigitalOcean DNS. The Snap-packaged Docker daemon is being prevented by AppArmor from sending the DNS packets that containers need.
That also explains everything we've observed:
Host → DNS works
Host → Sentry HTTPS works
Host → Docker Hub HTTPS works
Container → DNS blocked by AppArmor
↓
Docker embedded DNS cannot resolve names
↓
NGINX cannot resolve Sentry
↓
NGINX exits
↓
central-nginx-1 restarts forever
↓
port 443 unavailable
I would NOT disable AppArmor globally
And I would not start randomly changing firewall rules now. We have very specific evidence identifying the blocker.
The clean long-term solution is likely to move Docker from the Snap package to Docker's normal Debian/Ubuntu package. But because this is your production ODK Central installation, I would not uninstall Snap Docker yet.
The one thing AI had me change was nano /var/snap/docker/3613/config/daemon.json
replacing the x's with real IP addresses, but it looks like NGINX is still in a restart loop.
AI referenced this article but not sure how relevant it is:
Has anyone else had issues with docker? I have version 29.8.0. What concerns me is this issue occurred without me doing any sort of updates, at least to my knowledge. The first instance of the server being down occurred Wed, Sep 23, 2026.
Looks like a looping with NGINX caused by an issue with how Docker was installed (Docker Snap) and AI kept suggesting an issue with AppArmor. I reverted docker back to an older version, but that still didn't solve the issue.
Since it was taking so long to find a solution and I found out that my machine was running Ubuntu 25 when I thought it was running Ubuntu 24 LTS, I just ended up creating a new droplet using Ubuntu 26 LTS and migrating my ODK Central install to the new droplet and now ODK Central runs fine without any issues.
That's probably unhelpful for anyone else who might run into this issue, but I've found sometimes the best solution isn't continuing to dig deeper when you hit rock, but find a new place to dig.
Full Log Here
root@Ubuntu-24LTS:~/central# docker logs --tail 100 central-service-1
at /usr/odk/lib/task/task.js:62:48
at /usr/odk/node_modules/@sentry/opentelemetry/build/cjs/resource-CTgtEOmw.js:604:15
at Module.handleCallbackErrors (/usr/odk/node_modules/@sentry/core/build/cjs/utils/handleCallbackErrors.js:11:26)
at /usr/odk/node_modules/@sentry/opentelemetry/build/cjs/resource-CTgtEOmw.js:603:19
at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:63:14)
at SentryAsyncLocalStorageContextManager.with (/usr/odk/node_modules/@sentry/opentelemetry/build/cjs/index.js:27:36)
at ContextAPI.with (/usr/odk/node_modules/@opentelemetry/api/build/src/api/context.js:51:46)
at Tracer.startActiveSpan (/usr/odk/node_modules/@opentelemetry/sdk-trace-base/build/src/Tracer.js:138:32)
at /usr/odk/node_modules/@sentry/opentelemetry/build/cjs/resource-CTgtEOmw.js:601:19
at /usr/odk/node_modules/@sentry/opentelemetry/build/cjs/resource-CTgtEOmw.js:740:21
at _startSpan (/usr/odk/node_modules/@sentry/opentelemetry/build/cjs/resource-CTgtEOmw.js:574:10)
at Object.startSpan (/usr/odk/node_modules/@sentry/opentelemetry/build/cjs/resource-CTgtEOmw.js:616:10)
at Module.startSpan (/usr/odk/node_modules/@sentry/core/build/cjs/tracing/trace.js:32:16)
at Command. (/usr/odk/lib/task/task.js:58:19)
generating local service configuration..
waiting for PostgreSQL to become connectable to...
running migrations..
logging server upgrade..
null
starting cron..
using 4 worker(s) based on available memory (2062970880)..
starting server.
2026-10-02T05:07:23: PM2 log: Launching in no daemon mode
2026-10-02T05:07:23: PM2 error: (node:57) [DEP0176] DeprecationWarning: fs.R_OK is deprecated, use fs.constants.R_OK instead
(Use node --trace-deprecation ... to show where the warning was created)
2026-10-02T05:07:23: PM2 log: App [service:0] starting in -cluster mode-
2026-10-02T05:07:23: PM2 log: App [service:0] online
2026-10-02T05:07:23: PM2 log: App [service:1] starting in -cluster mode-
2026-10-02T05:07:23: PM2 log: App [service:1] online
2026-10-02T05:07:23: PM2 log: App [service:2] starting in -cluster mode-
2026-10-02T05:07:24: PM2 log: App [service:2] online
2026-10-02T05:07:24: PM2 log: App [service:3] starting in -cluster mode-
2026-10-02T05:07:25: PM2 log: App [service:3] online
npm error path /usr/odk
npm error command failed
npm error signal SIGTERM
npm error command sh -c "pm2-runtime" ./pm2.config.js
npm error A complete log of this run can be found in: /root/.npm/_logs/2026-10-02T05_07_18_939Z-debug-0.log
generating local service configuration..
waiting for PostgreSQL to become connectable to...
running migrations..
logging server upgrade..
null
starting cron..
using 4 worker(s) based on available memory (2062970880)..
starting server.
2026-10-02T14:08:14: PM2 log: Launching in no daemon mode
2026-10-02T14:08:14: PM2 error: (node:57) [DEP0176] DeprecationWarning: fs.R_OK is deprecated, use fs.constants.R_OK instead
(Use node --trace-deprecation ... to show where the warning was created)
2026-10-02T14:08:14: PM2 log: App [service:0] starting in -cluster mode-
2026-10-02T14:08:14: PM2 log: App [service:0] online
2026-10-02T14:08:15: PM2 log: App [service:1] starting in -cluster mode-
2026-10-02T14:08:15: PM2 log: App [service:1] online
2026-10-02T14:08:15: PM2 log: App [service:2] starting in -cluster mode-
2026-10-02T14:08:15: PM2 log: App [service:2] online
2026-10-02T14:08:15: PM2 log: App [service:3] starting in -cluster mode-
2026-10-02T14:08:16: PM2 log: App [service:3] online
npm error path /usr/odk
npm error command failed
npm error signal SIGTERM
npm error command sh -c "pm2-runtime" ./pm2.config.js
npm error A complete log of this run can be found in: /root/.npm/_logs/2026-10-02T14_08_11_376Z-debug-0.log
generating local service configuration..
waiting for PostgreSQL to become connectable to...
running migrations..
logging server upgrade..
null
starting cron..
using 4 worker(s) based on available memory (2062970880)..
starting server.
2026-10-02T14:32:22: PM2 log: Launching in no daemon mode
2026-10-02T14:32:22: PM2 error: (node:57) [DEP0176] DeprecationWarning: fs.R_OK is deprecated, use fs.constants.R_OK instead
(Use node --trace-deprecation ... to show where the warning was created)
2026-10-02T14:32:22: PM2 log: App [service:0] starting in -cluster mode-
2026-10-02T14:32:23: PM2 log: App [service:0] online
2026-10-02T14:32:23: PM2 log: App [service:1] starting in -cluster mode-
2026-10-02T14:32:23: PM2 log: App [service:1] online
2026-10-02T14:32:23: PM2 log: App [service:2] starting in -cluster mode-
2026-10-02T14:32:23: PM2 log: App [service:2] online
2026-10-02T14:32:24: PM2 log: App [service:3] starting in -cluster mode-
2026-10-02T14:32:24: PM2 log: App [service:3] online
generating local service configuration..
waiting for PostgreSQL to become connectable to...
running migrations..
logging server upgrade..
null
starting cron..
using 4 worker(s) based on available memory (2062970880)..
starting server.
2026-10-02T18:21:56: PM2 log: Launching in no daemon mode
2026-10-02T18:21:56: PM2 error: (node:57) [DEP0176] DeprecationWarning: fs.R_OK is deprecated, use fs.constants.R_OK instead
(Use node --trace-deprecation ... to show where the warning was created)
2026-10-02T18:21:56: PM2 log: App [service:0] starting in -cluster mode-
2026-10-02T18:21:56: PM2 log: App [service:0] online
2026-10-02T18:21:56: PM2 log: App [service:1] starting in -cluster mode-
2026-10-02T18:21:57: PM2 log: App [service:1] online
2026-10-02T18:21:57: PM2 log: App [service:2] starting in -cluster mode-
2026-10-02T18:21:58: PM2 log: App [service:2] online
2026-10-02T18:21:58: PM2 log: App [service:3] starting in -cluster mode-
2026-10-02T18:22:00: PM2 log: App [service:3] online
root@Ubuntu-24LTS:~/central#
More AI troubleshooting led to:
Summary
This is now very clear. We have confirmed the root cause.
The Docker daemon is running under the AppArmor profile: