All articles
TutorialsApr 27, 2026 · 19 min read

Self-Host Memos on a VPS for a Personal Microblog

Self-Host Memos on a VPS for a Personal Microblog

Most note apps want to be a second brain. Memos wants to be a feed. You drop short markdown thoughts into a chronological timeline, tag them, and search later. It feels closer to a private Twitter or Mastodon than to Logseq or Obsidian, which is exactly why it works for the kind of notes you would otherwise lose in Slack DMs to yourself.

Memos is open source, written in Go, ships as a single binary, and the Docker image runs comfortably on a 256 MB VPS. SQLite is the default store, so there's no separate database container to manage. This guide gets you from a fresh server to a working public URL with HTTPS, your own admin account, registrations locked down, and the iOS or Android app pointed at it.

TL;DR

  • Install Docker and Docker Compose on a small VPS
  • Point a subdomain like notes.example.com at the server
  • Run neosmemo/memos:stable behind Caddy in one docker-compose.yml
  • Sign up as the first user (who becomes Host), then disable open registration
  • Install the iOS or Android client and connect to your URL
  • Back up the SQLite file in the persistent volume daily

Total time: about 15 minutes.

What You Need

  • A VPS with at least 256 MB RAM (512 MB is comfortable) running Ubuntu 22.04 or 24.04
  • A domain or subdomain you can point at the server
  • Ports 80 and 443 open to the internet for Let's Encrypt
  • Root or sudo access

Memos is genuinely tiny. On an idle server it sits around 40 MB of RAM with a few hundred notes. If you're already running other Docker workloads, this slots in alongside them.

How Memos Differs from Logseq and Obsidian

Quick orientation, because the question always comes up:

  • Logseq and Obsidian are outliner and graph tools. Notes are atomic, linked, and meant to be reorganized. The unit of thought is a page or block.
  • Memos is chronological short-form. The unit of thought is a timestamped post. Tags and search replace folder hierarchies. There's no graph, no daily journal scaffolding, no sync-the-vault dance.

Think of Memos as a personal microblog you can also publish from. Many people run all three side by side: Obsidian for long-form, Memos for stream-of-consciousness, and a dedicated bookmark app for links.

Step 1: Point a Subdomain at Your VPS

In your DNS provider, add an A record:

notes.example.com → YOUR_VPS_IPV4

Add an AAAA record if you use IPv6. Verify it resolves:

dig +short notes.example.com

DNS has to point at your VPS before Caddy can fetch a certificate.

Step 2: Install Docker and Docker Compose

On a fresh Ubuntu box:

sudo apt update sudo apt install -y ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Confirm:

docker --version docker compose version

Step 3: Open the Firewall

If you use UFW:

sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable

Caddy needs port 80 for the ACME HTTP challenge and 443 for HTTPS.

Step 4: Create the Project Directory

sudo mkdir -p /opt/memos cd /opt/memos sudo mkdir -p memos-data caddy-data caddy-config

Everything persistent lives under /opt/memos. If you back up this one directory, you can rebuild the stack on any host.

Step 5: Write the Compose File

Memos is a single container. No database service to run, no Redis, no migrations to babysit. Create /opt/memos/docker-compose.yml:

services: memos: image: neosmemo/memos:stable container_name: memos restart: unless-stopped volumes: - ./memos-data:/var/opt/memos networks: - memos-net caddy: image: caddy:2 container_name: memos-caddy restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - ./caddy-data:/data - ./caddy-config:/config networks: - memos-net networks: memos-net:

A few notes:

  • The Memos container exposes port 5230 internally. We do not publish it on the host because Caddy reaches it on the Docker network.
  • The volume mount ./memos-data:/var/opt/memos is the entire data set: SQLite database, uploaded images, and any attached files.
  • neosmemo/memos:stable is the recommended image tag for production. The latest tag tracks the dev branch and breaks more often.

Step 6: Write the Caddyfile

Create /opt/memos/Caddyfile:

notes.example.com { encode zstd gzip reverse_proxy memos:5230 }

Caddy will request a Let's Encrypt certificate for notes.example.com automatically on first boot. No extra config needed.

Step 7: Start the Stack

cd /opt/memos sudo docker compose up -d sudo docker compose logs -f

Watch the logs until Caddy reports the certificate was issued. Then open https://notes.example.com in a browser. You should see the Memos sign-up screen.

Step 8: Create the Host Account

The first account you create on a fresh Memos install is automatically promoted to Host, which is the equivalent of root admin. Sign up with the username and password you want to keep.

Once you're in, you'll see the timeline view, an empty editor, and the side rail with tags and explore tabs. The keyboard shortcut to post is Ctrl+Enter (or Cmd+Enter on macOS).

The very next thing you should do is lock down public registration. By default, any visitor can create an account on your instance. Until you turn that off, you're running an open writable service on the public internet.

Step 9: Disable Public Registration

In the Memos web UI:

  1. Click your avatar in the bottom-left, then Settings.
  2. Open the Workspace tab (only visible to Host accounts).
  3. Find Disallow user registration (or Disable signup, depending on version) and toggle it on.
  4. Save.

To add other users later, the Host account can create them manually from the same Workspace settings panel under Members.

While you're in Workspace settings, also confirm:

  • Disable password login stays off unless you have an SSO provider set up.
  • Visibility default is set to Private, so new memos don't accidentally land on a public timeline.

Step 10: Install the Mobile App

Memos has community iOS and Android clients that talk to your server over the same REST API the web UI uses.

  • iOS: the Memos app on the App Store. On first launch, tap Sign In, enter https://notes.example.com as the host, then your username and password.
  • Android: Moememos on Google Play or F-Droid. Same flow: server URL plus credentials.

For both apps, the URL must be the full https://... form. If the client refuses to log in, double-check that your domain is reachable in a browser first. The phone never sees a more lenient version of TLS than your laptop does.

Step 11: Tagging and Search Basics

Memos uses inline hashtags, like a microblog. Three things worth knowing on day one:

  • #tag anywhere in a memo creates that tag automatically. The sidebar lists tags by frequency.
  • Nested tags work with /, for example #books/2026 and #books/wishlist. The sidebar groups them in a tree.
  • The search bar across the top accepts plain keywords, tag filters (tag:books), and date filters (from:2026-04-01 to:2026-04-30).

Visibility per memo is set with the dropdown next to the post button:

  • Private: only you can see it.
  • Workspace: other users on your instance can see it.
  • Public: anyone with the direct link can see it, and it shows up on the public Explore page if that's enabled.

A handy pattern is to tag work-in-progress items #inbox, then sweep the inbox view once a day and either delete, retag, or expand them.

Step 12: Back Up the Volume

The SQLite file in /opt/memos/memos-data is the single source of truth. Lose it and you've lost everything.

The SQLite file in your volume IS your entire data set. Memos has no cloud, no replication, no second copy by default. If the disk dies and you have no backup, the notes are gone. Set up the cron job in this step before you start writing notes you care about.

Create /usr/local/bin/memos-backup.sh:

#!/usr/bin/env bash set -euo pipefail BACKUP_DIR="/var/backups/memos" DATE="$(date +%F-%H%M)" mkdir -p "$BACKUP_DIR" docker exec memos sqlite3 /var/opt/memos/memos_prod.db ".backup '/var/opt/memos/memos.backup.db'" tar -czf "$BACKUP_DIR/memos-$DATE.tar.gz" -C /opt/memos memos-data find "$BACKUP_DIR" -name "memos-*.tar.gz" -mtime +14 -delete

The sqlite3 .backup command produces a consistent snapshot even while Memos is running, which is safer than tarring the live database file.

Make it executable and schedule a daily run:

sudo chmod +x /usr/local/bin/memos-backup.sh echo "20 3 * * * root /usr/local/bin/memos-backup.sh" | \ sudo tee /etc/cron.d/memos-backup

For off-site safety, sync /var/backups/memos to S3, Backblaze B2, or another VPS using rclone on the same schedule.

To restore: stop the stack, replace memos-data/ with the contents of a backup, start the stack again.

Step 13: Upgrade Memos Safely

Memos ships frequent point releases. The safe upgrade path:

cd /opt/memos sudo docker compose pull sudo docker compose up -d

Always take a fresh backup first. Across major releases the schema occasionally changes, and rolling back is much easier with a known-good snapshot than with a half-migrated database.

Optional: Put Memos Behind a VPN

A personal microblog that no one else needs to read is a great candidate for VPN-only access. Pair this with our Tailscale guide so notes.example.com only resolves and answers inside your tailnet. The mobile clients work fine over WireGuard or Tailscale.

Troubleshooting

Caddy returns 502 Bad Gateway. The Memos container hasn't fully started, or it crashed on boot. Check sudo docker compose logs memos. Usually a permissions issue on the volume - run sudo chown -R 1000:1000 /opt/memos/memos-data and restart.

Login loop after upgrading Caddy. The browser cookie was set with Secure over a connection Caddy now serves slightly differently. Hard-refresh, then clear cookies for notes.example.com. If it persists, check that the Caddyfile still has only the apex notes.example.com { block and isn't redirecting to a different host.

Image uploads fail with permission errors. Memos writes uploads under /var/opt/memos/assets. Inside the container that path needs to be writable by UID 1000. Same fix as above: sudo chown -R 1000:1000 /opt/memos/memos-data.

API key returns 401 Unauthorized. Memos API tokens are bound to a specific user. If you regenerated one in the UI, the old value is dead immediately. Send the token as a Bearer header: Authorization: Bearer YOUR_TOKEN. Some scripts mistakenly send it as Token YOUR_TOKEN, which the server rejects.

Caddy fails to issue a certificate. DNS hasn't propagated, or 80/443 are blocked by your provider. Verify with dig +short notes.example.com and curl -I http://notes.example.com.

Going Further

  • Automate posts with the REST API. Memos exposes a documented API at /api/v1/.... Generate a token in Settings → My Account → Access Tokens, then post a memo from anywhere with curl -H "Authorization: Bearer $TOKEN" -d '{"content":"hello"}' https://notes.example.com/api/v1/memos. Great for shortcuts on iOS, browser bookmarklets, or shell aliases.
  • Subscribe to your own RSS feed. Public memos are exposed at https://notes.example.com/u/USERNAME/rss.xml. Plug it into any reader to get a chronological feed of your public posts, or use it to syndicate to a static site.
  • Mobile clients beyond the official one. Moememos on iOS and Android both support multiple accounts, drafts, and image uploads, and they pair well with iOS Shortcuts.
  • Add Linkding for bookmarks. Memos is great at thoughts, less great at storing dozens of URLs. Linkding is the bookmark equivalent: same single-container philosophy, same Caddy reverse-proxy pattern, separate subdomain. The two complement each other nicely.

Self-hosted Memos is the kind of tool you forget about for weeks because it just runs. A few hundred notes in, the timeline plus tag search becomes the easiest place to write down anything that doesn't deserve a full markdown page.


Looking for a small VPS that fits a stack like this without breaking a sweat? Our Linux plans include fast NVMe storage, IPv6, and plenty of headroom for Docker workloads. See the options.