From 19bb92d4f2565f72c8577d04fc937a0dd3f5a9a2 Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Sun, 8 Nov 2026 15:22:09 -0500 Subject: [PATCH] Deploy with git pull on the server The server reads the private repository with its own read-only deploy key, then pulls and rebuilds. The README no longer tells you to copy a local working tree to the server. Git and Docker ignore backups/. Co-Authored-By: Claude Opus 5.5 --- .dockerignore | 1 + .gitignore | 1 + README.md | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index 451b81f..e7372dc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,3 +4,4 @@ dist .env *.sqlite* *.csv +backups/ diff --git a/.gitignore b/.gitignore index c063061..db969cb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist/ .env .DS_Store *.csv +backups/ diff --git a/README.md b/README.md index 03bb94a..8280a5f 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,26 @@ SQLite is an embedded database, so there is no useful separate SQLite server ima 1. Create a [GitHub OAuth app](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) with homepage `https://timelog.minhtrannhat.com` and callback `https://timelog.minhtrannhat.com/auth/github/callback`. Disable callback URL wildcard matching. This app asks for no OAuth scopes and uses your stable numeric GitHub user ID as its allowlist. You can find the ID at `https://api.github.com/users/YOUR_LOGIN`. 2. Copy `.env.example` to `.env` on the server and set `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, and `GITHUB_ALLOWED_ID`. Run `bun run vapid` once to generate push keys and put its three values in `.env`. Keep `.env` private (`chmod 600 .env`). -3. Copy this project to `~/apps/timelog` on the server, excluding `node_modules`, `dist`, local SQLite files, and the original Forest CSV. Run `docker compose up -d --build` there. +3. The repository is private, so the server reads it with its own read-only deploy key. Run `ssh-keygen -t ed25519 -N "" -C "vps deploy key: timelog" -f ~/.ssh/gitea_timelog` on the server, and add `~/.ssh/gitea_timelog.pub` in Gitea under the repository's **Settings → Deploy Keys** (leave write access off). Then clone the repository to `~/apps/timelog` and run `docker compose up -d --build` there: + + ```sh + git clone -c core.sshCommand="ssh -i ~/.ssh/gitea_timelog -o IdentitiesOnly=yes" ssh://git@ssh.minhtrannhat.com:8089/minhtrannhat/timelog.git ~/apps/timelog + ``` 4. Install [deploy/nginx.conf](deploy/nginx.conf) as `/etc/nginx/sites-enabled/timelog.conf`, run `sudo nginx -t`, then `sudo systemctl reload nginx`. The server already has Nginx and Docker Compose; this config routes the subdomain to the loopback web port. Ensure the subdomain's DNS points through the existing Cloudflare setup before using the public URL. 5. Sign in at `https://timelog.minhtrannhat.com`, open Settings, and import the Forest CSV. The supplied file has 2,709 sessions; re-imports skip identical records. Export there whenever you want a Forest-shaped copy of the log. Do not publish the site before the OAuth credentials and allowed GitHub ID are set. The API rejects data requests without a valid session cookie and only accepts writes from `PUBLIC_ORIGIN`. +To deploy a new version, push it to Gitea, then pull and rebuild on the server. Back up the database first (see below). + +```sh +cd ~/apps/timelog +git pull --ff-only +docker compose up -d --build +``` + +Deploy only from pushed commits. Do not copy files from a local working tree to the server. + To back up the database consistently while it is running: ```sh