UniFi Guest Portal
A custom external portal server for UniFi guest WiFi networks with a modern, responsive design.
Features
- 🎨 Modern, mobile-responsive design
- 🔒 Secure authentication with UniFi Controller
- ⚡ Fast and lightweight
- 🎯 Easy to customize
- ⏱️ Configurable access duration (default: 24 hours)
Prerequisites
- Node.js 16+ installed
- UniFi Controller with admin credentials
- Proxmox LXC container (or any Linux server)
- Reverse proxy with SSL (Zoraxy in your case)
- Local DNS resolution (Pi-hole)
Installation
1. Create LXC Container on Proxmox
# Create Ubuntu/Debian container
# Assign static IP (e.g., 192.168.1.100)
# Update the system
apt update && apt upgrade -y
# Install Node.js
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs git
# Verify installation
node --version
npm --version
2. Deploy the Portal Application
# Upload the unifi-portal folder to your container
# Or clone from your git repository
cd /opt
# Copy the unifi-portal folder here
# Navigate to project directory
cd unifi-portal
# Install dependencies
npm install
# Configure environment variables
cp .env.example .env
nano .env # Edit with your actual credentials
3. Configure UniFi Controller Credentials
Edit server.js and update these values:
const UNIFI_USERNAME = 'your-unifi-admin-username';
const UNIFI_PASSWORD = 'your-unifi-admin-password';
const UNIFI_SITE = 'default'; // or your site name
4. Test the Application
# Start the server
npm start
# Test from another machine
curl http://192.168.1.100:3000/health
5. Set up as a System Service
Create a systemd service file:
nano /etc/systemd/system/unifi-portal.service
Add this content:
[Unit]
Description=UniFi Guest Portal
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/unifi-portal
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start the service:
systemctl daemon-reload
systemctl enable unifi-portal
systemctl start unifi-portal
systemctl status unifi-portal
6. Configure Pi-hole DNS
Add a local DNS record in Pi-hole:
- Domain:
portal.yourdomain.local(or whatever you prefer) - IP:
192.168.1.100(your LXC container IP)
7. Configure Zoraxy Reverse Proxy
In Zoraxy:
- Create a new proxy rule
- Domain:
portal.yourdomain.local - Target:
http://192.168.1.100:3000 - Enable SSL (use self-signed cert or Let's Encrypt)
- Save and test
8. Configure UniFi Controller
- Log into your UniFi Controller at
https://192.168.1.1 - Go to Settings → Guest Control
- Create or edit a Guest Hotspot/Portal
- Set Authentication to External Portal Server
- External Portal Server URL:
https://portal.yourdomain.local - Set HTTPS Redirection: Enabled
- Save settings
Testing
- Connect a device to your guest WiFi network
- Open a browser - you should be redirected to your custom portal
- Click "Connect to WiFi"
- You should get internet access and be redirected
Customization
Change the Design
Edit public/index.html to customize:
- Colors (gradient, buttons, etc.)
- Logo (change the emoji or add an image)
- Text and messaging
- Add form fields (email capture, terms checkbox, etc.)
Adjust Access Duration
In server.js, modify the minutes parameter:
minutes: 1440 // 24 hours (1440 minutes)
Common values:
- 60 = 1 hour
- 480 = 8 hours
- 1440 = 24 hours
- 10080 = 1 week
Add Email Collection
You can add a form field to collect emails before authorization. Example modification to public/index.html:
<input type="email" id="guestEmail" placeholder="Enter your email" required>
And modify the /authorize endpoint in server.js to save the email.
Troubleshooting
Portal doesn't redirect
- Check UniFi Controller external portal URL is correct
- Verify DNS resolution:
nslookup portal.yourdomain.local - Check Zoraxy proxy rule is active
"Authorization failed"
- Verify UniFi credentials in
server.js - Check UniFi Controller is accessible from container:
curl -k https://192.168.1.1 - Review logs:
journalctl -u unifi-portal -f
SSL Certificate errors
- UniFi Controller uses self-signed cert by default (expected)
- The code ignores cert errors with
rejectUnauthorized: false - For production, consider proper SSL certificates
Check logs
# View service logs
journalctl -u unifi-portal -f
# Or if running manually
npm start
Security Notes
- The portal server needs admin credentials to the UniFi Controller
- Store credentials securely (consider using environment variables)
- Use HTTPS for your portal (required for most mobile devices)
- The code currently disables SSL verification for the UniFi Controller (common for self-signed certs)
- Consider implementing rate limiting to prevent abuse
Project Structure
unifi-portal/
├── server.js # Main Express server with UniFi API integration
├── package.json # Node.js dependencies
├── public/
│ └── index.html # Custom landing page
├── .env.example # Environment variables template
└── README.md # This file
API Endpoints
GET /- Main portal page (receives UniFi redirect parameters)POST /authorize- Authorizes guest device with UniFi ControllerGET /health- Health check endpoint
UniFi API Reference
The portal uses these UniFi Controller API endpoints:
POST /api/login- Authenticate to controllerPOST /api/s/{site}/cmd/stamgr- Authorize guest devicePOST /api/logout- Logout from controller
License
MIT
Support
For issues or questions, check:
- UniFi API documentation
- Node.js/Express.js documentation
- Your network configuration (DNS, firewall, routing)
Description
Languages
HTML
68.8%
JavaScript
31.2%