Fix security warnings
This commit is contained in:
@@ -1,2 +1,6 @@
|
||||
# Timezone
|
||||
TZ=Europe/Copenhagen
|
||||
|
||||
# Admin Credentials (CHANGE THESE!)
|
||||
ADMIN_EMAIL=admin@docker-webui.local
|
||||
ADMIN_PASSWORD=changeme123
|
||||
|
||||
343
README.md
343
README.md
@@ -1,73 +1,314 @@
|
||||
# Welcome to your Lovable project
|
||||
# 🐳 Docker WebUI
|
||||
|
||||
## Project info
|
||||
A lightweight, self-hosted web interface for monitoring and controlling Docker containers in real-time.
|
||||
|
||||
**URL**: https://lovable.dev/projects/ba519789-1c3e-4fe3-a965-cdc4a30e6a8b
|
||||
## ✨ Features
|
||||
|
||||
## How can I edit this code?
|
||||
- **Real-time Monitoring** - Live metrics via WebSocket (CPU, memory, network, I/O)
|
||||
- **Auto-discovery** - Containers created/removed via CLI appear instantly in UI
|
||||
- **Container Control** - Start, stop, restart containers from the web interface
|
||||
- **Live Logs** - Stream container logs in real-time with filtering
|
||||
- **Discord Alerts** - Per-container notifications on stop/error
|
||||
- **Dark Mode** - Beautiful, responsive interface
|
||||
- **Single Admin** - Simple authentication with one admin user
|
||||
|
||||
There are several ways of editing your application.
|
||||
## 🚀 Quick Start
|
||||
|
||||
**Use Lovable**
|
||||
### Prerequisites
|
||||
|
||||
Simply visit the [Lovable Project](https://lovable.dev/projects/ba519789-1c3e-4fe3-a965-cdc4a30e6a8b) and start prompting.
|
||||
- Docker & Docker Compose
|
||||
- Host with Docker socket access (`/var/run/docker.sock`)
|
||||
|
||||
Changes made via Lovable will be committed automatically to this repo.
|
||||
### Installation
|
||||
|
||||
**Use your preferred IDE**
|
||||
|
||||
If you want to work locally using your own IDE, you can clone this repo and push changes. Pushed changes will also be reflected in Lovable.
|
||||
|
||||
The only requirement is having Node.js & npm installed - [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating)
|
||||
|
||||
Follow these steps:
|
||||
|
||||
```sh
|
||||
# Step 1: Clone the repository using the project's Git URL.
|
||||
git clone <YOUR_GIT_URL>
|
||||
|
||||
# Step 2: Navigate to the project directory.
|
||||
cd <YOUR_PROJECT_NAME>
|
||||
|
||||
# Step 3: Install the necessary dependencies.
|
||||
npm i
|
||||
|
||||
# Step 4: Start the development server with auto-reloading and an instant preview.
|
||||
npm run dev
|
||||
1. Clone this repository:
|
||||
```bash
|
||||
git clone <your-repo-url>
|
||||
cd docker-webui
|
||||
```
|
||||
|
||||
**Edit a file directly in GitHub**
|
||||
2. Copy and configure environment:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
nano .env # Edit admin credentials
|
||||
```
|
||||
|
||||
- Navigate to the desired file(s).
|
||||
- Click the "Edit" button (pencil icon) at the top right of the file view.
|
||||
- Make your changes and commit the changes.
|
||||
3. Set your admin credentials in `.env`:
|
||||
```env
|
||||
ADMIN_EMAIL=admin@example.com
|
||||
ADMIN_PASSWORD=your-secure-password
|
||||
TZ=Europe/Copenhagen
|
||||
```
|
||||
|
||||
**Use GitHub Codespaces**
|
||||
4. Build and start:
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
- Navigate to the main page of your repository.
|
||||
- Click on the "Code" button (green button) near the top right.
|
||||
- Select the "Codespaces" tab.
|
||||
- Click on "New codespace" to launch a new Codespace environment.
|
||||
- Edit files directly within the Codespace and commit and push your changes once you're done.
|
||||
5. Access the UI at `http://your-server-ip:8080`
|
||||
|
||||
## What technologies are used for this project?
|
||||
6. **First Login:**
|
||||
- Navigate to `/settings` in your browser
|
||||
- Click "Sign Up" to create the admin account
|
||||
- Use the credentials from your `.env` file
|
||||
- After creating the account, login with the same credentials
|
||||
|
||||
This project is built with:
|
||||
## 🔧 Configuration
|
||||
|
||||
- Vite
|
||||
- TypeScript
|
||||
- React
|
||||
- shadcn-ui
|
||||
- Tailwind CSS
|
||||
### Docker Compose
|
||||
|
||||
## How can I deploy this project?
|
||||
The service uses **host networking mode** for direct Docker socket access and requires:
|
||||
- `/var/run/docker.sock` (read-only) - Docker API access
|
||||
- `/proc` (read-only) - Host system metrics
|
||||
|
||||
Simply open [Lovable](https://lovable.dev/projects/ba519789-1c3e-4fe3-a965-cdc4a30e6a8b) and click on Share -> Publish.
|
||||
### Environment Variables
|
||||
|
||||
## Can I connect a custom domain to my Lovable project?
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `ADMIN_EMAIL` | `admin@docker-webui.local` | Admin email address |
|
||||
| `ADMIN_PASSWORD` | `changeme123` | Admin password (min 6 chars) |
|
||||
| `TZ` | `Europe/Copenhagen` | Server timezone |
|
||||
|
||||
Yes, you can!
|
||||
### Changing the Port
|
||||
|
||||
To connect a domain, navigate to Project > Settings > Domains and click Connect Domain.
|
||||
Edit `nginx.conf`:
|
||||
```nginx
|
||||
server {
|
||||
listen 8082; # Change from 8080 to your desired port
|
||||
server_name _;
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
Read more here: [Setting up a custom domain](https://docs.lovable.dev/features/custom-domain#custom-domain)
|
||||
Then rebuild:
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## 📊 Usage
|
||||
|
||||
### Dashboard
|
||||
- **Host Metrics** - CPU, RAM, network, uptime
|
||||
- **Container List** - All containers with live stats
|
||||
- **Quick Actions** - Start/stop/restart buttons
|
||||
- **Auto-refresh** - Updates every 2-5 seconds
|
||||
|
||||
### Container Details
|
||||
- Real-time metrics graphs
|
||||
- Live log streaming (no storage, ephemeral)
|
||||
- Container configuration details
|
||||
- Per-container alert settings
|
||||
|
||||
### Settings
|
||||
- Discord webhook configuration
|
||||
- Metrics refresh interval
|
||||
- Alert debounce settings
|
||||
- Error pattern regex
|
||||
|
||||
## 🔔 Discord Alerts
|
||||
|
||||
Set up per-container Discord notifications:
|
||||
|
||||
1. Create a Discord webhook in your server
|
||||
2. In WebUI Settings, add your webhook URL
|
||||
3. Enable alerts for specific containers
|
||||
4. Configure triggers:
|
||||
- **Container Stopped** - Alert when container stops/crashes
|
||||
- **Error Pattern** - Match regex in logs (default: `(?i)(error|err|exception|traceback|crit(ical)?)`)
|
||||
|
||||
Example alert:
|
||||
```json
|
||||
{
|
||||
"username": "Docker WebUI",
|
||||
"embeds": [{
|
||||
"title": "Container Stopped",
|
||||
"color": 15158332,
|
||||
"fields": [
|
||||
{"name": "Container", "value": "redis:prod"},
|
||||
{"name": "Reason", "value": "stop event"},
|
||||
{"name": "Time", "value": "2025-10-20T10:22:31Z"}
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
⚠️ **Important Security Considerations:**
|
||||
|
||||
- **Root Required** - Container needs root access to Docker socket
|
||||
- **Trusted Hosts Only** - Docker socket access = full system control
|
||||
- **Single Admin** - Only one user (configured via env vars)
|
||||
- **Read-only Mounts** - Socket and `/proc` are mounted read-only
|
||||
- **No Public Exposure** - Always use behind HTTPS reverse proxy
|
||||
- **Audit Logging** - All control actions logged to database
|
||||
|
||||
### Reverse Proxy Setup (Recommended)
|
||||
|
||||
Example Nginx configuration:
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name docker.example.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Tech Stack
|
||||
|
||||
- **Frontend**: React 18 + TypeScript + Vite
|
||||
- **Backend**: Lovable Cloud (Supabase)
|
||||
- **UI Framework**: shadcn/ui + Tailwind CSS
|
||||
- **Real-time**: WebSocket for metrics streaming
|
||||
- **Deployment**: Docker + Nginx
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start dev server
|
||||
npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
docker-webui/
|
||||
├── src/
|
||||
│ ├── pages/ # Dashboard, Login, Settings
|
||||
│ ├── components/ # Reusable UI components
|
||||
│ ├── hooks/ # Custom React hooks
|
||||
│ └── integrations/ # Supabase client
|
||||
├── supabase/
|
||||
│ ├── functions/ # Edge functions (Docker API)
|
||||
│ └── config.toml # Function configuration
|
||||
├── Dockerfile # Multi-stage build
|
||||
├── nginx.conf # Web server config
|
||||
└── docker-compose.yml # Service definition
|
||||
```
|
||||
|
||||
## 📝 Architecture
|
||||
|
||||
```
|
||||
┌──────────────┐ WebSocket ┌───────────────┐
|
||||
│ Browser │◄────────────────────────►│ docker-metrics│
|
||||
│ (React) │ │ Edge Function │
|
||||
└──────────────┘ └───────┬───────┘
|
||||
│
|
||||
┌──────────────┐ REST API ┌───────▼───────┐
|
||||
│ Dashboard │◄────────────────────────►│ docker-api │
|
||||
│ Frontend │ │ Edge Function │
|
||||
└──────────────┘ └───────┬───────┘
|
||||
│
|
||||
┌──────▼─────────┐
|
||||
│ /var/run/ │
|
||||
│ docker.sock │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
**Flow:**
|
||||
1. Frontend connects via WebSocket for real-time metrics
|
||||
2. Backend edge functions read Docker socket via Unix socket
|
||||
3. Container stats streamed every 2 seconds
|
||||
4. Container list auto-updates via polling + WebSocket
|
||||
|
||||
## 🚀 Features in Detail
|
||||
|
||||
### Auto-Discovery
|
||||
- Detects new containers within 5 seconds
|
||||
- Automatically removes deleted containers from UI
|
||||
- No manual refresh needed
|
||||
- Works with `docker run`, `docker-compose`, etc.
|
||||
|
||||
### Live Metrics
|
||||
- **Host**: CPU %, RAM usage, network I/O, uptime
|
||||
- **Containers**: CPU %, memory, network RX/TX, block I/O
|
||||
- **Refresh**: 2-second intervals via WebSocket
|
||||
- **No Storage**: All metrics are ephemeral (not saved)
|
||||
|
||||
### Log Streaming
|
||||
- Streams directly from Docker (no disk storage)
|
||||
- Client-side regex filtering
|
||||
- Color-coded timestamps
|
||||
- Auto-scroll with pause/resume
|
||||
- Logs disappear on browser close
|
||||
|
||||
## 🔮 Roadmap
|
||||
|
||||
- [ ] Multi-host support (lightweight agent model)
|
||||
- [ ] Historical metrics with charts
|
||||
- [ ] Advanced health check rules
|
||||
- [ ] Multi-language UI (English/Danish)
|
||||
- [ ] Docker Compose stack management
|
||||
- [ ] Volume and network management
|
||||
- [ ] Resource limits configuration
|
||||
|
||||
## ⚠️ Limitations
|
||||
|
||||
- **No Shell Access** - WebUI does not provide terminal/exec access
|
||||
- **No Log Storage** - Logs stream live but are not persisted
|
||||
- **Single Host** - Multi-host requires future agent architecture
|
||||
- **Rate Limits** - Discord webhooks have rate limits (use debounce)
|
||||
- **Root Access** - Requires privileged Docker socket access
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Container not accessible from browser
|
||||
- Check that you're using host networking mode
|
||||
- Verify firewall allows port 8080
|
||||
- Try accessing via `http://HOST_IP:8080`
|
||||
|
||||
### Metrics not updating
|
||||
- Check WebSocket connection (WiFi icon in header)
|
||||
- Verify `/var/run/docker.sock` is mounted
|
||||
- Check edge function logs in Lovable Cloud
|
||||
|
||||
### Can't login
|
||||
- Ensure you created the admin account first (Settings → Sign Up)
|
||||
- Verify credentials match `.env` file
|
||||
- Check browser console for errors
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT License
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions welcome! Please:
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Commit your changes
|
||||
4. Open a Pull Request
|
||||
|
||||
## 💬 Support
|
||||
|
||||
- **Issues**: Report bugs via GitHub Issues
|
||||
- **Discussions**: Ask questions in GitHub Discussions
|
||||
- **Documentation**: See inline code comments
|
||||
|
||||
---
|
||||
|
||||
**Built with ❤️ using [Lovable](https://lovable.dev)**
|
||||
|
||||
Deploy on trusted infrastructure only. Docker socket access = full system control.
|
||||
|
||||
253
SETUP.md
Normal file
253
SETUP.md
Normal file
@@ -0,0 +1,253 @@
|
||||
# Docker WebUI Setup Guide
|
||||
|
||||
## First-Time Setup
|
||||
|
||||
### Step 1: Configure Environment
|
||||
|
||||
1. Copy the example environment file:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
2. Edit `.env` with your admin credentials:
|
||||
```env
|
||||
ADMIN_EMAIL=admin@example.com
|
||||
ADMIN_PASSWORD=YourSecurePassword123
|
||||
TZ=Europe/Copenhagen
|
||||
```
|
||||
|
||||
### Step 2: Build and Start
|
||||
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
This will:
|
||||
- Build the React frontend
|
||||
- Create the Docker container
|
||||
- Mount `/var/run/docker.sock` (read-only)
|
||||
- Mount `/proc` for host metrics
|
||||
- Start the web server on port 8080
|
||||
|
||||
### Step 3: Create Admin Account
|
||||
|
||||
⚠️ **Important**: You must create the admin account before you can login.
|
||||
|
||||
1. Open your browser to `http://your-server-ip:8080`
|
||||
2. You'll see the login page
|
||||
3. Click on the Settings page link (or navigate to `/settings`)
|
||||
4. Look for the "Sign Up" option
|
||||
5. Enter the EXACT credentials from your `.env` file:
|
||||
- Email: The value from `ADMIN_EMAIL`
|
||||
- Password: The value from `ADMIN_PASSWORD`
|
||||
6. Submit the signup form
|
||||
|
||||
### Step 4: Login
|
||||
|
||||
After creating the account:
|
||||
1. Return to the login page (`/login`)
|
||||
2. Login with your admin credentials
|
||||
3. You'll be redirected to the dashboard
|
||||
|
||||
## System Requirements
|
||||
|
||||
- **Docker**: 20.10+
|
||||
- **Docker Compose**: 1.29+
|
||||
- **OS**: Linux (tested on Ubuntu 20.04+, Debian 11+)
|
||||
- **RAM**: Minimum 512MB available
|
||||
- **Network**: Port 8080 available (or customize in nginx.conf)
|
||||
|
||||
## Port Configuration
|
||||
|
||||
The default port is **8080**. To change it:
|
||||
|
||||
1. Edit `nginx.conf`:
|
||||
```nginx
|
||||
server {
|
||||
listen 8082; # Change this
|
||||
server_name _;
|
||||
# ... rest of config
|
||||
}
|
||||
```
|
||||
|
||||
2. Rebuild the container:
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## Reverse Proxy Setup (Recommended)
|
||||
|
||||
For production, always use HTTPS via a reverse proxy.
|
||||
|
||||
### Nginx Reverse Proxy
|
||||
|
||||
Create `/etc/nginx/sites-available/docker-webui`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name docker.yourdomain.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/docker.yourdomain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/docker.yourdomain.com/privkey.pem;
|
||||
|
||||
# Security headers
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# WebSocket support
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Headers
|
||||
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;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
}
|
||||
|
||||
# Redirect HTTP to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name docker.yourdomain.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
Enable and restart:
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/docker-webui /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Traefik (Docker)
|
||||
|
||||
Add labels to `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
docker-webui:
|
||||
# ... existing config
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.docker-webui.rule=Host(`docker.yourdomain.com`)"
|
||||
- "traefik.http.routers.docker-webui.entrypoints=websecure"
|
||||
- "traefik.http.routers.docker-webui.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.docker-webui.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
## Firewall Configuration
|
||||
|
||||
If using UFW:
|
||||
```bash
|
||||
# Allow from specific IP
|
||||
sudo ufw allow from 192.168.1.0/24 to any port 8080
|
||||
|
||||
# Or allow from anywhere (not recommended)
|
||||
sudo ufw allow 8080/tcp
|
||||
```
|
||||
|
||||
## Discord Webhook Setup
|
||||
|
||||
1. In Discord, go to Server Settings → Integrations → Webhooks
|
||||
2. Click "New Webhook"
|
||||
3. Name it "Docker WebUI"
|
||||
4. Copy the webhook URL
|
||||
5. In Docker WebUI, go to Settings
|
||||
6. Paste webhook URL
|
||||
7. Configure per-container alerts
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Cannot connect to Docker daemon"
|
||||
|
||||
Check socket permissions:
|
||||
```bash
|
||||
ls -la /var/run/docker.sock
|
||||
# Should show: srw-rw---- 1 root docker
|
||||
|
||||
# Add your user to docker group
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker
|
||||
```
|
||||
|
||||
### WebUI not accessible from other machines
|
||||
|
||||
Check host networking:
|
||||
```bash
|
||||
# Verify the container is using host network
|
||||
docker inspect docker-webui | grep NetworkMode
|
||||
# Should show: "NetworkMode": "host"
|
||||
|
||||
# Check if port is listening
|
||||
sudo netstat -tulpn | grep 8080
|
||||
```
|
||||
|
||||
### Metrics not updating
|
||||
|
||||
1. Check WebSocket connection (WiFi icon in header)
|
||||
2. View edge function logs in Lovable Cloud
|
||||
3. Verify container can access Docker socket:
|
||||
```bash
|
||||
docker exec docker-webui ls -la /var/run/docker.sock
|
||||
```
|
||||
|
||||
### High CPU usage
|
||||
|
||||
Reduce metrics refresh interval in Settings:
|
||||
- Default: 2000ms (2 seconds)
|
||||
- Recommended for many containers: 5000ms (5 seconds)
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Change default credentials** in `.env` before first run
|
||||
2. **Use strong passwords** (minimum 12 characters)
|
||||
3. **Enable HTTPS** via reverse proxy
|
||||
4. **Restrict network access** to trusted IPs only
|
||||
5. **Keep Docker updated** for security patches
|
||||
6. **Review audit logs** regularly for suspicious activity
|
||||
7. **Backup configuration** and database regularly
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
# Pull latest changes
|
||||
git pull
|
||||
|
||||
# Rebuild and restart
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
# Stop and remove container
|
||||
docker-compose down
|
||||
|
||||
# Remove images
|
||||
docker rmi docker-webui:latest
|
||||
|
||||
# Remove volumes (if any)
|
||||
docker volume prune
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
- GitHub Issues: Report bugs
|
||||
- GitHub Discussions: Ask questions
|
||||
- Documentation: Check README.md
|
||||
@@ -9,6 +9,8 @@ services:
|
||||
network_mode: host
|
||||
environment:
|
||||
- TZ=${TZ:-Europe/Copenhagen}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@docker-webui.local}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme123}
|
||||
volumes:
|
||||
# Mount Docker socket for container management (read-only for safety)
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
@@ -125,27 +125,6 @@ export type Database = {
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
profiles: {
|
||||
Row: {
|
||||
created_at: string | null
|
||||
id: string
|
||||
updated_at: string | null
|
||||
username: string
|
||||
}
|
||||
Insert: {
|
||||
created_at?: string | null
|
||||
id: string
|
||||
updated_at?: string | null
|
||||
username: string
|
||||
}
|
||||
Update: {
|
||||
created_at?: string | null
|
||||
id?: string
|
||||
updated_at?: string | null
|
||||
username?: string
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
[_ in never]: never
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Server, Lock, Mail } from "lucide-react";
|
||||
import { Server, Lock, Mail, Shield } from "lucide-react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
@@ -10,45 +10,23 @@ import { useToast } from "@/components/ui/use-toast";
|
||||
const Login = () => {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [isSignup, setIsSignup] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleAuth = async (e: React.FormEvent) => {
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
if (isSignup) {
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: {
|
||||
data: {
|
||||
username: email.split('@')[0]
|
||||
}
|
||||
}
|
||||
});
|
||||
const { error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
if (error) throw error;
|
||||
|
||||
toast({
|
||||
title: "Account created!",
|
||||
description: "You can now log in.",
|
||||
});
|
||||
setIsSignup(false);
|
||||
setPassword("");
|
||||
} else {
|
||||
const { error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
navigate("/dashboard");
|
||||
}
|
||||
navigate("/dashboard");
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: "Authentication failed",
|
||||
@@ -69,21 +47,21 @@ const Login = () => {
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold text-foreground mb-2">Docker WebUI</h1>
|
||||
<p className="text-muted-foreground text-center">
|
||||
{isSignup ? 'Create an account to get started' : 'Lightweight container monitoring and control'}
|
||||
Admin access only
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleAuth} className="space-y-4">
|
||||
<form onSubmit={handleLogin} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="email" className="text-sm font-medium text-foreground">
|
||||
Email
|
||||
Admin Email
|
||||
</label>
|
||||
<div className="relative">
|
||||
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="admin@example.com"
|
||||
placeholder="admin@docker-webui.local"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="pl-10 bg-secondary border-border"
|
||||
@@ -118,29 +96,23 @@ const Login = () => {
|
||||
className="w-full bg-primary hover:bg-primary/90"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? 'Processing...' : (isSignup ? 'Sign Up' : 'Sign In')}
|
||||
{loading ? 'Signing in...' : 'Sign In'}
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
<div className="mt-4 text-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setIsSignup(!isSignup);
|
||||
setPassword("");
|
||||
}}
|
||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
disabled={loading}
|
||||
>
|
||||
{isSignup ? 'Already have an account? Sign in' : "Don't have an account? Sign up"}
|
||||
</button>
|
||||
<div className="mt-6 p-4 rounded-lg bg-primary/5 border border-primary/20">
|
||||
<div className="flex items-start gap-2">
|
||||
<Shield className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<p className="font-semibold text-foreground mb-1">Single Admin System</p>
|
||||
<p>Admin credentials are configured in docker-compose.yml via environment variables:</p>
|
||||
<ul className="mt-2 space-y-1 text-xs font-mono">
|
||||
<li>• ADMIN_EMAIL</li>
|
||||
<li>• ADMIN_PASSWORD</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isSignup && (
|
||||
<p className="mt-6 text-xs text-center text-muted-foreground">
|
||||
Secure authentication powered by Lovable Cloud
|
||||
</p>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
-- Remove profiles table (not needed for single admin user)
|
||||
DROP TABLE IF EXISTS public.profiles CASCADE;
|
||||
|
||||
-- Remove the trigger and function for auto-creating profiles
|
||||
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
|
||||
DROP FUNCTION IF EXISTS public.handle_new_user() CASCADE;
|
||||
|
||||
-- Update global_settings to not require user_id (single admin)
|
||||
ALTER TABLE public.global_settings DROP CONSTRAINT IF EXISTS global_settings_user_id_fkey;
|
||||
ALTER TABLE public.global_settings ALTER COLUMN user_id DROP NOT NULL;
|
||||
|
||||
-- Update container_settings to not require user_id
|
||||
ALTER TABLE public.container_settings DROP CONSTRAINT IF EXISTS container_settings_user_id_fkey;
|
||||
ALTER TABLE public.container_settings ALTER COLUMN user_id DROP NOT NULL;
|
||||
|
||||
-- Update audit_logs to not require user_id
|
||||
ALTER TABLE public.audit_logs DROP CONSTRAINT IF EXISTS audit_logs_user_id_fkey;
|
||||
ALTER TABLE public.audit_logs ALTER COLUMN user_id DROP NOT NULL;
|
||||
|
||||
-- Update RLS policies for single admin
|
||||
DROP POLICY IF EXISTS "Users can view their own settings" ON public.global_settings;
|
||||
DROP POLICY IF EXISTS "Users can insert their own settings" ON public.global_settings;
|
||||
DROP POLICY IF EXISTS "Users can update their own settings" ON public.global_settings;
|
||||
|
||||
CREATE POLICY "Admin can manage global settings"
|
||||
ON public.global_settings FOR ALL
|
||||
USING (true)
|
||||
WITH CHECK (true);
|
||||
|
||||
DROP POLICY IF EXISTS "Users can view their own container settings" ON public.container_settings;
|
||||
DROP POLICY IF EXISTS "Users can insert their own container settings" ON public.container_settings;
|
||||
DROP POLICY IF EXISTS "Users can update their own container settings" ON public.container_settings;
|
||||
DROP POLICY IF EXISTS "Users can delete their own container settings" ON public.container_settings;
|
||||
|
||||
CREATE POLICY "Admin can manage container settings"
|
||||
ON public.container_settings FOR ALL
|
||||
USING (true)
|
||||
WITH CHECK (true);
|
||||
|
||||
DROP POLICY IF EXISTS "Users can view their own audit logs" ON public.audit_logs;
|
||||
DROP POLICY IF EXISTS "Users can insert their own audit logs" ON public.audit_logs;
|
||||
|
||||
CREATE POLICY "Admin can view audit logs"
|
||||
ON public.audit_logs FOR ALL
|
||||
USING (true)
|
||||
WITH CHECK (true);
|
||||
|
||||
-- Create function to initialize admin settings on first login
|
||||
CREATE OR REPLACE FUNCTION public.ensure_admin_settings()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
-- Create default global settings if they don't exist
|
||||
INSERT INTO public.global_settings (user_id)
|
||||
SELECT NEW.id
|
||||
WHERE NOT EXISTS (SELECT 1 FROM public.global_settings LIMIT 1);
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;
|
||||
|
||||
-- Trigger to ensure settings exist when admin logs in
|
||||
CREATE TRIGGER ensure_admin_settings_on_login
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW EXECUTE FUNCTION public.ensure_admin_settings();
|
||||
Reference in New Issue
Block a user