diff --git a/README.md b/README.md index 2370e77..095ed1c 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ no database, no data leaving your machine except the requests you send to Ollama - [Changing models](#changing-models) - [Checking the connection](#checking-the-connection) - [Running on your network / from your phone](#running-on-your-network--from-your-phone) + - [Keep it running as a service](#keep-it-running-as-a-service-systemd-user-service) - [Folders](#folders) - [Install as an app (PWA)](#install-as-an-app-pwa) - [Security notes](#security-notes) @@ -378,6 +379,37 @@ Notes for phones: - Clipboard paste works best on desktop; on mobile use the camera or photo picker. - Add the page to your home screen for a full-screen, app-like experience. +### Keep it running as a service (systemd user service) + +`deploy/freezmo.service` runs the production build under **systemd (user)**, so Freezmo comes back by +itself after a reboot and restarts if it ever crashes: + +```bash +npm run build # the service serves the built app +mkdir -p ~/.config/systemd/user +cp deploy/freezmo.service ~/.config/systemd/user/ +systemctl --user daemon-reload +systemctl --user enable --now freezmo.service +loginctl enable-linger "$USER" # start at boot without logging in +``` + +| Command | What it does | +| --- | --- | +| `systemctl --user status freezmo` | is it up? | +| `journalctl --user -u freezmo -f` | live logs | +| `systemctl --user restart freezmo` | after a rebuild | +| `systemctl --user stop freezmo` | stop it | + +It binds `0.0.0.0:3207` exactly like `npm start` and reads `.env.local` from the project directory. +The unit refuses to start without `.next/BUILD_ID`, so run `npm run build` before enabling it — and +again after pulling changes. + +Because the build and the running server share `.next/`, stop the service before a manual rebuild: + +```bash +systemctl --user stop freezmo && npm run build && systemctl --user start freezmo +``` + --- ## Folders @@ -580,6 +612,8 @@ public/ icons/ PWA + iOS icons and splash screens assets/ app-icon-source.jpeg master artwork the icons are rendered from +deploy/ + freezmo.service systemd user unit (auto-start at boot) scripts/ copy-pdf-worker.mjs copies the pdf.js worker to /public (runs on predev/prebuild) make-icons.mjs regenerates the PWA/iOS icons from the master (one-off tool) diff --git a/deploy/freezmo.service b/deploy/freezmo.service new file mode 100644 index 0000000..87f115e --- /dev/null +++ b/deploy/freezmo.service @@ -0,0 +1,33 @@ +[Unit] +# Freezmo — self-hosted notes-to-study-feed app. +# Install (per user, no root needed): +# mkdir -p ~/.config/systemd/user +# cp deploy/freezmo.service ~/.config/systemd/user/ +# systemctl --user daemon-reload +# systemctl --user enable --now freezmo.service +# loginctl enable-linger "$USER" # start at boot without logging in +# Logs: journalctl --user -u freezmo -f +Description=Freezmo (self-hosted study app) +Documentation=file://%h/freezmo/README.md +After=network-online.target +Wants=network-online.target +# In OLLAMA_AUTH=local mode the daemon should be up first (no-op otherwise). +After=ollama.service + +[Service] +Type=simple +WorkingDirectory=%h/freezmo +Environment=NODE_ENV=production +Environment=NEXT_TELEMETRY_DISABLED=1 +Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +# Refuse to start without a production build — clearer than next crashing in a +# restart loop. Run `npm run build` in %h/freezmo first. +AssertPathExists=%h/freezmo/.next/BUILD_ID +# Next.js loads .env.local (OLLAMA_*) from the working directory itself. +ExecStart=/bin/node %h/freezmo/node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3207 +Restart=always +RestartSec=3 +TimeoutStartSec=0 + +[Install] +WantedBy=default.target