A lazy developer's solution for home server management, featuring dynamic DDNS (Aliyun DNS API) and automatic port mapping via UPnP.
- Dynamic DDNS: Automatically update DNS records using Aliyun DNS API, support for multiple domains, real-time public IP sync, and custom record types.
- UPnP Port Mapping: Automatically register port mappings to your router, support TCP/UDP, dynamic port management, and real-time status monitoring.
- Web UI: Modern, responsive, and supports both English and Chinese.
- Multi-language: Switch between English and Chinese easily.
- Frontend: Next.js 15 (App Router), TypeScript, Tailwind CSS 4, shadcn/ui, next-intl
- Backend: FastAPI (Python 3.12+), SQLAlchemy, miniupnpc, Aliyun DNS SDK
git clone https://github.com/yfge/PandaHome.git
cd PandaHome# Backend (run from repository root)
uv pip install --system -e api
# or
pip install -e api
# Frontend
npm install --prefix webcp api/.env.example api/.env
cp web/.env.local.example web/.env.localThen edit the files to provide your secrets (see Environment Variables).
# From repository root
pip install pre-commit
pre-commit install --install-hookscd api
alembic upgrade head
bootstrap-admin --username admin --password changeme --email admin@example.com# Backend (port 8003 to match the web client default)
uvicorn src.app.main:app --reload --app-dir api/src --port 8003
# Frontend
npm run dev --prefix web- Web UI: http://localhost:3000
- API Docs: http://localhost:8003/docs
- Log every code-producing session in
agent_chats/YYYYMMDD-HHMMSS-topic.mdfollowing the template described inagent_chats/README.md. - Run tests before opening a PR:
pytest -q api/testsnpm run test --prefix web
- Run
pre-commit run --all-filesbefore opening a PR; hooks enforce Ruff lint/format onapi/,npm run lint(and tests) for the frontend when dependencies are installed. - See
AGENTS.mdfor the full engineering handbook covering repository layout, conventions, and incident process.
Backend (api/.env):
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
SQLAlchemy database connection string. | sqlite:///./app.db |
SECRET_KEY |
JWT signing key; replace in production. | change-me |
JWT_ALGORITHM |
JWT signing algorithm. | HS256 |
ACCESS_TOKEN_EXPIRE_MINUTES |
Token lifetime in minutes. | 30 |
AUTH_TOKEN_URL |
OAuth2 token endpoint path. | /api/auth/token |
AUTH_HASHING_SCHEMES |
Comma-separated Passlib hashing schemes. | bcrypt |
AUTH_HASHING_DEPRECATED |
Passlib deprecated hashing strategy. | auto |
ALIYUN_ACCESS_KEY_ID |
Aliyun access key ID. | (required) |
ALIYUN_ACCESS_KEY_SECRET |
Aliyun access key secret. | (required) |
ALIYUN_REGION_ID |
Aliyun region for DNS API. | cn-hangzhou |
Frontend (web/.env.local):
| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_API_BASE_URL |
Base URL of the FastAPI backend. | http://localhost:8003 |
- Seed an administrator with
bootstrap-admin --username admin --password changeme --email admin@example.com(re-run to rotate credentials). - Start backend + frontend, then visit
http://localhost:3000/loginto sign in. - Successful login stores a bearer token locally; protected routes (
/status,/upnp,/domains) require the token. - Expired or invalid tokens trigger automatic logout and redirect back to
/login.
See docs/auth-lifecycle.md for the full authentication lifecycle (env requirements, CLI bootstrap, login/logout flow).
GET /api/status- System status snapshotGET /health- Health check
See docs/monitoring.md for data sources, update cadence, and troubleshooting tips.
GET /api/upnp/mappings- List all port mappingsPOST /api/upnp/mappings- Add a new port mappingDELETE /api/upnp/mappings/{external_port}?protocol=TCP|UDP- Remove a port mapping (defaults toTCP)
See docs/upnp.md for router prerequisites, troubleshooting tips, and security notes.
GET /api/domains/domains- List all domainsGET /api/domains/domains/{domain}/records- List domain recordsPOST /api/domains/domains/{domain}/records- Add a new recordPUT /api/domains/domains/{domain}/records/{record_id}- Update a recordDELETE /api/domains/domains/{domain}/records/{record_id}- Delete a record
See docs/domains.md for Aliyun access key setup, required permissions, and rate limit troubleshooting.
MIT