A secure, self-hosted personal cloud solution for macOS, built with OpenClaw + Codex AI-assisted development.
Private NAS for Mac is a custom-built Network Attached Storage (NAS) software designed to turn your Mac (and its connected external drives) into a secure personal cloud. It aims to replace commercial services like Google Drive or Dropbox by providing a user-friendly web interface for file management, all while keeping your data physically in your control.
Unlike typical cloud services exposed to the public internet, this project adopts a VPN-First Security Model, ensuring your data is accessible only through a secure, private tunnel.
- VPN-Gated Access: The web interface is hidden from the public internet. Access is strictly controlled via WireGuard VPN.
- Mac-Native: Optimized for macOS file systems (APFS) and external volume handling (
/Volumes). - Modern Web UI: A responsive, drag-and-drop file manager built with React and Material UI.
- Robust Backend: Powered by Java Spring Boot 4.x with Domain-Driven Design (DDD).
- Admin Dashboard: Comprehensive monitoring of system health, user management, and access logs.
This project is developed with an AI-assisted workflow focused on fast iteration and tight feedback loops.
We use OpenClaw as the orchestration layer and Codex agents/models for implementation, review, and refactoring across specs, architecture, backend, frontend, and operations.
- Backend: Java 25, Spring Boot 4.x, Spring Security, JPA/Hibernate
- Frontend: TypeScript, React, Vite, Material UI (MUI), Zustand
- Infrastructure: Docker, Docker Compose, WireGuard (VPN), PostgreSQL
- Architecture: Hexagonal Architecture (Ports & Adapters)
Detailed specifications and architectural decisions can be found in the spec/ directory:
- Master Specification: The high-level goals and roadmap.
- Technical Architecture: System design, container diagrams, and module structure.
- VPN Implementation: Details on the security model and networking.
- Admin Page Spec: UI/UX and API specs for the administration interface.
- VPN Operations Runbook: Key rotation, revoke, upgrade/rollback checklist.
- Release Traceability (2026-02): issue-PR mapping for recent hardening rounds.
- Project Wiki: onboarding, architecture, run/test, operations quick reference.
- Docker Desktop installed on your Mac.
β οΈ Ifconfig/db-dataalready exists, changingNAS_USER/NAS_PASSWORD/NAS_DBlater may cause backend DB authentication failures. Reinitialize DB data (after backup) or keep credentials aligned with the existing DB.
-
Copy the example environment file:
cp .env.example .env
-
Open
.envand configure required security values:APP_SECURITY_BOOTSTRAP_ADMIN_PASSWORD(initial admin password)JWT_SECRET(Base64, decoded length >= 32 bytes)WG_HOST(Public IP or DDNS)WG_EASY_VERSION(pinned wg-easy image version)WG_PASSWORD_HASH(wg-easy admin password hash)NAS_USER,NAS_PASSWORD,NAS_DB(PostgreSQL credentials)TRUSTED_PROXY_SUBNETS(X-Forwarded-Forλ₯Ό μ λ’°ν νλ‘μ CIDR λͺ©λ‘)FRONTEND_BIND_ADDRESS(frontend host bind address, secure default:127.0.0.1)
Trusted Proxy μ€μ μμ:
- λ‘컬 λ¨λ
:
127.0.0.1/32,::1/128 - λ¨μΌ 리λ²μ€ νλ‘μ:
<proxy-ip>/32 - κΈμ§ κΆμ₯:
0.0.0.0/0,::/0(λͺ¨λ IP μ λ’°)
VPN allowed subnets κΈ°λ³Έκ°μλ IPv6 loopback(
::1/128)μ΄ ν¬ν¨λ©λλ€.CORS 보μ κ°λ:
allowCredentials=trueꡬμ±μμλCORS_ALLOWED_ORIGINSμ wildcard(*,http://*,https://*)λ₯Ό μ¬μ©ν μ μμ΅λλ€.
Generate a secure JWT secret:
openssl rand -base64 32
Run the startup script (recommended):
./start.shOr run Docker directly (recommended with rebuild to avoid stale images):
docker-compose up -d --builddocker-compose ps
docker-compose logs --tail=100 nas-db nas-backend nas-frontendnas-db:pg_isreadyκΈ°λ° healthynas-backend:GET /actuator/healthμν κΈ°λ° healthy (IPv4 loopback 127.0.0.1 κ³ μ )nas-frontend: nginx index μλ΅ κΈ°λ° healthy- If Dockerfile/healthcheck was changed, run with
--buildto avoid stale image mismatch.
Audit logs API pagination example:
curl -H "Authorization: Bearer <token>" "http://127.0.0.1/api/admin/system/audit-logs?offset=0&limit=100"(limit max 500)
bash scripts/smoke_e2e.shThis script builds/starts containers, validates core auth/health paths, and then checks discovered backend API routes for safe-method(GET) non-404/non-5xx reachability.
- Pull Request / Push(main):
- backend
./gradlew test - frontend
npm ci && npm run build - frontend production dependency audit
npm audit --omit=dev --audit-level=high
- backend
- Push(main):
bash scripts/smoke_e2e.sh
- Production-safe defaults are in
application.yml(SQL logs off). - For local debugging with SQL logs enabled, use dev profile:
SPRING_PROFILES_ACTIVE=dev- If needed, override preview cache directory explicitly:
APP_STORAGE_CACHE_DIR=/tmp/nas-cache- Gradle configuration cache is enabled in
backend/gradle.properties. - First build warms cache; repeated runs are faster.
- Access the Admin UI at http://localhost:51821.
- Login with the password you set in
.env.- Frontend auth token is stored in sessionStorage, so closing the browser requires login again.
- Create a new client (peer).
- Scan the QR code with the WireGuard mobile app or download the configuration for your laptop.
- On your home router, forward UDP port 51820 to your Mac's local IP address.
- Do not forward port 80 publicly unless you explicitly intend to expose the frontend.
- Keep
FRONTEND_BIND_ADDRESS=127.0.0.1by default for safer local-only bind. - Keep
WG_EASY_VERSIONpinned. Upgrade by explicitly changing version, reviewing changelog, then redeploying.
Β© 2026 Private NAS Project. Created with Vibe.