# Admin web deployment Build the frontend and publish the generated `dist` directory as the Nginx document root: ```powershell npm run build ``` The admin web app uses Vue Router HTML5 history mode. The active Nginx `server` block must therefore contain: ```nginx location / { try_files $uri $uri/ /index.html; } ``` Use `nginx.conf` as the site template. If the host already terminates HTTPS in another `server` block, merge the `location` blocks into that HTTPS block instead of creating a second TLS listener. Keep `/api/` and `/uploads/` proxied to the Spring Boot service; only client-side page routes should fall back to `index.html`. The backend maps uploaded files as follows: ```text /uploads/avatars/** -> AVATAR_STORAGE_DIR (default: ./data/avatars) /uploads/guide-applications/** -> GUIDE_APPLICATION_STORAGE_DIR (default: ./data/guide-applications) ``` The recommended Nginx configuration is already included in `nginx.conf`: ```nginx location ^~ /uploads/ { proxy_pass http://127.0.0.1:8011; } ``` This preserves the backend authorization check for guide application documents. If avatars must be served directly by Nginx, only expose the avatar directory and keep guide applications proxied: ```nginx location ^~ /uploads/avatars/ { alias /opt/tourguide/data/avatars/; autoindex off; } location ^~ /uploads/guide-applications/ { proxy_pass http://127.0.0.1:8011; } ``` Replace `/opt/tourguide/data/...` with the actual absolute server paths. Configure the same absolute paths through `AVATAR_STORAGE_DIR` and `GUIDE_APPLICATION_STORAGE_DIR` for the backend, so storage does not depend on the Java process working directory. After reloading Nginx, verify all three request types: ```text GET / -> frontend index.html (200) GET /login -> frontend index.html (200) GET /api/health -> backend JSON (200) ```