run your own self destructing note service
- Java 17 or newer (21 recommended; required by Ring / Jetty 12)
- Clojure CLI (
clj/clojure) - PostgreSQL available over TCP with a role/password your JDBC URL can use
Copy the local example, then edit values to match your machine:
cp dev.env.example .env.env is gitignored. On startup the app loads it automatically for any
variables not already set in the process environment (so exported env vars
and CI/production still win). The example includes:
DATABASE_URL— JDBC URL with user/password (not Unix peer auth)DATABASE_ENCRYPTION_KEY— key used to encrypt messages at restSESSION_COOKIE_KEY— must be exactly 16 characters/bytesENABLE_WORKERS— setfalselocally unless you want the expiry worker running
Create a Postgres role and database that match dev.env.example (user/password
selfdestruct / selfdestruct):
createuser selfdestruct
psql -c "ALTER USER selfdestruct WITH PASSWORD 'selfdestruct';"
createdb -O selfdestruct self-destruct-dev
clj -M:migrateIf you use a different role, update DATABASE_URL in .env. JDBC connections
use TCP auth; peer auth via Unix sockets is not used.
After migrations have been applied:
clj -M:dev-mainThat starts Garden CSS auto-compile and the Ring server (default port 8000).
Equivalent pieces if you prefer to run them separately:
clj -M:css watch
clj -M:run -- --port 8000:run uses the production entrypoint (-main). :dev-main uses
-dev-main with Ring reload.
./run-tests-local.shThis recreates self-destruct-test, runs migrations, then clj -M:test.
Ensure your Postgres role can create that database (or create it yourself and
point DATABASE_URL at it).
Pull requests and pushes to master run on GitHub Actions (.github/workflows/ci.yml):
Postgres service, clj -M:migrate, clj -M:test, and an uberjar build.
- Migratus handles schema changes; files live in
resources/migrations. - Create a new pair of
*.up.sql/*.down.sqlfiles underresources/migrations(timestamp prefix, e.g.20260731120000-add-thing.up.sql). - Apply migrations with
clj -M:migrateorjava -jar target/self-destruct.jar --migratein production.
clj -T:build uberWrites target/self-destruct.jar (compiles Garden CSS first, then AOT + uberjar).
For FreeBSD production deploy (app user, rc.d, nginx, certbot, backups), see
DEPLOYMENT_FREEBSD.md and the scripts under scripts/.
Required environment variables (also listed in .env.example):
DATABASE_URLDATABASE_ENCRYPTION_KEYPORTSESSION_COOKIE_KEY(exactly 16 characters/bytes)
Optional:
HOST(e.g.127.0.0.1so Jetty only accepts local/nginx traffic)REPORTED_LOG_LEVEL(defaults towarn; min level for Sentry when enabled)LOG_APPENDER(printlnorsentry)SENTRY_DSN(required only whenLOG_APPENDER=sentry)ENABLE_WORKERS(defaults to enabled; setfalseto disable background workers)MESSAGE_EXPIRE_MINUTES(defaults to1440/ 24 hours)WORKER_DELAY_SECONDS(defaults to3600/ 1 hour)SECURE_DEFAULTS(settrueto use Ringsecure-site-defaults)
Copyright © Chad Stovern.