No description
Find a file
2026-08-03 11:02:29 +01:00
frontend fixed name 2026-08-03 11:02:29 +01:00
migrations first build 2026-08-03 09:42:13 +01:00
src first build 2026-08-03 09:42:13 +01:00
.env.example first build 2026-08-03 09:42:13 +01:00
.gitignore first build 2026-08-03 09:42:13 +01:00
Cargo.lock fixed name 2026-08-03 11:02:29 +01:00
Cargo.toml fixed name 2026-08-03 11:02:29 +01:00
DESIGN.md first build 2026-08-03 09:42:13 +01:00
mapserver.service first build 2026-08-03 09:42:13 +01:00
nginx-snippet.conf first build 2026-08-03 09:42:13 +01:00
postgres.container first build 2026-08-03 09:42:13 +01:00
README.md fixed name 2026-08-03 11:02:29 +01:00
rust_push.sh first build 2026-08-03 09:42:13 +01:00

rs_maps — build and deploy

Single Rust binary + one rootless Postgres container. See DESIGN.md for the reasoning.

This code has not been compiled. It was written without a Rust toolchain available, so treat the first cargo build as the real review. Expect to fix a handful of import paths and trait-bound details, not the structure.

1. Refresh dependency versions

Cargo.toml has plausible versions, but pin them properly:

cargo add axum -F multipart,macros
cargo add tokio -F full
cargo add sqlx --no-default-features -F runtime-tokio,tls-rustls,postgres,uuid,time,macros,migrate
cargo add tower-sessions
cargo add tower-sessions-sqlx-store -F postgres
cargo add lettre --no-default-features -F tokio1-rustls,smtp-transport,builder,pool
cargo add rust-embed -F debug-embed
cargo build

Two version-sensitive spots to check first if it doesn't compile:

  • tower-sessions / tower-sessions-sqlx-store must be a matching pair. The store crate tracks the main crate's version and they break in lockstep. Check the store's own README for which tower-sessions it expects.
  • axum 0.8 changed path params from :id to {id}. This code uses {id}. If you end up on 0.7 for some reason, they all need changing back.

2. Database

podman secret create mapserver-db-password -   # type the password, then Ctrl-D
mkdir -p ~/.config/containers/systemd
cp deploy/postgres.container ~/.config/containers/systemd/
systemctl --user daemon-reload
systemctl --user start postgres

Migrations run automatically on startup — both ./migrations and the session store's own.

3. Config

mkdir -p ~/.config/mapserver ~/gpx
cp .env.example ~/.config/mapserver/.env
chmod 600 ~/.config/mapserver/.env
$EDITOR ~/.config/mapserver/.env

Must change: DATABASE_URL, REG_TOKEN, PUBLIC_URL, BASE_PATH, GPX_DIR.

Leave SMTP_HOST empty for now — reset links get logged instead of emailed, and the whole flow is testable without a provider.

4. Run

cargo build --release
mkdir -p ~/.local/bin && cp target/release/mapserver ~/.local/bin/
cp deploy/mapserver.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now mapserver
loginctl enable-linger "$USER"     # or nothing starts at boot
journalctl --user -u mapserver -f

5. nginx

Merge deploy/nginx-snippet.conf into your existing TLS server block, then nginx -t && systemctl reload nginx.

6. First account

Visit https://your-domain/maps/, choose "Create an account", and enter the REG_TOKEN from .env.


Testing the reset flow with real mail

mailpit gives you a local SMTP server and a web inbox with no signup:

SMTP_HOST=127.0.0.1
SMTP_PORT=1025
SMTP_TLS=none
SMTP_USERNAME=
SMTP_PASSWORD=

When you move to a real provider: use an app-specific password (any account with 2FA will reject the normal one over SMTP), check SMTP isn't disabled by default on the account, and make sure SMTP_FROM is an address that account may send as.

Things worth checking by hand after the first deploy

  • curl -i https://your-domain/maps/api/gpx/file/../../etc/passwd → 400 or 404, never a file
  • Live location works (needs HTTPS; it silently fails on plain HTTP)
  • Session survives systemctl --user restart mapserver
  • Upload a >2 MB GPX — catches both the axum and nginx body limits at once
  • Upload the same filename twice — second one should come back as name-1.gpx
  • Reboot the server, confirm both units come back (this is what enable-linger is for)

Unit tests

cargo test

No database needed — every test is pure: base-path normalisation, bbox parsing, GPX filename safety, and the rate-limiter window.