DEV Community

우병수
우병수

Posted on • Originally published at techdigestor.com

FileRun, OnlyOffice, and Pangolin for a Self-Hosted Web Calendar: Which One Actually Fits Your Stack

TL;DR: The setup sounds simple until you actually try to build it: a calendar you can open in a browser, sync to your phone over CalDAV, host on your own hardware, and never pay a per-seat bill for. That constraint eliminates almost every polished option immediately.

📖 Reading time: ~23 min

What's in this article

  1. The Problem: You Want a Web Calendar Without Renting Someone Else's Server
  2. The Constraint That Forces a Choice
  3. FileRun 2026: Calendar as a Bolt-On to a File Manager
  4. OnlyOffice: Calendar Inside a Document Collaboration Suite
  5. Pangolin: The Reverse-Proxy-Native Approach
  6. Side-by-Side: What You Actually Get Per Use Case
  7. Gotchas That Cost Time Across All Three

The Problem: You Want a Web Calendar Without Renting Someone Else's Server

The setup sounds simple until you actually try to build it: a calendar you can open in a browser, sync to your phone over CalDAV, host on your own hardware, and never pay a per-seat bill for. That constraint eliminates almost every polished option immediately. What's left is a pile of self-hosted tools that technically touch calendars but were mostly built to solve adjacent problems — and the documentation rarely admits that.

The usual suspects disappoint in predictable ways. Nextcloud does have a working CalDAV implementation and a decent browser UI, but you're pulling in a full PHP application stack, a mandatory database, and a sprawling plugin ecosystem just to get a calendar. On a small VPS or a home server with limited RAM, Nextcloud idles at several hundred megabytes before anyone logs in. Radicale is the opposite extreme — a tight Python CalDAV/CardDAV server that runs in about 20MB, has zero browser UI, and requires you to already know what a .ics file is to do anything with it. The guides that recommend Radicale almost always pair it with a third-party web frontend that's either abandoned or requires a separate Node or PHP runtime, which defeats the point. And most tutorials conflate file sync with calendar functionality entirely — they'll walk you through mounting a WebDAV share and call it done.

FileRun 2026, OnlyOffice, and Pangolin approach the problem from three genuinely different angles, which is why comparing them forces a real decision rather than a preference. FileRun is a file manager that added calendar and contacts through tight OnlyOffice integration — the calendar exists because OnlyOffice Documents ships with one, and FileRun wires up the auth. OnlyOffice as a standalone Document Server gives you the office suite and calendar surface, but calendar is not its primary job and the deployment complexity reflects that. Pangolin is a newer entrant that treats calendaring as a first-class feature alongside its reverse proxy and identity layer, which means the calendar ships with SSO baked in rather than bolted on. Each of those architectural choices has downstream consequences: what breaks when you upgrade, how CalDAV sync actually behaves with iOS and Android clients, and how much Docker Compose YAML you're maintaining on a Sunday afternoon.

The trade-off is real because none of these are drop-in. FileRun with OnlyOffice gives you the most polished browser experience but requires two cooperating containers plus a database, and the OnlyOffice Document Server alone wants at least 2GB of RAM allocated before it feels stable. Pangolin's calendar story is newer and the ecosystem is thinner, but the identity and routing layer it ships with is genuinely useful if you're running multiple self-hosted services behind the same domain. If you're already evaluating what tooling sits around your self-hosted stack — including AI-assisted development tools — the tradeoffs around local vs. cloud-hosted capability are worth thinking through in parallel; see our guide on AI Coding Tools in 2026: Cloud Copilots vs Local Models for how that decision tree plays out.

One thing that doesn't get said enough in self-hosting calendar guides: CalDAV compliance is not binary. A server can pass basic sync and still break iOS's birthday calendar sync, still corrupt recurring event exceptions on Android, or still refuse to serve free/busy data to a second client. The version of the CalDAV server underneath — whether that's the one bundled in OnlyOffice, FileRun's integration layer, or Pangolin's backend — determines which of those edge cases you'll hit. That's the part worth testing before you migrate anything important off Google Calendar or iCloud.

The Constraint That Forces a Choice

The Hardware Baseline and Why It Forces Real Decisions

The comparison here isn't theoretical. Single-node Docker host, 16 GB RAM, no GPU, Caddy handling TLS termination and reverse proxying. That constraint eliminates a whole class of recommendations immediately — anything that idles at 2+ GB RAM per service is already competing for headroom with databases, reverse proxies, and whatever else is running on the same box. Calendar workloads have no GPU requirement, but they do have a latency expectation: a user hitting a CalDAV sync or loading a shared calendar invite shouldn't wait four seconds while a JVM warms up.

Three axes determine which stack survives that environment. First: calendar feature completeness — specifically CalDAV protocol support, per-user sharing with granular permissions, and outbound invite handling that external clients (iOS Calendar, Thunderbird, Android via DAVx⁵) can actually consume without custom workarounds. Second: resource overhead at idle and under concurrent sessions, because a service that idles at 80 MB but balloons to 900 MB when three users sync simultaneously is a different animal than one that's consistently 300 MB. Third: integration surface — how cleanly does this service plug into an existing Docker Compose stack with a shared Postgres instance, a shared Redis, or an SMTP relay container? Services that want their own bundled database, or that assume they own the network namespace, create operational drag that compounds over time.

Nextcloud comes up in every self-hosted calendar conversation for obvious reasons: the ecosystem is massive, the CalDAV implementation is mature, and the file access story is genuinely good. The problem is that Nextcloud's calendar features come attached to a full collaboration suite you probably don't want. On a 16 GB single-node host, a production Nextcloud install with PostgreSQL backend, Redis for file locking, and a PHP-FPM pool sized for even modest concurrency will consume 600 MB–1.2 GB at idle depending on worker configuration — before you add ONLYOFFICE or any other app. If the requirement is "calendar plus light file access," you're paying a significant resource tax for hub features (Nextcloud Talk, Activities, the full Files app with chunked uploads) that sit idle and still consume memory through background workers and cron jobs.

The sharper problem with Nextcloud is its cron dependency. The nextcloud-cron container — or a system cron hitting occ cron — has to run every five minutes or calendar reminders drift, shares stop propagating, and background jobs queue up silently. Miss it for an hour and you start debugging why invites aren't arriving, not realizing the jobs table has 400 pending entries. That operational overhead is fine when you're running a full Nextcloud deployment for a team, but it's hard to justify for a stack whose primary workload is CalDAV sync and occasional document preview. FileRun, Radicale, and Baikal sidestep this entirely — they're stateless or near-stateless per-request services without background job infrastructure. That's the concrete reason to look past Nextcloud when the scope is narrow.

# Rough idle footprint comparison — measure on your own host with:
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}"

# Nextcloud (PHP-FPM + background workers, no apps beyond Calendar):
# nextcloud-app     ~420MiB / 16GiB
# nextcloud-cron    ~180MiB / 16GiB
# nextcloud-redis   ~12MiB  / 16GiB

# Radicale (Python, single process, SQLite or filesystem storage):
# radicale          ~28MiB  / 16GiB

# Baikal (PHP, no background workers):
# baikal            ~55MiB  / 16GiB
Enter fullscreen mode Exit fullscreen mode

Those aren't benchmarks — run them yourself, because PHP-FPM pool sizes and OPcache configuration will shift numbers significantly. The point is the order of magnitude difference. A service stack that leaves 14 GB free after the calendar layer is running means you can colocate FileRun, an ONLYOFFICE Document Server for previews, and a Postgres 16 instance without swapping. That arithmetic is why the hardware baseline has to be explicit before any recommendation lands.

FileRun 2026: Calendar as a Bolt-On to a File Manager

The important framing to get right before you touch a config file: FileRun is a Dropbox-style self-hosted file manager that happens to expose CalDAV and CardDAV endpoints. It is not a calendar application with file storage attached. That distinction changes your expectations immediately — the calendar UI inside FileRun is bare-bones by design, and the real value of the CalDAV endpoint is for syncing with an external client (Thunderbird, Apple Calendar, DAVx⁵ on Android). If you want a rich calendar interface in the browser, you will be disappointed. If you want a single container that handles file sync and lets your phone sync its calendar without running a separate Nextcloud or Radicale instance, FileRun in 2026 is still a reasonable answer.

The MySQL 8 requirement is not negotiable and it is where most first-time deployments stall. FileRun's PHP layer also requires iconv and gd to be present — they are not always included in base PHP-FPM images and the error you get when they are missing is a generic 500, not a helpful "extension not found" message. A minimal working docker-compose.yml that avoids the common traps:

version: "3.9"

services:
  filerun-db:
    image: mysql:8.0
    container_name: filerun-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: changeme_root
      MYSQL_DATABASE: filerun
      MYSQL_USER: filerun
      MYSQL_PASSWORD: changeme_filerun
    volumes:
      - filerun-db:/var/lib/mysql
    # innodb_buffer_pool_size controls RAM floor; 128M is workable for small deployments
    command: --innodb_buffer_pool_size=128M --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

  filerun:
    image: filerun/filerun:latest
    container_name: filerun
    restart: unless-stopped
    depends_on:
      - filerun-db
    environment:
      FR_DB_HOST: filerun-db
      FR_DB_PORT: 3306
      FR_DB_NAME: filerun
      FR_DB_USER: filerun
      FR_DB_PASS: changeme_filerun
    volumes:
      - filerun-html:/var/www/html
      - /mnt/data/filerun-userfiles:/user-files
    ports:
      - "8080:80"

volumes:
  filerun-db:
  filerun-html:
Enter fullscreen mode Exit fullscreen mode

The official FileRun image bundles the PHP extensions including gd and iconv, so if you pull filerun/filerun directly you will not hit the extension trap. Where people get burned is when they try to run FileRun on a generic php:8.2-fpm base behind their own Nginx config — at that point you need to explicitly add docker-php-ext-install gd intl in your Dockerfile and rebuild. The utf8mb4 charset flags on MySQL are not optional either; FileRun stores file and calendar metadata that includes Unicode characters and the default MySQL 8 charset handling will silently truncate emoji in filenames or event titles.

The CalDAV endpoint lives at /dav.php. For Thunderbird with the TbSync or CardBook extension, or Apple Calendar on macOS/iOS, the URL format is:

# Apple Calendar / Thunderbird CardBook
https://filerun.yourdomain.com/dav.php/calendars/USERNAME/default/

# What the FileRun docs show (correct)
https://filerun.yourdomain.com/dav.php/calendars/USERNAME/

# What breaks Android DAVx⁵ (missing trailing slash)
https://filerun.yourdomain.com/dav.php/calendars/USERNAME
Enter fullscreen mode Exit fullscreen mode

That trailing slash on the /calendars/USERNAME/ path is not mentioned in the FileRun documentation but it is the first thing to check when DAVx⁵ connects, authenticates successfully, and then shows zero calendars. The underlying issue is that the PHP router does not issue a redirect for the slash-less variant when the request comes from a DAV client rather than a browser — the server returns a 200 with an empty response body instead of a 301, so DAVx⁵ interprets it as "no calendars found" rather than a misconfigured URL. Apple Calendar is more forgiving and will follow the redirect; Android clients are not.

On resource usage: expect the PHP-FPM container to sit at roughly 80–120 MB RAM at idle with no active users. Under active file sync or calendar operations it will spike, but it returns to baseline quickly. The MySQL container is the variable — at the 128 MB innodb_buffer_pool_size shown above, it will idle around 200–250 MB total process RSS. If you push that setting to 512 MB (reasonable for a small team), MySQL alone can consume 400–500 MB. On a VPS with 2 GB total RAM, the combination is workable but leaves limited headroom if you are also running a reverse proxy and anything else on the same host. FileRun does not cache aggressively at the PHP layer, so repeated directory listings do go back to MySQL — keep that buffer pool large enough to hold your working set of file metadata or you will feel it in latency.

OnlyOffice: Calendar Inside a Document Collaboration Suite

The most common OnlyOffice mistake isn't a configuration error — it's running the wrong product entirely. OnlyOffice Docs (the standalone document editor, the one virtually every Docker tutorial covers) has no calendar. Zero. The calendar feature lives exclusively in OnlyOffice Community Server, which is a completely different container with a completely different resource profile. If you followed a guide that had you pull onlyoffice/documentserver, you got the editor only. Community Server is onlyoffice/communityserver, and conflating the two will cost you hours before you realize the calendar tab simply doesn't exist in what you deployed.

The Docker deployment reality for Community Server is aggressive on resources. The single container image runs MySQL, Elasticsearch, and RabbitMQ internally — not as separate compose services you can tune individually, but bundled inside the one container with its own internal process supervisor. On a 16 GB host, expect 3–5 GB RAM consumed at idle before a single user connects. Elasticsearch alone accounts for a significant chunk of that. You can cap it somewhat with JVM heap flags passed as environment variables, but you're fighting the architecture rather than tuning it:

docker run -d \
  --name onlyoffice-community \
  -p 80:80 -p 443:443 -p 5222:5222 \
  -e ELASTICSEARCH_SERVER_JAVA_OPTS="-Xms512m -Xmx512m" \
  -v /app/onlyoffice/CommunityServer/data:/var/www/onlyoffice/Data \
  -v /app/onlyoffice/CommunityServer/mysql:/var/lib/mysql \
  -v /app/onlyoffice/CommunityServer/logs:/var/log/onlyoffice \
  onlyoffice/communityserver
Enter fullscreen mode Exit fullscreen mode

Dropping Elasticsearch's heap to 512 MB helps, but the service will start complaining under any real indexing load. This is not a box you run on a $6/month VPS.

The calendar feature surface is genuinely capable once you're in. Room booking is built in, external CalDAV sync exists, and iCal feed export works reliably. The UI is polished — arguably the most finished calendar UI in the self-hosted space. The friction shows up in CalDAV client compatibility. DAVx⁵ on Android connects without drama. macOS Calendar is where things get fiddly: the auto-discovery URL that Apple expects doesn't always resolve correctly, and you'll often end up manually constructing the endpoint URL in the format https://your-domain/caldav/[user-guid]/ rather than just pointing at the domain root. The docs claim broad CalDAV compatibility; the reality is you'll debug at least one client before everything syncs cleanly.

The overhead is defensible exactly once: when your team already needs collaborative document editing and would otherwise run a separate OnlyOffice Docs instance anyway. In that scenario, Community Server consolidates two services into one, and the 4 GB idle RAM cost gets spread across both use cases. If you only want a web calendar — maybe with some file storage on the side — that calculus falls apart immediately. FileRun with a CalDAV sidecar, or Nextcloud on a constrained machine, will deliver a usable calendar at a fraction of the memory footprint. Community Server's bundled architecture is a product decision optimized for replacing Google Workspace entirely, not for running one module of it.

Pangolin: The Reverse-Proxy-Native Approach

Pangolin solves a different problem than FileRun or OnlyOffice do. It doesn't ship a calendar, a file manager, or a document editor — it's a self-hosted tunneling and reverse proxy platform, roughly analogous to Cloudflare Tunnel but running entirely on infrastructure you control. The interesting move here is using Pangolin as the exposure layer for a lightweight CalDAV server like Baïkal or Radicale, so you get identity-aware access control and encrypted tunneling without touching a firewall rule. If your calendar host lives on a separate VLAN, a homelab node behind CGNAT, or a remote machine you'd rather not punch holes in, this architecture is worth understanding.

The core architectural difference: FileRun and OnlyOffice assume the service is directly reachable — you configure a reverse proxy in front, you open ports, you manage TLS termination yourself. Pangolin flips this. The tunnel daemon on your internal host dials outward to your Pangolin server; no inbound port ever opens. The Pangolin edge then applies zero-trust rules (user identity, device posture, resource policies) before a request even reaches your Baïkal container. For a calendar endpoint specifically, this means a stolen session token is less dangerous — the attacker still has to pass the identity check at the Pangolin layer before they can even issue a CalDAV request.

Configuring a Pangolin site target to front a Baïkal container requires careful attention to header forwarding. CalDAV clients — iOS Calendar, Thunderbird with the TbSync extension, and most DAV-aware clients — rely on the Authorization header passing through untouched, and they use the Host and DAV headers to discover capability. A common failure mode is the proxy stripping or rewriting Authorization: Digest headers, which causes silent auth failures that look like connectivity problems. The Pangolin site config to get this right:

# pangolin/config/sites/baikal-cal.yaml
site:
  id: baikal-cal
  target: http://baikal.internal:8800   # internal container, no port exposure needed
  tunnel:
    enabled: true
    daemon_host: homelab-node-01        # the host running the newt tunnel daemon

  proxy:
    preserve_host: true                 # CalDAV clients break if Host gets rewritten
    trusted_headers:
      - X-Forwarded-For
      - X-Forwarded-Proto
    pass_through_headers:
      - Authorization                   # Digest auth must not be consumed or stripped
      - DAV                             # capability negotiation header
      - Depth                           # required for PROPFIND recursion
      - Destination                     # required for MOVE/COPY operations
    strip_headers:
      - X-Internal-Token                # don't leak internal routing headers

  access:
    policy: authenticated               # Pangolin identity check before any proxying
    allowed_roles:
      - calendar-users
Enter fullscreen mode Exit fullscreen mode

The Depth and Destination headers aren't documented in most proxy guides because they're invisible in browser-based apps — but CalDAV PROPFIND requests use Depth: 1 extensively, and any proxy that doesn't pass them through will produce 400 errors that look like Baïkal configuration failures. Test with curl before trusting a GUI client's error message:

# Verify PROPFIND reaches Baïkal with correct headers intact
curl -v \
  --request PROPFIND \
  --header "Depth: 1" \
  --header "Content-Type: application/xml" \
  --user "user:password" \
  --data '' \
  https://baikal-cal.your-pangolin-domain.example/dav.php/calendars/user/

# A working response starts with HTTP/2 207 (Multi-Status)
# A proxy header problem usually returns 401 or 400 with no DAV response body
Enter fullscreen mode Exit fullscreen mode

The honest trade-off: you're now operating two separate systems where FileRun runs one. The Pangolin tunnel daemon (newt) on each internal host needs to stay running and connected, and you need to reason about two failure domains — the calendar service going down versus the tunnel or Pangolin edge going down. On my setup I'd handle this by running the newt daemon under a systemd unit with Restart=always and a separate health check, rather than assuming the Pangolin dashboard will catch a dropped tunnel fast enough. The payoff is real network isolation: the Baïkal container genuinely has no listening port reachable from outside its own host, and adding a second calendar service for a different team means adding a site config entry, not modifying firewall rules or figuring out NAT hairpinning again.

Side-by-Side: What You Actually Get Per Use Case

The comparison that matters isn't feature lists — it's what each stack costs you when it's idle and what breaks first under real conditions. Most self-hosters discover these limits the hard way after a weekend of setup, not from the docs. Let me short-circuit that.

Criteria

FileRun

OnlyOffice

Pangolin

CalDAV standard compliance

Partial — CalDAV exposed via bundled component, not a first-class implementation; interop quirks with Thunderbird

Reasonable RFC 4791 coverage but config is non-obvious; requires explicit HTTPS or clients silently refuse to connect

N/A — Pangolin is a reverse proxy/tunnel layer, CalDAV compliance is entirely the backend's problem

Idle RAM floor

~200–350 MB with PHP-FPM + MariaDB; predictable and low

1.2–2 GB at genuine idle with Document Server running; JVM-adjacent behavior — it never really sleeps

~50–80 MB; it's a Go binary doing tunnel brokering, not processing documents

Disk footprint after initial pull

~800 MB–1.2 GB including MariaDB image

6–8 GB for the full Document Server stack; the community edition image alone is over 4 GB compressed

Under 200 MB; single binary distribution path is available

Multi-user sharing UI

Solid file-level sharing with link expiry, password protection; calendar sharing is minimal compared to the file side

Room/group calendars work well when the full platform is deployed; sharing model is tightly coupled to the broader workspace concept

No sharing UI — delegates entirely to whatever is sitting behind it

Mobile client compatibility

Works with DAVx⁵ on Android and iOS native Accounts; occasional sync delay on the file side

Mobile web is passable; native mobile CalDAV via DAVx⁵ functions but the UI push is clearly toward the desktop browser experience

Transparent to clients — they hit whatever URL Pangolin exposes and never know there's a tunnel

Biggest single dealbreaker

Commercial license required for production; the free tier isn't usable long-term for a real deployment

Resource floor makes it indefensible on a 16 GB host running other services; you're burning RAM 24/7 for a feature most users open twice a week

People mistake it for a calendar product and are confused when there's no calendar — it's access infrastructure, full stop

FileRun verdict: The right call if you're already running it as a file manager and want calendar as a secondary convenience, not a primary capability. On constrained hardware — say a 2-core VPS with 4 GB RAM — FileRun's PHP-FPM footprint is manageable where OnlyOffice would be immediately out of the question. The CalDAV implementation is good enough for personal use and small teams, provided you're not expecting tight spec compliance. License cost is the real gate: budget for it or pick something else.

OnlyOffice verdict: Defensible only when real-time document collaboration is also on the requirements list. If someone on the team needs co-editing on DOCX or XLSX files in the browser, the resource spend amortizes across multiple use cases and starts to make sense. Running OnlyOffice purely for CalDAV on a host that also runs a database, a Node app, and a reverse proxy is resource waste you'll feel every time you SSH in and check htop. On a dedicated 32 GB machine with room to spare it's fine, but that's exactly the scenario where you probably have better options too.

Pangolin verdict: Not a calendar product and shouldn't be evaluated as one. Its specific value is solving the external access problem — getting a CalDAV server that lives on a machine without a public IP reliably reachable from the internet without punching firewall holes. Pair it with Baïkal (Docker image under 50 MB, strict RFC 4791 implementation, near-zero idle RAM beyond PHP-FPM) and you get a minimal-footprint calendar stack that's actually reachable from iOS and Android over WireGuard or the Pangolin tunnel. That combination beats any of the heavier stacks for operators who just want calendars to sync and don't need a document suite hanging off the side.

# Baïkal + Pangolin: the lightest viable external CalDAV setup
# docker-compose.yml fragment

services:
  baikal:
    image: ckulka/baikal:nginx  # ~48 MB compressed; nginx variant avoids Apache overhead
    volumes:
      - ./baikal/config:/var/www/baikal/config
      - ./baikal/Specific:/var/www/baikal/Specific
    restart: unless-stopped
    # Do NOT expose a port directly — let Pangolin handle TLS termination

  pangolin:
    image: fosrl/pangolin:latest
    environment:
      - PANGOLIN_UPSTREAM=http://baikal:80
      - PANGOLIN_DOMAIN=cal.yourdomain.com
      # Pangolin handles ACME cert renewal; clients see valid TLS, baikal sees plain HTTP internally
    ports:
      - "443:443"
      - "80:80"
    depends_on:
      - baikal
    restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode

The one gotcha with this Baïkal pairing: Baïkal's admin interface uses the same nginx instance as the CalDAV endpoint. Restrict /admin at the Pangolin or upstream config level — don't leave it accessible to the public-facing URL. Pangolin's route config supports path-level rules, so this is a one-liner addition rather than a separate nginx config overlay.

Gotchas That Cost Time Across All Three

The CalDAV principal URL problem will burn you on every new client setup, no matter which backend you're running. Most calendar apps — Thunderbird, iOS Calendar, DAVx⁵ — attempt auto-discovery by hitting /.well-known/caldav and following redirects to find the principal URL, then the calendar collection. The spec describes how this should work. Reality is messier: some clients interpret a redirect to the principal as the collection itself, others stop after one hop, and a few just silently fail without logging what they actually tried. The only configuration that reliably works across all clients is skipping auto-discovery entirely and hardcoding the full collection path. For FileRun that's something like https://files.example.com/dav.php/calendars/username/default/. For Baikal behind Pangolin, it's https://cal.example.com/dav.php/principals/username/ for the principal, but clients want the collection one level deeper. Test each client explicitly — don't assume that because auto-discovery worked in one, it'll work in another.

TLS termination at a reverse proxy breaks CalDAV in a way that's genuinely confusing to debug because the app logs show successful requests while every client silently refuses to authenticate. What's actually happening: Caddy or Nginx is terminating HTTPS and forwarding plain HTTP to the backend container. The CalDAV server generates redirect URLs and auth challenges using HTTP, the client sees those and either refuses to send credentials over what it thinks is a plaintext connection, or the authentication handshake fails because the scheme mismatch breaks the URL comparison logic. The fix is the same whether you're using Caddy or Nginx — you need to explicitly forward the original protocol. In Nginx:

proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
# Without these two lines, PROPFIND responses contain http:// hrefs
# and clients will either fall back silently or fail auth
Enter fullscreen mode Exit fullscreen mode

In Caddy, reverse_proxy forwards X-Forwarded-Proto automatically only if you're using the https scheme in the upstream address — if you're proxying to a container by Docker network name over plain HTTP (which is normal), you need header_up X-Forwarded-Proto https explicitly. Miss this and you'll spend an hour staring at 401s that aren't actually authentication failures.

FileRun has a specific gotcha that isn't prominently documented: the APP_ID environment variable gets written into the database on first boot, and that database value is what the application actually uses for URL generation and CSRF validation. If you change the domain the instance is served from — even just switching from an IP to a hostname, or adding a subdomain — updating the env var alone does nothing. The running instance reads the stored value. You need a direct database update:

-- Run against your FileRun MySQL/MariaDB database
UPDATE fc_settings SET value = 'https://newdomain.example.com'
WHERE name = 'APP_ID';

-- Then restart the FileRun container; the env var at that point
-- should match what's in the DB to avoid future confusion
Enter fullscreen mode Exit fullscreen mode

Failing to do this produces subtly broken behavior — file sharing links generate with the old domain, CalDAV redirects point to the wrong origin, and WebDAV clients reject the server's responses. The env var and the DB value need to be in sync, with the DB value being authoritative.

OnlyOffice Community Server bundles Elasticsearch as an internal dependency for search and, depending on your installation path, for calendar indexing. ES requires a kernel-level setting — vm.max_map_count must be at least 262144 — and on most default VPS images it's set to 65530. When the ES container hits that limit it fails to start, but the OnlyOffice application container doesn't surface this as a clear error. The calendar UI just stops working or loads empty. Check before anything else:

# On the host — not inside the container
sysctl vm.max_map_count
# If output is below 262144:
sysctl -w vm.max_map_count=262144
# To persist across reboots:
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
Enter fullscreen mode Exit fullscreen mode

On a shared VPS where you don't have host-level access, this is a hard blocker — you cannot fix it from inside a container, and privileged mode doesn't help with kernel parameters that require host access. If you're on a managed host without shell access to the hypervisor node, OnlyOffice Community Server is not a viable option. That's not a configuration problem you can engineer around.


Disclaimer: This article is for informational purposes only. The views and opinions expressed are those of the author(s) and do not necessarily reflect the official policy or position of Sonic Rocket or its affiliates. Always consult with a certified professional before making any financial or technical decisions based on this content.


Originally published on techdigestor.com. Follow for more developer-focused tooling reviews and productivity guides.

Top comments (0)