profileShare

rasmusjy / profileshare

Read-only snapshot

No repository description.

main default branch 54 files Expires Sep 13, 2026, 9:06 AM

Commit

Add Docker image, compose file and deploy script for code.rasmusj.com

commit dfe884e

4 changed files with +265 and −0

Jump to a changed file
  1. DEPLOY.md +135 −0
  2. Dockerfile +32 −0
  3. deploy.sh +64 −0
  4. docker-compose.yml +34 −0
added DEPLOY.md +135 −0
@@ -0,0 +1,135 @@
1 +# profileShare juurutamine, code.rasmusj.com
2 +
3 +Eesmärk: rasmusj.com saab näidata privaatsete repode koodi ilma ühtegi repo
4 +avalikuks tegemata. Portfooliolehel on kaks linki, üks kogu hetktõmmisele ja
5 +üks iga projekti juures otse selle repo juurde.
6 +
7 +Kolm sammu, millest ainult esimest ja kolmandat pead ise tegema.
8 +
9 +---
10 +
11 +## 1. DNS ja GitHubi app (10 min, sinu teha)
12 +
13 +**DNS.** Lisa A-kirje `code.rasmusj.com` -> `YOUR_SERVER_IP`, sama IP mis
14 +ülejäänud. Oota, kuni `nslookup code.rasmusj.com` vastab.
15 +
16 +**GitHubi app.** Sul on app juba olemas ja töötab lokaalselt. Vaja on ainult
17 +kolm aadressi ümber suunata, sest need peavad olema samal origin'il kui
18 +`BASE_URL`. Ava github.com/settings/apps, vali oma app ja muuda:
19 +
20 +| Väli | Uus väärtus |
21 +|---|---|
22 +| Homepage URL | `https://code.rasmusj.com` |
23 +| Callback URL | `https://code.rasmusj.com/auth/github/callback` |
24 +| Setup URL | `https://code.rasmusj.com/github/installed` |
25 +
26 +Klienditunnust ja saladust vahetada ei ole vaja, need jäävad samaks.
27 +
28 +**Kontrolli, et app on paigaldatud kõigile portfoolio repodele.** Ava
29 +github.com/settings/installations, vali app, "Configure", ja veendu, et
30 +valitud on `splitapp`, `roundtable`, `voicetask`, `allyouknow`,
31 +`countrysense` ja `profileshare`. Kui mõni puudub, lisa.
32 +
33 +---
34 +
35 +## 2. Server (esmakordselt, minu ette valmistatud)
36 +
37 +**Caddy plokk.** Lisa `/opt/caddy/Caddyfile` faili ja lae Caddy uuesti
38 +(`docker exec caddy caddy reload --config /etc/caddy/Caddyfile`):
39 +
40 +```
41 +code.rasmusj.com {
42 + encode zstd gzip
43 + reverse_proxy profileshare:3000
44 +}
45 +```
46 +
47 +**.env serveris.** See fail elab ainult serveris, `deploy.sh` ei kirjuta seda
48 +kunagi üle. Loo see kord:
49 +
50 +```bash
51 +mkdir -p /opt/projects/profileshare
52 +cat > /opt/projects/profileshare/.env <<'EOF'
53 +GITHUB_CLIENT_ID=...
54 +GITHUB_CLIENT_SECRET=...
55 +GITHUB_APP_SLUG=...
56 +NODE_ENV=production
57 +SESSION_SECRET=...
58 +BASE_URL=https://code.rasmusj.com
59 +PORT=3000
60 +DATABASE_PATH=data/profileshare.db
61 +EOF
62 +chmod 600 /opt/projects/profileshare/.env
63 +```
64 +
65 +Kolm esimest väärtust kopeeri oma lokaalsest `.env` failist. **`SESSION_SECRET`
66 +genereeri uus**, sest serveri andmebaas on uus ja lokaalse seansisaladuse
67 +kaasa vedamine ei anna midagi peale ühe lisakoha, kust see lekkida saab:
68 +
69 +```bash
70 +node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
71 +```
72 +
73 +Lokaalset `data/profileshare.db` faili serverisse ei kopeerita. Selles on
74 +neli aegunud hetktõmmist ja mõtet neid kaasa tuua ei ole.
75 +
76 +**Juuruta:**
77 +
78 +```bash
79 +./deploy.sh
80 +```
81 +
82 +Skript jooksutab enne saatmist testid, keeldub tööst kui `.env` puudub, ja
83 +ootab lõpus, kuni tervisekontroll roheliseks läheb.
84 +
85 +---
86 +
87 +## 3. Hetktõmmis ja lingid portfooliolehele (5 min, sinu teha)
88 +
89 +1. Ava `https://code.rasmusj.com`, logi GitHubiga sisse.
90 +2. Vali kõik kuus repot: `splitapp`, `roundtable`, `voicetask`, `allyouknow`,
91 + `countrysense`, `profileshare`.
92 +3. Vali kehtivusaeg. **Võta 365 päeva.** Praktikakohta otsid mitu kuud ja
93 + kirjades olev link peab veel siis töötama, kui keegi selle kolm nädalat
94 + hiljem avab.
95 +4. Kopeeri loodud link. See on kujul `https://code.rasmusj.com/s/<shareId>`.
96 +5. Saada see link mulle, siis panen portfooliolehele paika. Või tee ise:
97 + `portfolio/lib/content.ts`, väli `codeAccess.url`.
98 +
99 +**Repo ID-d.** Kolm on juba teada, need on GitHubi püsivad numbrid ja neid ei
100 +pea uuesti otsima:
101 +
102 +| Projekt | repoId |
103 +|---|---|
104 +| roundtable | `1296615860` |
105 +| countrysense | `1299668802` |
106 +| voicetask | `1309047169` |
107 +
108 +Puudu on `splitapp`, `allyouknow` ja `profileshare`. Need saab kätte nii: ava
109 +hetktõmmises see repo ja vaata aadressi lõppu, `/repositories/<number>`.
110 +
111 +---
112 +
113 +## Kui link aegub
114 +
115 +Tee töölaual uus hetktõmmis ja asenda portfoolios **üks rida**,
116 +`codeAccess.url`. Repo ID-d on püsivad ja neid ei pea puutuma, sest
117 +projektilingid ehitatakse kokku funktsiooniga `repoUrl()`.
118 +
119 +Kui link on aegunud ja uut ei ole, kaovad koodilingid lehelt ise ära ja tekst
120 +läheb tagasi variandile "küsi ja saadan lingi". Katkist linki leht kunagi ei
121 +näita.
122 +
123 +## Kust mida vaadata
124 +
125 +```bash
126 +docker logs -f profileshare # logid
127 +docker inspect -f '{{.State.Health.Status}}' profileshare
128 +docker exec profileshare ls -la /app/data # andmebaas on siin
129 +```
130 +
131 +Varundus on ühe faili kopeerimine:
132 +
133 +```bash
134 +docker cp profileshare:/app/data/profileshare.db ./profileshare-backup.db
135 +```
added Dockerfile +32 −0
@@ -0,0 +1,32 @@
1 +# syntax=docker/dockerfile:1
2 +
3 +# Node 24 because the app stores everything through `node:sqlite`, which is
4 +# built in from 22 and stable from 24. That is also why there is no build stage
5 +# and no compiler in this image: every dependency is plain JavaScript, so there
6 +# is no native module to compile and nothing to bundle.
7 +FROM node:24-bookworm-slim
8 +WORKDIR /app
9 +
10 +ENV NODE_ENV=production
11 +ENV PORT=3000
12 +
13 +COPY package*.json ./
14 +RUN npm ci --omit=dev
15 +
16 +COPY src ./src
17 +
18 +# The SQLite file lives in a named volume mounted here. It has to belong to the
19 +# `node` user, because the container does not run as root.
20 +RUN mkdir -p /app/data && chown -R node:node /app/data
21 +
22 +USER node
23 +
24 +EXPOSE 3000
25 +
26 +# Node 24 has global fetch, so the slim image needs no curl for this. The root
27 +# path renders the sign-in page and touches the database, so a 200 here means
28 +# both the server and its storage are alive.
29 +HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
30 + CMD node -e "fetch('http://127.0.0.1:3000/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
31 +
32 +CMD ["npm", "start"]
added deploy.sh +64 −0
@@ -0,0 +1,64 @@
1 +#!/usr/bin/env bash
2 +# One-command redeploy for code.rasmusj.com.
3 +#
4 +# Ships the source to the VPS, rebuilds the image there and restarts the
5 +# container. Run from Git Bash on Windows: ./deploy.sh
6 +#
7 +# Two things this script deliberately never touches:
8 +#
9 +# .env lives on the server only. It holds the GitHub App secret and the
10 +# session secret, and overwriting it from here would eventually
11 +# push a stale copy over a good one.
12 +# Caddyfile the shared reverse-proxy config at /opt/caddy. First-time setup
13 +# is done once by hand, so a routine redeploy cannot take other
14 +# sites down with it.
15 +#
16 +# The SQLite database is in a named Docker volume, so it survives every rebuild.
17 +set -euo pipefail
18 +
19 +VPS=user@host
20 +DEST=/opt/projects/profileshare
21 +
22 +cd "$(dirname "$0")"
23 +
24 +echo "==> Running the test suite before shipping anything..."
25 +npm test
26 +
27 +echo "==> Ensuring VPS project dir exists..."
28 +ssh "$VPS" "mkdir -p '$DEST'"
29 +
30 +echo "==> Checking that .env exists on the server..."
31 +if ! ssh "$VPS" "test -f '$DEST/.env'"; then
32 + echo ""
33 + echo " $DEST/.env is missing. Create it on the server first, see DEPLOY.md."
34 + echo " Nothing has been changed."
35 + exit 1
36 +fi
37 +
38 +echo "==> Uploading source (node_modules, data and .env stay out of it)..."
39 +tar --exclude=node_modules --exclude=data --exclude=.env --exclude=.git \
40 + --exclude=coverage -czf - . | ssh "$VPS" "
41 + rm -rf '$DEST/src.tmp' &&
42 + mkdir -p '$DEST/src.tmp' &&
43 + tar -C '$DEST/src.tmp' -xzf - &&
44 + cp '$DEST/.env' '$DEST/src.tmp/.env' &&
45 + rm -rf '$DEST/app' &&
46 + mv '$DEST/src.tmp' '$DEST/app'
47 +"
48 +
49 +echo "==> Rebuilding and restarting the container..."
50 +ssh "$VPS" "cd '$DEST/app' && docker compose up -d --build"
51 +
52 +echo "==> Waiting for the health check to go green..."
53 +ssh "$VPS" "
54 + for i in \$(seq 1 20); do
55 + state=\$(docker inspect -f '{{.State.Health.Status}}' profileshare 2>/dev/null || echo starting)
56 + [ \"\$state\" = healthy ] && echo ' healthy' && exit 0
57 + sleep 3
58 + done
59 + echo ' still not healthy, check: docker logs profileshare'
60 + exit 1
61 +"
62 +
63 +echo ""
64 +echo "==> Done. Live at https://code.rasmusj.com"
added docker-compose.yml +34 −0
@@ -0,0 +1,34 @@
1 +# code.rasmusj.com, profileShare.
2 +#
3 +# Same shape as the other projects on this host: Caddy already runs on the
4 +# external `web` network and terminates TLS, so nothing here is published to
5 +# the host directly. The container is only reachable through the proxy.
6 +#
7 +# The domain lives in the Caddyfile alone. Changing it never touches this file.
8 +
9 +services:
10 + profileshare:
11 + build: .
12 + container_name: profileshare
13 + restart: unless-stopped
14 + env_file: .env
15 + volumes:
16 + # The snapshots and the owner session live in one SQLite file. Backing up
17 + # is copying the volume; there is nothing else to keep.
18 + - profileshare-data:/app/data
19 + networks:
20 + - web
21 + expose:
22 + - "3000"
23 + logging:
24 + driver: json-file
25 + options:
26 + max-size: "10m"
27 + max-file: "3"
28 +
29 +volumes:
30 + profileshare-data:
31 +
32 +networks:
33 + web:
34 + external: true