aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CLAUDE.md6
-rw-r--r--README.md12
-rw-r--r--hosts/eurovm/default.nix1
-rw-r--r--modules/caddy.nix7
-rw-r--r--modules/memos.nix24
5 files changed, 48 insertions, 2 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 6817d40..13310d0 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -80,7 +80,7 @@ service module:
- `caddy.nix` — the main thing that binds to 80/443 (see `adguard.nix` below for the one
exception). Reverse-proxies each subdomain to a service's localhost port; the `dns.karanj.com`
vhost additionally serves the ACME HTTP-01 webroot for `acme.nix`. Application ports (5006,
- 8080, 8086) are bound to `127.0.0.1` and never exposed directly — Caddy is the public HTTP(S)
+ 5230, 8080, 8086) are bound to `127.0.0.1` and never exposed directly — Caddy is the public HTTP(S)
entry point for everything except AdGuard's encrypted-DNS ports, and handles Let's Encrypt
automatically for its own certs.
- `adguard.nix` — AdGuard Home; plain DNS (`dns.port`) is set to `0` and deliberately not opened
@@ -108,6 +108,10 @@ service module:
- `actual.nix` — Actual Budget via the native `services.actual` module (ships in this flake's
pinned nixpkgs). No secrets involved; the server password is set interactively on first
browser visit.
+- `memos.nix` — Memos note-taking app via the native `services.memos` module (ships in this
+ flake's pinned nixpkgs). Uses the module's default sqlite driver, so no separate database
+ service is needed (unlike Miniflux's Postgres). No secrets involved; the first account is
+ created interactively in the web UI on first visit.
- `cgit.nix` — git hosting. Three-way access split: web browsing is public/unauthenticated via
cgit, `git clone`/`pull` over HTTPS is public/read-only via `git-http-backend` + fcgiwrap, and
`git push` is SSH-only through a dedicated `git` system user with its own authorized keys. cgit
diff --git a/README.md b/README.md
index 6cae516..d98fdb3 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ A flake-based, modular NixOS configuration for a personal server running in Euro
| https://rss.karanj.com | Miniflux (RSS/Atom reader) |
| https://budget.karanj.com | Actual Budget (personal finance) |
| https://git.karanj.com | cgit (git repository browser) |
+| https://notes.karanj.com | Memos (note-taking) |
All services are reverse-proxied by **Caddy** with automatic TLS via Let's Encrypt.
AdGuard also listens directly on **853/tcp** for DNS-over-TLS and **8443/tcp** for
@@ -37,6 +38,7 @@ modules/
miniflux.nix Miniflux + PostgreSQL
actual.nix Actual Budget
cgit.nix cgit + fcgiwrap + git push user
+ memos.nix Memos (note-taking)
```
---
@@ -164,6 +166,7 @@ dns.karanj.com A <server-ipv4>
rss.karanj.com A <server-ipv4>
budget.karanj.com A <server-ipv4>
git.karanj.com A <server-ipv4>
+notes.karanj.com A <server-ipv4>
```
Or a single wildcard: `*.karanj.com A <server-ipv4>`.
@@ -221,6 +224,7 @@ joined to your tailnet first), then:
| Miniflux | https://rss.karanj.com | Log in with `admin` (or your `ADMIN_USERNAME`) + your sops password |
| Actual Budget | https://budget.karanj.com | Set a server password in the browser on first visit - no pre-configuration needed |
| cgit | https://git.karanj.com | No login needed - public read-only |
+| Memos | https://notes.karanj.com | Create the first account directly in the web UI on first visit |
To use the server as your device's DNS resolver, configure DNS-over-TLS or DNS-over-HTTPS as
described under [AdGuard Home](#adguard-home) below - plain DNS (port 53) is disabled.
@@ -312,6 +316,12 @@ and restart the service: `systemctl restart actual`.
- **Clone/Pull:** `git clone https://git.karanj.com/<repo>.git` (public, read-only)
- **Push:** SSH only - `git push git@<server-ipv4>:/srv/git/<repo>.git`
+### Memos
+
+Data is stored as a sqlite database under `/var/lib/memos/`. No password reset flow needed
+beyond what the web UI itself offers - it's a single-user instance with no separate admin
+credentials in this config.
+
### Caddy / TLS
TLS certificates are obtained automatically from Let's Encrypt on first startup (registered to
@@ -331,7 +341,7 @@ Caddy logs: `journalctl -u caddy -f`
| 853 | TCP | DNS-over-TLS (AdGuard Home) |
| 8443 | TCP | DNS-over-HTTPS (AdGuard Home) |
-All other ports are closed at the firewall. App-level ports (5006, 8080, 8086) are bound to
+All other ports are closed at the firewall. App-level ports (5006, 5230, 8080, 8086) are bound to
127.0.0.1 and never exposed directly. AdGuard's web UI (3000) binds all interfaces (required
so its DoH/DoT listener - which shares the same bind host - reaches the public interface),
but stays unreachable externally because the firewall never opens port 3000.
diff --git a/hosts/eurovm/default.nix b/hosts/eurovm/default.nix
index b487644..0181a07 100644
--- a/hosts/eurovm/default.nix
+++ b/hosts/eurovm/default.nix
@@ -12,6 +12,7 @@
../../modules/miniflux.nix
../../modules/actual.nix
../../modules/cgit.nix
+ ../../modules/memos.nix
];
networking.hostName = "eurovm";
diff --git a/modules/caddy.nix b/modules/caddy.nix
index f82c7f0..64418c3 100644
--- a/modules/caddy.nix
+++ b/modules/caddy.nix
@@ -37,6 +37,13 @@
'';
};
+ # Memos - note-taking app
+ "notes.karanj.com" = {
+ extraConfig = ''
+ reverse_proxy 127.0.0.1:5230
+ '';
+ };
+
# cgit - public read-only git viewer + smart HTTP for git clone/pull.
# Both cgit browsing and git-http-backend (clone/pull) are served by
# the same nginx vhost on 8086 - nginx itself routes between them by
diff --git a/modules/memos.nix b/modules/memos.nix
new file mode 100644
index 0000000..bc80e24
--- /dev/null
+++ b/modules/memos.nix
@@ -0,0 +1,24 @@
+{ config, ... }:
+
+# Memos - lightweight, privacy-first note-taking app.
+#
+# Native NixOS module (services.memos, available since this flake's pinned
+# nixpkgs release). Listens on 127.0.0.1:5230; Caddy handles public HTTPS
+# termination. Uses the module's default sqlite driver - no separate
+# database service needed, unlike Miniflux's Postgres.
+#
+# No secrets involved: the first account is created directly in the web UI
+# on first visit to https://notes.karanj.com.
+{
+ services.memos = {
+ enable = true;
+ settings = {
+ MEMOS_MODE = "prod";
+ MEMOS_ADDR = "127.0.0.1";
+ MEMOS_PORT = "5230";
+ MEMOS_DRIVER = "sqlite";
+ MEMOS_DATA = config.services.memos.dataDir;
+ MEMOS_INSTANCE_URL = "https://notes.karanj.com";
+ };
+ };
+}