After checking the logs, I realized that assumption was wrong.
Even with almost no real users, the server was constantly scanned: SSH brute-force attempts, HTTP probing for .env, AWS credential paths, and random endpoints.
Nothing broke, but it was clear I wasn’t really watching.
I explored a few options and ended up using CrowdSec. At first it felt heavy and not very friendly for a Docker + Kamal setup, but after some trial and error I got it working and automated.
I wrote up what I learned:
what SSH and HTTP logs actually look like on a “no-man’s” VPS
why repeated 404/403 probing matters
why temporary bans are safer than permanent ones
how I automated the setup so it’s repeatable
Article: https://muthuishere.medium.com/securing-a-production-vps-in-...
Video walkthrough: https://youtu.be/hSiMfbJ4c0Q
Automation / source code: https://github.com/muthuishere/automated-crowdsec-kamal
Sharing this in case it helps someone else running a small public server who assumes it’s too boring to be attacked. Happy to answer questions or hear how others handle this.
I switched to Colima and pointed docker context use colima. Then added Portainer for UI (docker run -d -p 9000:9000 ...).
With the same compose setup, Colima usage dropped to ~0.2%
Portainer provides containers/images/console UI
All while keeping the Docker CLI workflow
Full write-up (with screenshots) here: https://muthuishere.medium.com/docker-desktop-colima-portainer-my-mac-finally-breathes-b70d82d6cf0f
But every OS has different rules:
Mac/Linux: edit .bashrc, .zshrc, mess with PATH, source it Windows: create .bat, set up %PATH%, hope PowerShell respects it
You waste time managing commands instead of building things.
LNB solves that in one line:
npm install -g lnb
Then:
lnb alias build "docker run -v $(pwd):/workspace node:18 npm run build" build
Or:
lnb ./my-tool my-tool --help
Use cases:
Make any binary globally accessible
Wrap long dev commands into short aliases
Share consistent workflows across your team
Example:
lnb alias deploy "docker-compose -f prod.yml up -d" lnb alias logs "kubectl logs -f deployment/app" lnb alias test "npm test -- --coverage"
Cross-platform:
On macOS/Linux → symlinks or shell scripts in /usr/local/bin
On Windows → .cmd wrappers in %USERPROFILE%\bin
Works in Bash, Zsh, CMD, PowerShell, Windows Start menu search
Built for:
Developers who build CLIs or run local scripts
Teams who want consistent dev commands across machines
Anyone tired of tweaking PATH manually
Links: GitHub: https://github.com/muthuishere/lnb
You hit landmines like:
Mismatched IV/tag defaults (Java Crypto API vs WebCrypto)
Conflicting key formats (X.509 vs JWK vs raw)
Varied Base64 implementations and encoding subtleties
I spent hours chasing these. So I made Dual-Crypt, a fully working example:
AES-256-GCM + RSA-2048, wired correctly across Java ↔ JS
Uses spki for public key, pkcs8 for private key, 12-byte IV, 128-bit tag
Copy-paste ready code and a live demo
Read how I hacked it into existence, and try it yourself: https://muthuishere.medium.com/dual-crypt-cross-platform-encryption-spring-boot-react-that-actually-works-c713ecdbb89c Live demo here: https://dualcrypt.muthuishere.site