From 8011097882933c2cd8166134a2c4de163c405170 Mon Sep 17 00:00:00 2001 From: ebigunso Date: Tue, 12 Aug 2025 08:12:51 +0900 Subject: [PATCH 1/6] Use separate env files: add .env.docker.example; compose uses env_file; add .dockerignore; update README; ignore .env.docker --- .dockerignore | 19 +++++++++++++++++++ .env.docker.example | 30 ++++++++++++++++++++++++++++++ .gitignore | 3 +++ README.md | 14 ++++++++++++++ compose.yaml | 4 ++-- 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 .env.docker.example diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d516115 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +# Exclude local env files from Docker build context +.env +.env.local +.env.development +.env.test +.env.docker + +# Rust build artifacts +target + +# Git +.git +.gitignore + +# Node/npm caches if any future UI gets added +node_modules +npm-debug.log +yarn.lock +pnpm-lock.yaml diff --git a/.env.docker.example b/.env.docker.example new file mode 100644 index 0000000..567c6a9 --- /dev/null +++ b/.env.docker.example @@ -0,0 +1,30 @@ +# SleepTracker Docker Compose environment file (example) +# Copy this file to ".env.docker" and fill in the values before running: +# docker compose up --build +# +# Notes: +# - COOKIE_SECURE is omitted here; the application defaults to secure cookies (true) when unset. +# You may explicitly set COOKIE_SECURE=1 if you prefer, but do NOT set it to 0 in Docker. +# - Do not commit your real .env.docker with secrets to version control. + +# Use a file-based SQLite database inside the container volume +DATABASE_URL=sqlite:///data/sleep.db + +# Single admin user credentials used by the application +# - Generate an Argon2id password hash with: +# cargo run -p sleep-api --bin pw-hash +# - Paste the full $argon2id$... string below +ADMIN_EMAIL=admin@example.com +ADMIN_PASSWORD_HASH=$argon2id$v=19$REPLACE_WITH_HASH + +# Session secret (base64-encoded random bytes, 32+ bytes recommended) +# Examples to generate: +# Linux/macOS: head -c 32 /dev/urandom | base64 +# PowerShell: [Convert]::ToBase64String((1..32 | ForEach-Object {[byte](Get-Random -Max 256)})) +SESSION_SECRET=REPLACE_WITH_BASE64_SECRET + +# Optional: enable HSTS when served over HTTPS/behind TLS-terminating proxy +# ENABLE_HSTS=1 + +# Optional: explicitly enforce secure cookies in Docker (default is secure=true when unset) +# COOKIE_SECURE=1 diff --git a/.gitignore b/.gitignore index ad67955..1c15468 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ target # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +.env +.env.docker diff --git a/README.md b/README.md index b21cf55..eed7879 100644 --- a/README.md +++ b/README.md @@ -92,3 +92,17 @@ OpenAPI specification is in openapi.yaml and includes: - The cookie encryption Key is derived from SESSION_SECRET if present; otherwise a random key is generated (sessions will break on restart in that case). - Default database is sqlite::memory: for ephemeral dev/testing. For a persistent DB use DATABASE_URL=sqlite://./data/sleep.db and create the directory. + +## Environments + +- Local (cargo run): + - Use .env for local settings (e.g., COOKIE_SECURE=0 for http://). + - Start: `cargo run -p sleep-api`. + +- Docker Compose: + - Copy `.env.docker.example` to `.env.docker` and fill values (ADMIN_EMAIL, ADMIN_PASSWORD_HASH, SESSION_SECRET; optionally COOKIE_SECURE=1). + - Compose injects only `.env.docker` into the container; your local `.env` is not used inside the container. + - Start: `docker compose up --build`. + +- Paths in Docker: + - DATABASE_URL should point to the named volume path: `sqlite:///data/sleep.db`. diff --git a/compose.yaml b/compose.yaml index fa673e0..74fdc70 100644 --- a/compose.yaml +++ b/compose.yaml @@ -2,8 +2,8 @@ services: api: build: . working_dir: /data - environment: - - DATABASE_URL=sqlite://sleep.db + env_file: + - .env.docker ports: - "8080:8080" volumes: From cbe9d9341e0e7f5923ba050a12732464fe692d57 Mon Sep 17 00:00:00 2001 From: ebigunso Date: Tue, 12 Aug 2025 08:22:03 +0900 Subject: [PATCH 2/6] docs: document COOKIE_SECURE=0 in .env.example for local HTTP dev --- .env.example | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.env.example b/.env.example index bbd67bb..22f8f06 100644 --- a/.env.example +++ b/.env.example @@ -20,5 +20,10 @@ ADMIN_PASSWORD_HASH=$argon2id$v=19$REPLACE_WITH_HASH # Note: CSRF uses a random per-login cookie (double-submit) and does not use a CSRF secret. SESSION_SECRET=REPLACE_WITH_BASE64_SECRET +# Local development over HTTP (do NOT use in production or Docker) +# Set to 0 to allow non-Secure cookies and dev-friendly cookie names ("session"/"csrf"). +# In Docker/production, omit this variable (defaults to secure=true) or set COOKIE_SECURE=1. +COOKIE_SECURE=0 + # Optional: enable HSTS header (only when served over HTTPS/behind TLS) # ENABLE_HSTS=1 From ac81cfce86e6d399a35ff0cb918206e9b15ef9e2 Mon Sep 17 00:00:00 2001 From: ebigunso Date: Wed, 13 Aug 2025 22:31:49 +0900 Subject: [PATCH 3/6] :memo: Additional notes to Readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eed7879..16fc4d7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ SleepTracker is a small, single-user web API for tracking sleep sessions, built - Set ADMIN_EMAIL and ADMIN_PASSWORD_HASH - Generate a password hash: cargo run -p sleep-api --bin pw-hash - - Paste the $argon2id$... string into ADMIN_PASSWORD_HASH + - Paste the $argon2id$... string into ADMIN_PASSWORD_HASH (IMPORTANT: use single quotes in .env/.env.docker to prevent $-expansion by dotenv) + Example: + ADMIN_PASSWORD_HASH='$argon2id$v=19$m=19456,t=2,p=1$...$...' - Set SESSION_SECRET to a base64-encoded random value (32+ bytes recommended) - Optional: Set ENABLE_HSTS=1 when serving over HTTPS - Optional: See COOKIE_SECURE below for local HTTP development From 568fb2d6e66cfb3f99a9f2a3ba430f0271b70f74 Mon Sep 17 00:00:00 2001 From: ebigunso Date: Thu, 14 Aug 2025 03:18:04 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix(docker):=20strip=20CRLF=20from=20entryp?= =?UTF-8?q?oint=20in=20image=20build=20to=20prevent=20'exec=20=E2=80=A6=20?= =?UTF-8?q?no=20such=20file=20or=20directory'=20and=20ensure=20script=20is?= =?UTF-8?q?=20executable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 107ae2d..7616884 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,9 @@ WORKDIR /app ENV DATABASE_URL=sqlite:///data/sleep.db COPY --from=builder /app/target/release/sleep-api /app/sleep-api COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh -RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +# Normalize line endings in case the script was checked out with CRLF on Windows +RUN sed -i 's/\r$//' /usr/local/bin/docker-entrypoint.sh && chmod +x /usr/local/bin/docker-entrypoint.sh + ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] EXPOSE 8080 From 1c1bce38f2a6c7dde5706378ddec9bd4879bce8d Mon Sep 17 00:00:00 2001 From: ebigunso Date: Thu, 14 Aug 2025 03:37:53 +0900 Subject: [PATCH 5/6] :note: Readme update --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 16fc4d7..1417dc0 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,30 @@ SleepTracker is a small, single-user web API for tracking sleep sessions, built Server will listen on 0.0.0.0:8080. +## Run with Docker + +Use Docker Compose to build and run the app. + +- Docker Compose (recommended) + - Copy .env.docker.example to .env.docker and fill values: + - ADMIN_EMAIL, ADMIN_PASSWORD_HASH (quote the $argon2id$... string with single quotes) + - SESSION_SECRET: base64-encoded random value (32+ bytes) + - For local HTTP development, set COOKIE_SECURE=0. For HTTPS/prod, use COOKIE_SECURE=1. + - Build and start: + docker compose up --build + - Add -d to run in the background. + - Access the API at http://localhost:8080 + - Follow logs: + docker compose logs -f api + - Stop: + docker compose down + - Stop and delete the persistent data volume (DESTROYS DB): + docker compose down -v + - Notes: + - Data is stored at /data inside the container and persists in a named volume across restarts. + - Migrations run automatically on startup. + + ## Authentication and sessions - Single-user login based on ADMIN_EMAIL and ADMIN_PASSWORD_HASH. From 0c5ed632d2335f5755d69bbab2d89dbe484fa150 Mon Sep 17 00:00:00 2001 From: ebigunso Date: Thu, 14 Aug 2025 04:12:20 +0900 Subject: [PATCH 6/6] Update .env.docker.example Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .env.docker.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.docker.example b/.env.docker.example index 567c6a9..89344d0 100644 --- a/.env.docker.example +++ b/.env.docker.example @@ -15,7 +15,7 @@ DATABASE_URL=sqlite:///data/sleep.db # cargo run -p sleep-api --bin pw-hash # - Paste the full $argon2id$... string below ADMIN_EMAIL=admin@example.com -ADMIN_PASSWORD_HASH=$argon2id$v=19$REPLACE_WITH_HASH +ADMIN_PASSWORD_HASH='$argon2id$v=19$REPLACE_WITH_HASH' # Session secret (base64-encoded random bytes, 32+ bytes recommended) # Examples to generate: