Building RustSocks with URL Base Path¶
Complete guide for building and configuring RustSocks with a custom URL prefix (base path) for the API and dashboard.
📋 Table of Contents¶
🔧 How It Works¶
RustSocks supports deployment under any URL path through intelligent frontend-backend integration:
Backend (Rust)¶
- Config:
sessions.base_pathdefines the URL prefix (e.g.,/rustsocks,/proxy, or/) - Router nesting: If
base_path != "/", the entire application (API + dashboard) is mounted under this prefix - HTML rewriting: Automatic
index.htmlrewriting: - Injects
<script>window.__RUSTSOCKS_BASE_PATH__ = '/rustsocks';</script>before</head> - Rewrites asset paths:
./assets/→/rustsocks/assets/ - Static files: Serves
dashboard/dist/with automatic SPA routing fallback
Frontend (React)¶
- Auto-detection:
src/lib/basePath.jsautomatically detects base path from: window.__RUSTSOCKS_BASE_PATH__(injected by backend)- Or from script location (parses
/assets/index-*.jsURL) - Or from
window.location.pathname(fallback) - React Router:
<BrowserRouter basename={ROUTER_BASENAME}>for routing - API calls:
getApiUrl(path)adds prefix to all fetch() calls - Vite build: Builds with
base: './'(relative paths)
⚙️ Configuration¶
1. Backend Config (config/rustsocks.toml)¶
[sessions]
stats_api_enabled = true
dashboard_enabled = true
swagger_enabled = true
stats_api_bind_address = "127.0.0.1"
stats_api_port = 9090
# Base URL path prefix
base_path = "/rustsocks" # Options: "/", "/rustsocks", "/proxy", etc.
Important:
- base_path = "/" - dashboard at http://host/
- base_path = "/rustsocks" - dashboard at http://host/rustsocks
- base_path = "/rustsocks/" - trailing slash is automatically removed
2. Frontend Config (dashboard/vite.config.js)¶
No changes required! Vite is configured with base: './' (relative paths), which works with any base path.
export default defineConfig({
base: './', // ✅ MUST be './' for automatic functionality
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': 'http://127.0.0.1:9090',
'/health': 'http://127.0.0.1:9090',
'/metrics': 'http://127.0.0.1:9090',
}
}
})
🏗️ Building the Application¶
Step 1: Build Backend (Rust)¶
# Development build
cargo build
# Production build (optimized)
cargo build --release
Step 2: Build Frontend (React Dashboard)¶
cd dashboard
# Install dependencies (first time only)
npm install
# Production build
npm run build
This creates dashboard/dist/ with:
- index.html
- assets/index-*.js
- assets/index-*.css
- favicon.png
Step 3: Run¶
# From project root
./target/release/rustsocks --config config/rustsocks.toml
Backend automatically:
1. Loads static files from dashboard/dist/
2. Rewrites index.html adding base path script
3. Serves dashboard under /rustsocks (or other base_path)
🚀 Development Mode¶
1. Run Backend¶
cargo run -- --config config/rustsocks.toml
API available at: http://127.0.0.1:9090/api/
2. Run Frontend Dev Server¶
cd dashboard
npm run dev
Dashboard available at: http://localhost:3000
In dev mode:
- Vite proxy forwards /api, /health, /metrics to backend :9090
- Hot reload for React code changes
- Base path is NOT used (always /)
- Perfect for development
🌐 Production Deployment¶
Scenario 1: Dashboard under Root Path /¶
Config:
[sessions]
base_path = "/"
Build:
npm run build
cargo build --release
Access:
- Dashboard: http://server:9090/
- API: http://server:9090/api/
- Swagger: http://server:9090/swagger-ui/
Scenario 2: Dashboard under /rustsocks¶
Config:
[sessions]
base_path = "/rustsocks"
Build:
npm run build
cargo build --release
Access:
- Dashboard: http://server:9090/rustsocks
- API: http://server:9090/rustsocks/api/
- Swagger: http://server:9090/rustsocks/swagger-ui/
Scenario 3: Nginx Reverse Proxy¶
When using nginx reverse proxy, you have two options to avoid double prefixing issues (TOO_MANY_REDIRECTS).
Option A: Nginx adds prefix, backend at root (RECOMMENDED)¶
Nginx config:
location /rustsocks/ {
proxy_pass http://127.0.0.1:9090/; # Note: trailing slash, no prefix
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
RustSocks config:
[sessions]
base_path = "/" # Backend at root, nginx handles prefix
stats_api_bind_address = "127.0.0.1"
stats_api_port = 9090
Access:
- Dashboard: http://yourserver.com/rustsocks/
- API: http://yourserver.com/rustsocks/api/
Option B: Nginx strips prefix before forwarding¶
Nginx config:
location /rustsocks/ {
rewrite ^/rustsocks/(.*) /$1 break; # Strip /rustsocks/ before forwarding
proxy_pass http://127.0.0.1:9090;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
RustSocks config:
[sessions]
base_path = "/" # Backend at root, nginx strips prefix
stats_api_bind_address = "127.0.0.1"
stats_api_port = 9090
Access:
- Dashboard: http://yourserver.com/rustsocks/
- API: http://yourserver.com/rustsocks/api/
⚠️ Common Mistake: Double Prefixing¶
DON'T DO THIS:
location /rustsocks/ {
proxy_pass http://127.0.0.1:9090/rustsocks/; # ❌ With prefix
}
[sessions]
base_path = "/rustsocks" # ❌ Backend also with prefix
This causes TOO_MANY_REDIRECTS because:
1. Nginx forwards /rustsocks/ → http://127.0.0.1:9090/rustsocks/
2. Backend adds another /rustsocks/ → redirects to /rustsocks/rustsocks/
3. Infinite redirect loop!
📝 Examples¶
Example 1: Update base_path¶
# 1. Change config
sed -i 's|base_path = "/"|base_path = "/rustsocks"|' config/rustsocks.toml
# 2. Rebuild frontend (only if the dashboard assets are missing or you changed frontend code)
cd dashboard
npm run build
# 3. Rebuild backend (if code changes)
cd ..
cargo build --release
# 4. Restart server
./target/release/rustsocks --config config/rustsocks.toml
Note: Changing base_path does not require a rebuild. The dashboard detects the base path at runtime.
Example 2: Test different base paths¶
# Test 1: Root path
echo 'base_path = "/"' >> config/test.toml
cargo run -- --config config/test.toml
# Check: http://127.0.0.1:9090/
# Test 2: Subpath
echo 'base_path = "/myproxy"' >> config/test.toml
cargo run -- --config config/test.toml
# Check: http://127.0.0.1:9090/myproxy
Example 3: Docker deployment with base path¶
Dockerfile:
FROM rust:1.90-alpine AS rust-builder
WORKDIR /build
RUN apk add --no-cache build-base musl-dev linux-pam-dev openssl-dev pkgconfig
COPY Cargo.toml Cargo.lock ./
COPY src/ ./src/
RUN cargo build --release --all-features
FROM node:18-alpine AS dashboard-builder
WORKDIR /build/dashboard
COPY dashboard/package*.json ./
RUN npm ci
COPY dashboard/ ./
RUN npm run build
FROM alpine:3.19
RUN apk add --no-cache linux-pam libgcc ca-certificates libssl3
WORKDIR /app
COPY --from=rust-builder /build/target/release/rustsocks .
COPY --from=dashboard-builder /build/dashboard/dist ./dashboard/dist
COPY config/ ./config/
CMD ["./rustsocks", "--config", "config/rustsocks.toml"]
Make sure config/rustsocks.toml contains:
[sessions]
base_path = "/socks"
🐛 Troubleshooting¶
Problem: Dashboard shows "Cannot GET /rustsocks"¶
Cause: Base path mismatch between config and reverse proxy, or the dashboard build is missing.
Solution:
- Ensure sessions.base_path matches your deployment path.
- Verify dashboard/dist/ exists; build it if missing:
cd dashboard
npm run build
Problem: Assets (CSS/JS) not loading (404)¶
Cause: Incorrect Vite configuration
Solution: Ensure vite.config.js has base: './':
export default defineConfig({
base: './', // ✅ Must be relative path
// ...
})
Problem: API calls fail with 404¶
Cause: Frontend using wrong API path
Solution: Verify that:
1. getApiUrl() is used in all fetch() calls:
// ✅ Correct
fetch(getApiUrl('/api/sessions/stats'))
// ❌ Wrong
fetch('/api/sessions/stats')
window.__RUSTSOCKS_BASE_PATH__
Problem: React Router not working (blank page)¶
Cause: Incorrect basename in React Router
Solution: Ensure App.jsx uses ROUTER_BASENAME:
import { ROUTER_BASENAME } from './lib/basePath'
<BrowserRouter basename={ROUTER_BASENAME}>
<Routes>
{/* ... */}
</Routes>
</BrowserRouter>
Problem: Works on localhost, but not on server¶
Cause: Reverse proxy not forwarding correct headers
Solution: Add to nginx/apache:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
Problem: TOO_MANY_REDIRECTS with nginx reverse proxy¶
Cause: Double prefixing - both nginx and backend add the same prefix
Example of incorrect config:
location /rustsocks/ {
proxy_pass http://127.0.0.1:9090/rustsocks/; # ❌ Includes prefix
}
[sessions]
base_path = "/rustsocks" # ❌ Backend also adds prefix
Solution Option 1 (recommended): Backend at root /, nginx adds prefix:
location /rustsocks/ {
proxy_pass http://127.0.0.1:9090/; # ✅ No prefix, trailing slash
}
[sessions]
base_path = "/" # ✅ Backend at root
Solution Option 2: Nginx strips prefix before forwarding:
location /rustsocks/ {
rewrite ^/rustsocks/(.*) /$1 break; # ✅ Strip prefix
proxy_pass http://127.0.0.1:9090;
}
[sessions]
base_path = "/" # ✅ Backend at root
✅ Pre-Deployment Checklist¶
- [ ]
base_pathset inconfig/rustsocks.toml - [ ] Frontend built:
cd dashboard && npm run build - [ ] Backend built:
cargo build --release - [ ]
dashboard/dist/exists and containsindex.html - [ ] Test in browser:
- [ ] Dashboard loads
- [ ] Routing works (page switching)
- [ ] API calls work (Sessions, ACL, Stats)
- [ ] Assets (CSS/JS) load correctly
- [ ] Check browser console (F12) - no 404 errors
📚 Additional Resources¶
- Developer Guide - Developer guide
- Project README - Project overview
- Dashboard README - Dashboard documentation
- API Documentation - Swagger UI (when running)
Last Updated: 2025-11-02 Version: 0.9 Status: ✅ Production Ready