{"id":32177,"date":"2026-07-16T15:11:28","date_gmt":"2026-07-16T13:11:28","guid":{"rendered":"https:\/\/contabo.com\/blog\/?p=32177"},"modified":"2026-07-16T15:11:31","modified_gmt":"2026-07-16T13:11:31","slug":"selfhost-docmost-with-docker-on-vps","status":"publish","type":"post","link":"https:\/\/contabo.com\/blog\/selfhost-docmost-with-docker-on-vps\/","title":{"rendered":"How to Self-Host Docmost with Docker on a VPS (2026 Guide)\u00a0"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>In short.<\/strong> Self-hosting Docmost with Docker means running three containers, the Docmost app, PostgreSQL, and Redis, behind an Nginx reverse proxy with HTTPS. The Docmost Docker setup takes under 20 minutes on a VPS with 4 GB RAM or more. You optionally point file attachments at S3-compatible Object Storage to keep the VPS disk clean. This guide covers the full stack: Docker Compose, HTTPS, and object storage for attachments.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Docmost is an open source Confluence alternative that also replaces most of what teams use Notion for: real-time collaborative editing, nested pages, and workspace permissions, running entirely on infrastructure you control. Getting Docmost self-hosted on your own VPS means your team&#8217;s documentation never touches a third-party server, with no per-seat licensing. This guide goes past a bare install: it adds a production-ready reverse proxy with HTTPS and S3-compatible attachment storage, so the result is a deployable setup rather than a local test.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-prerequisites\">Prerequisites\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A Docmost Docker deployment needs a few things in place before a self-hosted instance is ready for real use:&nbsp;<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>A VPS with at least 2 vCPU and 4 GB RAM. Below that, PostgreSQL and Redis compete with the app container for memory under real usage. A Contabo Cloud VPS 20 (6 vCPU cores, 12 GB RAM, \u20ac6.00\/mo) comfortably covers the full stack with headroom for growth.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>Ubuntu 22.04 or 24.04.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li>Root or sudo SSH access.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li>A domain or subdomain pointed at your VPS&#8217;s IP address. This is required for Step 3, since Docmost&#8217;s real-time features depend on HTTPS working correctly.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"5\" class=\"wp-block-list\">\n<li>Optional: an S3-compatible Object Storage bucket (Contabo Object Storage works) if you want attachments off the VPS disk from day one.\u00a0<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Install Docker and Docker Compose for Docmost\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ubuntu&#8217;s default package repository carries an older Docker version, so this installs directly from Docker&#8217;s official repository instead, which keeps Compose and the Docker engine on the current stable release.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>sudo<\/strong> apt update <strong>&amp;&amp;<\/strong> <strong>sudo<\/strong> apt upgrade -y\u00a0\n<strong>sudo<\/strong> apt install -y ca-certificates curl\u00a0\n<strong>sudo<\/strong> install -m 0755 -d \/etc\/apt\/keyrings\u00a0\n<strong>sudo<\/strong> curl -fsSL <a href=\"https:\/\/download.docker.com\/linux\/ubuntu\/gpg\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">https:\/\/download.docker.com\/linux\/ubuntu\/gpg<\/a> -o \/etc\/apt\/keyrings\/docker.asc\u00a0\n<strong>sudo<\/strong> chmod a+r \/etc\/apt\/keyrings\/docker.asc\u00a0\necho \\\u00a0\n\u00a0\u00a0 \"deb &#91;arch=$(dpkg --print-architecture) signed-by=\/etc\/apt\/keyrings\/docker.asc] <a href=\"https:\/\/download.docker.com\/linux\/ubuntu\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">https:\/\/download.docker.com\/linux\/ubuntu<\/a> \\\u00a0\n\u00a0\u00a0 $(. \/etc\/os-release <strong>&amp;&amp;<\/strong> echo \"$VERSION_CODENAME\") stable\" <strong>|<\/strong> \\\u00a0\n\u00a0\u00a0 <strong>sudo<\/strong> tee \/etc\/apt\/sources.list.d\/docker.list <strong>><\/strong> \/dev\/null\u00a0\n<strong>sudo<\/strong> apt update\u00a0\n<strong>sudo<\/strong> apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the installation:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose version\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A version number confirms Docker Compose is ready for the Docmost stack.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Create the Docmost Docker Compose Stack\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The Docmost Docker stack runs three services: the Docmost application, PostgreSQL for data, and Redis for real-time collaboration state. This is the core of any self-hosted Docmost deployment, whether it runs on a single small VPS or a larger production server. PostgreSQL stores every page, user account, and permission setting. Redis handles the pub\/sub messaging that keeps multiple editors in sync, so it is not optional even for a single-user setup. Docker Compose defines all three as one unit, starting and stopping the whole stack together instead of three separate docker run commands.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a project directory and the Compose file:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>mkdir<\/strong> -p ~\/docmost <strong>&amp;&amp;<\/strong> cd ~\/docmost\u00a0\n<strong>nano<\/strong> docker-compose.yml\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Paste the following, replacing the placeholder values with your own domain and generated secrets:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>services:<\/strong>\u00a0\n\u00a0\u00a0 <strong>docmost:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>image:<\/strong> docmost\/docmost:latest\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>depends_on:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>-<\/strong> db\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>-<\/strong> redis\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>environment:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>APP_URL:<\/strong> \"<a href=\"https:\/\/your-domain.com\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">https:\/\/your-domain.com<\/a>\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>APP_SECRET:<\/strong> \"replace-with-a-long-random-string\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>DATABASE_URL:<\/strong> \"postgresql:\/\/docmost:your-db-password@db:5432\/docmost\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>REDIS_URL:<\/strong> \"redis:\/\/redis:6379\"\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>ports:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>-<\/strong> \"3000:3000\"\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>restart:<\/strong> unless-stopped\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>volumes:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>-<\/strong> docmost_storage:\/app\/data\/storage\u00a0\n\u00a0\n\u00a0 <strong>db:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>image:<\/strong> postgres:18\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>environment:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>POSTGRES_USER:<\/strong> docmost\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>POSTGRES_PASSWORD:<\/strong> your-db-password\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>POSTGRES_DB:<\/strong> docmost\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>volumes:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>-<\/strong> docmost_db_data:\/var\/lib\/postgresql\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>restart:<\/strong> unless-stopped\u00a0\n\u00a0\n\u00a0 <strong>redis:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>image:<\/strong> redis:8\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>command:<\/strong> <strong>&#91;<\/strong>\"redis-server\"<strong>,<\/strong> \"--appendonly\"<strong>,<\/strong> \"yes\"<strong>,<\/strong> \"--maxmemory-policy\"<strong>,<\/strong> \"noeviction\"<strong>]<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>volumes:<\/strong>\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>-<\/strong> docmost_redis_data:\/data\u00a0\n\u00a0\u00a0\u00a0\u00a0 <strong>restart:<\/strong> unless-stopped\u00a0\n\u00a0\n<strong>volumes:<\/strong>\u00a0\n\u00a0\u00a0 <strong>docmost_storage:<\/strong>\u00a0\n\u00a0\u00a0 <strong>docmost_db_data:<\/strong>\u00a0\n\u00a0\u00a0 <strong>docmost_redis_data:<\/strong>\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Generate a secure <code>APP_SECRET<\/code> with <code>openssl rand -hex 32<\/code>. Docmost requires this value to be at least 32 characters. It signs session tokens and encrypts sensitive fields, so it needs to be long, random, and never reused across environments. Do the same for the database password.\u00a0<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Email is optional and only needed to send workspace invitations. It requires SMTP or Postmark configuration covered in Docmost&#8217;s own configuration docs, so the compose file above omits it.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Configure HTTPS with Nginx\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Docmost listens on port 3000 by default with no built-in TLS, which matters for any self-hosted deployment reachable from the public internet. Nginx sits in front of the container, terminates TLS, and forwards requests internally, which is the standard pattern for exposing a containerized app to the internet safely.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Install Nginx and Certbot:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>sudo<\/strong> apt install -y nginx certbot python3-certbot-nginx\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create a server block for your domain:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>sudo<\/strong> nano \/etc\/nginx\/sites-available\/docmost\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add the following, replacing <code>your-domain.com<\/code> with your actual domain:\u00a0<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\u00a0\n\u00a0\u00a0\u00a0\u00a0 listen 80;\u00a0\n\u00a0\u00a0\u00a0\u00a0 server_name your-domain.com;\u00a0\n\u00a0\n\u00a0\u00a0\u00a0 location \/ {\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_pass <a href=\"http:\/\/localhost:3000\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">http:\/\/localhost:3000<\/a>;\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_http_version 1.1;\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_set_header Upgrade $http_upgrade;\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_set_header Connection \"upgrade\";\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_set_header Host $host;\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_set_header X-Real-IP $remote_addr;\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 proxy_set_header X-Forwarded-Proto $scheme;\u00a0\n\u00a0\u00a0\u00a0\u00a0 }\u00a0\n}\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Upgrade and Connection headers are required for Docmost&#8217;s real-time collaboration feature, which runs over WebSockets. Without them, the page editor loads but stays read-only.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enable the site and request a certificate:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>sudo<\/strong> ln -s \/etc\/nginx\/sites-available\/docmost \/etc\/nginx\/sites-enabled\/\u00a0\n<strong>sudo<\/strong> certbot --nginx -d your-domain.com\u00a0\n<strong>sudo<\/strong> systemctl reload nginx\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Certbot rewrites the server block to redirect HTTP to HTTPS automatically and sets up auto-renewal.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Start Docmost with Docker and Complete Setup\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Start the Docmost Docker stack:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose up -d\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Watch the logs while the containers initialize:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose logs -f\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wait for the Docmost service to report it is listening, then open <a href=\"https:\/\/your-domain.com\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">https:\/\/your-domain.com<\/a> in a browser. Create your admin account and first workspace on the setup screen that appears. This account has full workspace permissions, so use a strong password.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To confirm all three containers are healthy, run:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose ps\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Each service should show a status of running or <code>healthy<\/code>. Once your workspace is created, invite teammates from the admin settings. Each invited member gets their own login, and the same real-time editing access you just tested.\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5 (Optional): Connect Contabo Object Storage for Attachments\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">By default, Docmost stores uploaded files on the container filesystem. Pointing your Docmost Docker deployment at S3-compatible Object Storage decouples file storage from the server entirely, which means a server migration or disk resize no longer needs to account for years of accumulated attachments. This is one of the details that separates a self-hosted knowledge base test install from a production deployment.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add the following environment variables to the <code>docmost <\/code>service in <code>docker-compose.yml<\/code>:\u00a0<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>STORAGE_DRIVER:<\/strong> \"s3\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>AWS_S3_BUCKET:<\/strong> \"your-bucket-name\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>AWS_S3_ENDPOINT:<\/strong> \"<a href=\"https:\/\/eu2.contabostorage.com\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">https:\/\/eu2.contabostorage.com<\/a>\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>AWS_S3_REGION:<\/strong> \"default\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>AWS_S3_ACCESS_KEY_ID:<\/strong> \"your-access-key\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>AWS_S3_SECRET_ACCESS_KEY:<\/strong> \"your-secret-key\"\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>AWS_S3_FORCE_PATH_STYLE:<\/strong> \"true\"\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The endpoint hostname follows the region prefix Contabo uses (<code>eu2 <\/code>for the European region shown here). Use the hostname shown in your own Object Storage panel if you provisioned a different region. The <code>AWS_S3_REGION<\/code> value stays default regardless of which regional endpoint you use, matching the configuration examples Contabo publishes for S3-compatible tools. <code>AWS_S3_FORCE_PATH_STYLE<\/code> is required for most S3-compatible providers, Contabo included.\u00a0<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Restart the stack to apply the change:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose up -d\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">New attachments now upload directly to Object Storage. Existing local files stay on disk unless you migrate them manually.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A handful of issues account for most failed Docmost Docker deployments:&nbsp;<\/p>\n\n\n\n<ol start=\"6\" class=\"wp-block-list\">\n<li><strong>Container exits immediately after <code>docker compose up -d<\/code>.<\/strong> Check <code>docker compose logs docmost<\/code> for a database connection error first. This almost always traces to a typo in <code>DATABASE_URL<\/code> or a <code>POSTGRES_PASSWORD<\/code> mismatch between the <code>docmost <\/code>and <code>db <\/code>service blocks.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"7\" class=\"wp-block-list\">\n<li><strong>Nginx returns a 502 Bad Gateway.<\/strong> Confirm the Docmost container is actually running with <code>docker compose ps<\/code>. A 502 means Nginx cannot reach port 3000, usually because the container crashed or is still starting.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"8\" class=\"wp-block-list\">\n<li><strong>Certbot fails to issue a certificate.<\/strong> This is almost always DNS. Confirm your domain&#8217;s A record points at the VPS IP with <code>dig your-domain.com<\/code>, and wait for propagation before retrying.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"9\" class=\"wp-block-list\">\n<li><strong>Real-time collaboration doesn&#8217;t work, and the editor loads but stays read-only.<\/strong> Docmost&#8217;s own documentation confirms this exact symptom means the reverse proxy isn&#8217;t forwarding the Upgrade and Connection headers from Step 3.\u00a0<\/li>\n<\/ol>\n\n\n\n<ol start=\"10\" class=\"wp-block-list\">\n<li><strong>File uploads fail after switching to Object Storage.<\/strong> Double-check <code>AWS_S3_BUCKET<\/code> and <code>AWS_S3_ENDPOINT<\/code> for typos, and confirm the access key has writing permissions on that specific bucket. A missing <code>AWS_S3_FORCE_PATH_STYLE<\/code>: &#8220;<code>true<\/code>&#8221; also causes silent upload failures with Contabo and most other S3-compatible providers.\u00a0<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Keeping Your Self-Hosted Docmost Updated\u00a0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pull the latest image and recreate the containers:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/docmost\u00a0\ndocker compose pull\u00a0\ndocker compose up -d\u00a0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the running version in the admin panel after the containers restart. Check the Docmost release notes before a major version bump, since schema migrations occasionally require a manual step that a minor update does not. A database backup before a major update, using the <code>pg_dump<\/code> command from the FAQ below, costs one command and gives you a clean rollback point.\u00a0<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Keeping a self-hosted Docmost instance current is otherwise low effort: the update itself is two commands, and the persistent volumes in Step 2 mean the database, cache, and attachments all survive the restart untouched.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ: Self-Hosted Docmost\u00a0<\/h2>\n\n\n\n<div class=\"schema-faq wp-block-yoast-faq-block\"><div class=\"schema-faq-section\" id=\"faq-question-1784207291094\"><strong class=\"schema-faq-question\">How much RAM does Docmost need?\u00a0<\/strong> <p class=\"schema-faq-answer\">Docmost, PostgreSQL, and Redis together run comfortably on 4 GB of RAM for small to mid-sized teams. A 2 GB VPS works for light testing but leaves little headroom under real usage. For a production workspace with regular concurrent editing, 8 GB or more gives PostgreSQL room to cache effectively without swapping.\u00a0<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1784207313511\"><strong class=\"schema-faq-question\">Can I use Docmost without a domain?\u00a0<\/strong> <p class=\"schema-faq-answer\">Yes, for testing. You can access Docmost over HTTP using the server&#8217;s IP address and port 3000 directly, without any domain or Nginx setup. Real-time collaboration and any feature depending on secure cookies will not work correctly without HTTPS, though. A domain and a reverse proxy are required for a usable production deployment.\u00a0<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1784207345030\"><strong class=\"schema-faq-question\">How do I back up Docmost data?\u00a0<\/strong> <p class=\"schema-faq-answer\">Back up the PostgreSQL data volume, since it holds all workspace content, users, and permissions. Run <code>docker compose exec db pg_dump -U docmost docmost > backup.sql<\/code> on a schedule, and store the output somewhere off the VPS, such as a separate server or Object Storage bucket. If you use Object Storage for attachments, that data is already stored separately from the server.\u00a0<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1784207371971\"><strong class=\"schema-faq-question\">Does Docmost support S3 storage?\u00a0<\/strong> <p class=\"schema-faq-answer\">Yes. Setting <code>STORAGE_DRIVER=s3<\/code> along with the bucket, endpoint, region, and credential variables (<code>AWS_S3_BUCKET, AWS_S3_ENDPOINT, AWS_S3_REGION, AWS_S3_ACCESS_KEY_ID, AWS_S3_SECRET_ACCESS_KEY<\/code>) redirects new file uploads to any S3-compatible provider, including Contabo Object Storage. This keeps attachments off the VPS disk and makes them easier to back up independently of the database. The change applies only to new uploads going forward.\u00a0<\/p> <\/div> <\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In short. Self-hosting Docmost with Docker means running three containers, the Docmost app, PostgreSQL, and Redis, behind an Nginx reverse proxy with HTTPS. The Docmost Docker setup takes under 20 minutes on a VPS with 4 GB RAM or more. You optionally point file attachments at S3-compatible Object Storage to keep the VPS disk clean. [&hellip;]<\/p>\n","protected":false},"author":44,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_uag_custom_page_level_css":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[18],"tags":[1471,4707,4472,894],"ppma_author":[3402],"class_list":["post-32177","post","type-post","status-publish","format-standard","hentry","category-tutorials","tag-docker","tag-docmost","tag-self-hosted","tag-vps"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"Milan Ivanovic","author_link":"https:\/\/contabo.com\/blog\/author\/milan\/"},"uagb_comment_info":0,"uagb_excerpt":"In short. Self-hosting Docmost with Docker means running three containers, the Docmost app, PostgreSQL, and Redis, behind an Nginx reverse proxy with HTTPS. The Docmost Docker setup takes under 20 minutes on a VPS with 4 GB RAM or more. You optionally point file attachments at S3-compatible Object Storage to keep the VPS disk clean.&hellip;","authors":[{"term_id":3402,"user_id":0,"is_guest":1,"slug":"contabro","display_name":"ContaBro","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","author_category":"","user_url":"","last_name":"","first_name":"","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/32177","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/users\/44"}],"replies":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/comments?post=32177"}],"version-history":[{"count":1,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/32177\/revisions"}],"predecessor-version":[{"id":32178,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/32177\/revisions\/32178"}],"wp:attachment":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/media?parent=32177"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/categories?post=32177"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/tags?post=32177"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=32177"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}