Drop the compose file and systemd unit for the sync server
The server is a single process, so a compose file that only wrapped one
container added a second way to do the same thing. Docker is now the one
documented path, pointing at a Postgres that lives outside the container.
💘 Generated with Crush
Assisted-by: Crush:kimi-k3
This commit is contained in:
@@ -42,12 +42,11 @@ clicking an item copies it back to the clipboard.
|
|||||||
code and server URL in `UserDefaults` (`sync.code`, `sync.serverURL`,
|
code and server URL in `UserDefaults` (`sync.code`, `sync.serverURL`,
|
||||||
`sync.version`), pushes the whole store as JSON, and polls every 5s.
|
`sync.version`), pushes the whole store as JSON, and polls every 5s.
|
||||||
- `Server/main.go` — the Go sync backend (single file, `net/http` + `lib/pq`).
|
- `Server/main.go` — the Go sync backend (single file, `net/http` + `lib/pq`).
|
||||||
Also ships `Server/Dockerfile` + `Server/docker-compose.yml` (Postgres +
|
Also ships `Server/Dockerfile` (static binary on distroless) and
|
||||||
server), `Server/README.md` (self-hosting), and `Server/prompt-sync.service`
|
`Server/README.md` (self-hosting). Logs one line per request, creates its
|
||||||
(systemd unit). Logs one line per request, creates its schema on startup,
|
schema on startup, shuts down gracefully on SIGTERM so a redeploy cannot cut
|
||||||
shuts down gracefully on SIGTERM so a redeploy cannot cut off a push, and
|
off a push, and supports `-healthcheck` (pings local `/healthz`) so the
|
||||||
supports `-healthcheck` (pings local `/healthz`) so the distroless image
|
shell-less image needs no curl for its Docker `HEALTHCHECK`.
|
||||||
needs no shell for its Docker `HEALTHCHECK`.
|
|
||||||
|
|
||||||
## Sync protocol
|
## Sync protocol
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,9 @@ PROMPT_SYNC_DATABASE_URL="postgres://localhost:5432/prompt_sync?sslmode=disable"
|
|||||||
go run . # listens on :8080
|
go run . # listens on :8080
|
||||||
```
|
```
|
||||||
|
|
||||||
Or run it with Docker (`POSTGRES_PASSWORD=… docker compose up -d`) — see
|
Or build the Docker image (`docker build -t prompt-sync Server/`) and point it
|
||||||
[Server/README.md](Server/README.md) for that and for deploying to a VPS.
|
at your own Postgres — see [Server/README.md](Server/README.md) for that and for
|
||||||
|
deploying to a host.
|
||||||
|
|
||||||
Then in the panel: click the sync icon, set the server URL (e.g.
|
Then in the panel: click the sync icon, set the server URL (e.g.
|
||||||
`http://192.168.1.10:8080` or an HTTPS host), and either **Generate Code** on
|
`http://192.168.1.10:8080` or an HTTPS host), and either **Generate Code** on
|
||||||
|
|||||||
+22
-23
@@ -30,41 +30,40 @@ in-flight push is not cut off mid-write.
|
|||||||
|
|
||||||
## Run with Docker
|
## Run with Docker
|
||||||
|
|
||||||
`docker-compose.yml` starts Postgres and the server together:
|
The image is a static binary on `distroless` (non-root, no shell), so its
|
||||||
|
`HEALTHCHECK` calls `prompt-sync -healthcheck`, which pings the local
|
||||||
```bash
|
`/healthz` — no curl needed in the image. That is what `docker ps` reports as
|
||||||
cd Server
|
the container health.
|
||||||
POSTGRES_PASSWORD=$(openssl rand -hex 16) docker compose up -d
|
|
||||||
docker compose logs -f server # request log
|
|
||||||
```
|
|
||||||
|
|
||||||
Or build the image on its own and point it at an existing Postgres:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t prompt-sync Server/
|
docker build -t prompt-sync Server/
|
||||||
docker run -d --name prompt-sync -p 8080:8080 \
|
docker run -d --name prompt-sync -p 8080:8080 \
|
||||||
-e PROMPT_SYNC_DATABASE_URL="postgres://user:pass@host:5432/prompt_sync?sslmode=disable" \
|
-e PROMPT_SYNC_DATABASE_URL="postgres://user:pass@host:5432/prompt_sync?sslmode=disable" \
|
||||||
prompt-sync
|
prompt-sync
|
||||||
|
|
||||||
|
docker logs -f prompt-sync # request log
|
||||||
```
|
```
|
||||||
|
|
||||||
The image is a static binary on `distroless` (non-root, no shell, ~6 MB binary),
|
Postgres stays outside the container; the server only needs a URL. If Postgres
|
||||||
so its `HEALTHCHECK` calls `prompt-sync -healthcheck`, which pings the local
|
runs on the Docker host itself, `host` is `host.docker.internal` on macOS and
|
||||||
`/healthz` and exits non-zero on failure — no curl needed in the image. That is
|
Windows, or the host's LAN address on Linux (`--network host` also works).
|
||||||
what `docker ps` reports as the container health.
|
|
||||||
|
|
||||||
## Deploy to a Linux host
|
## Deploy to a host
|
||||||
|
|
||||||
|
Build for the host's architecture and ship the image, or build it on the host
|
||||||
|
itself (a `git clone` plus `docker build` is usually simplest):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# from the repo root, on the Mac
|
# build on the Mac for a linux/arm64 host, then copy it over
|
||||||
cd Server
|
docker build --platform linux/arm64 -t prompt-sync Server/
|
||||||
GOOS=linux GOARCH=arm64 go build -o prompt-sync . # amd64 for x86 hosts
|
docker save prompt-sync | gzip > prompt-sync.tar.gz
|
||||||
scp prompt-sync <host>:/tmp/ && ssh <host> 'sudo mv /tmp/prompt-sync /usr/local/bin/'
|
scp prompt-sync.tar.gz <host>:
|
||||||
|
ssh <host> 'gunzip -c prompt-sync.tar.gz | docker load'
|
||||||
|
|
||||||
# on the host: create the database and role, then
|
ssh <host> 'docker run -d --name prompt-sync --restart unless-stopped \
|
||||||
sudo cp Server/prompt-sync.service /etc/systemd/system/
|
-p 8080:8080 \
|
||||||
sudo systemctl edit --full prompt-sync # set PROMPT_SYNC_DATABASE_URL
|
-e PROMPT_SYNC_DATABASE_URL="postgres://user:pass@db-host:5432/prompt_sync?sslmode=disable" \
|
||||||
sudo systemctl enable --now prompt-sync
|
prompt-sync'
|
||||||
journalctl -u prompt-sync -f # verify it is listening
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Put it behind TLS if it is reachable from the internet — the code is the only
|
Put it behind TLS if it is reachable from the internet — the code is the only
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
# Postgres + the sync server. `docker compose up -d` is the whole deploy:
|
|
||||||
#
|
|
||||||
# POSTGRES_PASSWORD=$(openssl rand -hex 16) docker compose up -d
|
|
||||||
#
|
|
||||||
# Then point the app at http://<host>:8080. The data lives in the named volume,
|
|
||||||
# so `docker compose down` keeps it and `down -v` wipes it.
|
|
||||||
|
|
||||||
services:
|
|
||||||
db:
|
|
||||||
image: postgres:18-alpine
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: prompt_sync
|
|
||||||
POSTGRES_USER: prompt
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
|
|
||||||
volumes:
|
|
||||||
- prompt-db:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U prompt -d prompt_sync"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
server:
|
|
||||||
build: .
|
|
||||||
environment:
|
|
||||||
PROMPT_SYNC_ADDR: ":8080"
|
|
||||||
PROMPT_SYNC_DATABASE_URL: postgres://prompt:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/prompt_sync?sslmode=disable
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
prompt-db:
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Prompt sync server
|
|
||||||
Documentation=https://gitea.tzgyn.dev/TZGyn/prompt
|
|
||||||
After=network-online.target postgresql.service
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
# The binary is built on a Mac with:
|
|
||||||
# GOOS=linux GOARCH=arm64 go build -o prompt-sync .
|
|
||||||
ExecStart=/usr/local/bin/prompt-sync
|
|
||||||
Environment=PROMPT_SYNC_ADDR=:8080
|
|
||||||
Environment=PROMPT_SYNC_DATABASE_URL=postgres://prompt:CHANGE_ME@localhost:5432/prompt_sync?sslmode=disable
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=2
|
|
||||||
# The server only needs to talk to Postgres and bind :8080.
|
|
||||||
NoNewPrivileges=true
|
|
||||||
PrivateTmp=true
|
|
||||||
ProtectSystem=strict
|
|
||||||
ProtectHome=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
Reference in New Issue
Block a user