Files
SneakyScan/docs/DEPLOYMENT.md
Phillip Tarrant 5e3a70f837 Fix schedule management and update documentation for database-backed configs
This commit addresses multiple issues with schedule management and updates
  documentation to reflect the transition from YAML-based to database-backed
  configuration system.

  **Documentation Updates:**
  - Update DEPLOYMENT.md to remove all references to YAML config files
  - Document that all configurations are now stored in SQLite database
  - Update API examples to use config IDs instead of YAML filenames
  - Remove configs directory from backup/restore procedures
  - Update volume management section to reflect database-only storage

  **Cron Expression Handling:**
  - Add comprehensive documentation for APScheduler cron format conversion
  - Document that from_crontab() accepts standard format (Sunday=0) and converts automatically
  - Add validate_cron_expression() helper method with detailed error messages
  - Include helpful hints for day-of-week field errors in validation
  - Fix all deprecated datetime.utcnow() calls, replace with datetime.now(timezone.utc)

  **Timezone-Aware DateTime Fixes:**
  - Fix "can't subtract offset-naive and offset-aware datetimes" error
  - Add timezone awareness to croniter.get_next() return values
  - Make _get_relative_time() defensive to handle both naive and aware datetimes
  - Ensure all datetime comparisons use timezone-aware objects

  **Schedule Edit UI Fixes:**
  - Fix JavaScript error "Cannot set properties of null (setting 'value')"
  - Change reference from non-existent 'config-id' to correct 'config-file' element
  - Add config_name field to schedule API responses for better UX
  - Eagerly load Schedule.config relationship using joinedload()
  - Fix AttributeError: use schedule.config.title instead of .name
  - Display config title and ID in schedule edit form

  **Technical Details:**
  - app/web/services/schedule_service.py: 6 datetime.utcnow() fixes, validation enhancements
  - app/web/services/scheduler_service.py: Documentation, validation, timezone fixes
  - app/web/templates/schedule_edit.html: JavaScript element reference fix
  - docs/DEPLOYMENT.md: Complete rewrite of config management sections

  Fixes scheduling for Sunday at midnight (cron: 0 0 * * 0)
  Fixes schedule edit page JavaScript errors
  Improves user experience with config title display
2025-11-24 12:53:06 -06:00

1125 lines
30 KiB
Markdown

# SneakyScanner Deployment Guide
## Table of Contents
1. [Overview](#overview)
2. [Prerequisites](#prerequisites)
3. [Quick Start](#quick-start)
4. [Configuration](#configuration)
5. [First-Time Setup](#first-time-setup)
6. [Running the Application](#running-the-application)
7. [Using the Web Interface](#using-the-web-interface)
8. [Volume Management](#volume-management)
9. [Health Monitoring](#health-monitoring)
10. [Troubleshooting](#troubleshooting)
11. [Security Considerations](#security-considerations)
12. [Upgrading](#upgrading)
13. [Backup and Restore](#backup-and-restore)
---
## Overview
SneakyScanner is deployed as a Docker container running a Flask web application with an integrated network scanner. The application requires privileged mode and host networking to perform network scans using masscan and nmap.
**Architecture:**
- **Web Application**: Flask app on port 5000 with modern web UI
- **Database**: SQLite (persisted to volume) - stores all configurations, scan results, and settings
- **Background Jobs**: APScheduler for async scan execution
- **Scanner**: masscan, nmap, sslyze, Playwright
- **Config Management**: Database-backed configuration system managed entirely via web UI
- **Scheduling**: Cron-based scheduled scans with dashboard management
---
## Prerequisites
### System Requirements
- **Operating System**: Linux (Ubuntu 20.04+, Debian 11+, or similar)
- **Docker**: Version 20.10+ or Docker Engine 24.0+
- **Docker Compose**: Version 2.0+ (or docker-compose 1.29+)
- **Memory**: Minimum 2GB RAM (4GB+ recommended)
- **Disk Space**: Minimum 5GB free space
- **Permissions**: Root/sudo access for Docker privileged mode
### Network Requirements
- Outbound internet access for Docker image downloads
- Access to target networks for scanning
- Port 5000 available on host (or configure alternative)
### Install Docker and Docker Compose
**Ubuntu/Debian:**
```bash
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add your user to docker group
sudo usermod -aG docker $USER
newgrp docker
# Verify installation
docker --version
docker compose version
```
**Other Linux distributions:** See [Docker installation guide](https://docs.docker.com/engine/install/)
---
## Quick Start
For users who want to get started immediately with the web application:
**Option 1: Automated Setup (Recommended)**
```bash
# 1. Clone the repository
git clone <repository-url>
cd SneakyScan
# 2. Run the setup script
./setup.sh
# 3. Access the web interface
# Open browser to: http://localhost:5000
# Login with password from ./admin_password.txt or ./logs/admin_password.txt
```
The setup script automatically:
- Generates secure random keys (SECRET_KEY, ENCRYPTION_KEY)
- Prompts for password or generates a random one
- Creates required directories
- Builds Docker image
- Starts the application
- Auto-initializes database on first run
**Option 2: Manual Setup**
```bash
# 1. Clone the repository
git clone <repository-url>
cd SneakyScan
# 2. Create environment file
cp .env.example .env
# Edit .env and set SECRET_KEY and SNEAKYSCANNER_ENCRYPTION_KEY
# Optionally set INITIAL_PASSWORD (leave blank for auto-generation)
nano .env
# 3. Build and start (database auto-initializes on first run)
docker compose up --build -d
# 4. Check logs for auto-generated password (if not set in .env)
docker compose logs web | grep "Password"
# Or check: ./logs/admin_password.txt
# 5. Access the web interface
# Open browser to: http://localhost:5000
```
**Alternative: Standalone CLI Scanner**
For quick one-off scans without the web interface:
```bash
# Build and run with standalone compose file
docker compose -f docker-compose-standalone.yml build
docker compose -f docker-compose-standalone.yml up
# Results saved to ./output/ directory
```
**Note**: `docker-compose.yml` (web application) is now the default. Use `docker-compose-standalone.yml` for CLI-only scans.
---
## Configuration
### Environment Variables
SneakyScanner is configured via environment variables. The recommended approach is to use a `.env` file.
**UDP Port Scanning**
- UDP Port scanning is disabled by default.
- You can turn it on via the .env variable.
- By Default, UDP port scanning only scans the top 20 ports, for convenience I have included the NMAP top 100 UDP ports as well.
#### Creating Your .env File
```bash
# Copy the example file
cp .env.example .env
# Generate secure keys
# SECRET_KEY: Flask session secret (64-character hex string)
python3 -c "import secrets; print('SECRET_KEY=' + secrets.token_hex(32))" >> .env
# SNEAKYSCANNER_ENCRYPTION_KEY: Fernet key for database encryption (32 url-safe base64 bytes)
python3 -c "from cryptography.fernet import Fernet; print('SNEAKYSCANNER_ENCRYPTION_KEY=' + Fernet.generate_key().decode())" >> .env
# Edit other settings as needed
nano .env
```
#### Key Configuration Options
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `FLASK_ENV` | Environment mode (`production` or `development`) | `production` | Yes |
| `FLASK_DEBUG` | Enable debug mode (`true` or `false`) | `false` | Yes |
| `SECRET_KEY` | Flask session secret (change in production!) | `dev-secret-key-change-in-production` | **Yes** |
| `SNEAKYSCANNER_ENCRYPTION_KEY` | Encryption key for sensitive settings | (empty) | **Yes** |
| `DATABASE_URL` | SQLite database path | `sqlite:////app/data/sneakyscanner.db` | Yes |
| `INITIAL_PASSWORD` | Password for first-run initialization (leave empty to auto-generate) | (empty) | No |
| `LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `INFO` | No |
| `SCHEDULER_EXECUTORS` | Number of concurrent scan threads | `2` | No |
| `SCHEDULER_JOB_DEFAULTS_MAX_INSTANCES` | Max instances of same job | `3` | No |
| `CORS_ORIGINS` | CORS allowed origins (comma-separated) | `*` | No |
**Important Security Note:**
- **ALWAYS** change `SECRET_KEY` and `SNEAKYSCANNER_ENCRYPTION_KEY` in production
- Never commit `.env` file to version control
- Use strong, randomly-generated keys
---
## First-Time Setup
### Step 1: Prepare Directories
The application needs these directories (created automatically by Docker):
```bash
# Verify directories exist
ls -la data/ output/ logs/
# If missing, create them
mkdir -p data output logs
```
### Step 2: Configure Scan Targets
After starting the application, create scan configurations using the web UI:
**Creating Configurations via Web UI**
1. Navigate to **Configs** in the web interface
2. Click **"Create New Config"**
3. Use the form-based config creator:
- Enter site name
- Enter CIDR range (e.g., `192.168.1.0/24`)
- Select expected TCP/UDP ports from dropdowns
- Optionally enable ping checks
4. Click **"Save Configuration"**
5. Configuration is saved to database and immediately available for scans and schedules
**Note**: All configurations are stored in the database, not as files. This provides better reliability, easier backup, and seamless management through the web interface.
### Step 3: Build Docker Image
```bash
# Build the image (takes 5-10 minutes on first run)
docker compose -f docker-compose.yml build
# Verify image was created
docker images | grep sneakyscanner
```
### Step 4: Initialize Database
**Automatic Initialization (Recommended)**
As of Phase 5, the database is automatically initialized on first run:
```bash
# Just start the application
docker compose up -d
# On first run, the entrypoint script will:
# - Detect no existing database
# - Generate a random password (if INITIAL_PASSWORD not set in .env)
# - Save password to ./logs/admin_password.txt
# - Initialize database schema
# - Create default settings and alert rules
# - Start the Flask application
# Check logs to see the auto-generated password
docker compose logs web | grep "Password"
# Or view the password file
cat logs/admin_password.txt
```
**Manual Initialization (Advanced)**
You can still manually initialize the database if needed:
```bash
# Initialize database and set application password
docker compose run --rm init-db --password "YourSecurePassword" --force
# The init-db command will:
# - Create database schema
# - Set the application password (bcrypt hashed)
# - Create default settings with encryption
# - Create default alert rules
# Verify database was created
ls -lh data/sneakyscanner.db
```
**Password Management:**
- Leave `INITIAL_PASSWORD` blank in `.env` for auto-generation
- Auto-generated passwords are saved to `./logs/admin_password.txt`
- For custom password, set `INITIAL_PASSWORD` in `.env`
- Minimum 8 characters recommended
- Use a strong, unique password
- Store securely (password manager)
**Note**: The init-db service is defined with `profiles: [tools]` in docker-compose.yml, which means it won't start automatically with `docker compose up`. However, the web service now handles initialization automatically via the entrypoint script.
### Step 5: Verify Configuration
```bash
# Check database file was created
ls -lh data/sneakyscanner.db
# Verify Docker Compose configuration
docker compose -f docker-compose.yml config
```
---
## Running the Application
### Starting the Application
```bash
# Start in detached mode (background)
docker compose -f docker-compose.yml up -d
# View logs during startup
docker compose -f docker-compose.yml logs -f web
# Expected output:
# web_1 | INFO:werkzeug: * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
```
### Accessing the Web Interface
1. Open browser to: **http://localhost:5000**
2. Login with the password you set during database initialization (username is not required - single-user mode)
3. Dashboard will display:
- Recent scans with status indicators
- Summary statistics (total scans, IPs, ports, services)
- Trend charts showing infrastructure changes over time
- Quick actions (run scan, create config, view schedules)
### Stopping the Application
```bash
# Stop containers (preserves data)
docker compose -f docker-compose.yml down
# Stop and remove volumes (WARNING: deletes all data!)
docker compose -f docker-compose.yml down -v
```
### Restarting the Application
```bash
# Restart all services
docker compose -f docker-compose.yml restart
# Restart only the web service
docker compose -f docker-compose.yml restart web
```
### Viewing Logs
```bash
# View all logs
docker compose -f docker-compose.yml logs
# Follow logs in real-time
docker compose -f docker-compose.yml logs -f
# View last 100 lines
docker compose -f docker-compose.yml logs --tail=100
# View logs for specific service
docker compose -f docker-compose.yml logs web
```
---
## Using the Web Interface
### Dashboard Overview
The dashboard provides a central view of your scanning activity:
**Key Sections:**
- **Summary Statistics**: Total scans, IPs discovered, open ports, services detected
- **Recent Scans**: Last 10 scans with status, timestamp, and quick actions
- **Trend Charts**: Port count trends over time using Chart.js
- **Quick Actions**: Buttons to run scans, create configs, manage schedules
### Managing Scan Configurations
All scan configurations are stored in the database and managed entirely through the web interface.
**Creating Configs:**
1. Navigate to **Configs****Create New Config**
2. Fill in the configuration form:
- Enter site name (e.g., "Production Servers")
- Enter CIDR range (e.g., `192.168.1.0/24`)
- Select expected TCP/UDP ports from dropdowns
- Enable/disable ping checks
3. Click **"Save Configuration"**
4. Configuration is immediately stored in database and available for use
**Editing Configs:**
1. Navigate to **Configs** → Select config from list
2. Click **"Edit"** button
3. Modify any fields in the configuration form
4. Click **"Save Changes"** to update database
**Viewing Configs:**
- Navigate to **Configs** page to see all saved configurations
- Each config shows site name, CIDR range, and expected ports
- Click on any config to view full details
**Deleting Configs:**
- Click **"Delete"** button next to any config
- **Warning**: Cannot delete configs used by active schedules
- Deletion removes the configuration from the database permanently
**Note**: All configurations are database-backed, providing automatic backups when you backup the database file.
### Running Scans
**Manual Scans:**
1. Navigate to **Dashboard** or **Scans**
2. Click **"Run Scan Now"**
3. Select configuration file from dropdown
4. Click **"Start Scan"**
5. Scan executes in background (APScheduler)
6. Monitor progress on **Scans** page
**Scheduled Scans:**
1. Navigate to **Schedules****Create Schedule**
2. Enter schedule name (e.g., "Daily production scan")
3. Select config file
4. Enter cron expression (e.g., `0 2 * * *` for 2 AM daily)
5. Enable schedule
6. Scans run automatically in background
**Cron Expression Examples:**
- `0 2 * * *` - Daily at 2 AM
- `0 */6 * * *` - Every 6 hours
- `0 0 * * 0` - Weekly on Sunday at midnight
- `0 0 1 * *` - Monthly on 1st at midnight
### Viewing Scan Results
**Scan List:**
- Navigate to **Scans** page
- View all historical scans with filters
- Click scan ID to view details
**Scan Details:**
- Full scan results organized by site
- Discovered IPs, ports, services
- SSL/TLS certificate information
- TLS version support and cipher suites
- Service version detection
- Screenshots of web services
- Download buttons (JSON, HTML, ZIP)
**Trend Analysis:**
- Charts showing port count changes over time
- Identify infrastructure drift
- Track service version updates
---
## Volume Management
### Understanding Volumes
SneakyScanner uses several mounted volumes for data persistence:
| Volume | Container Path | Purpose | Important? |
|--------|----------------|---------|------------|
| `./data` | `/app/data` | SQLite database (contains configurations, scan history, settings) | **Critical** |
| `./output` | `/app/output` | Scan results (JSON, HTML, ZIP, screenshots) | Yes |
| `./logs` | `/app/logs` | Application logs (rotating file handler) | No |
**Note**: All scan configurations are stored in the SQLite database (`./data/sneakyscanner.db`). There is no separate configs directory or YAML files. Backing up the database file ensures all your configurations are preserved.
### Backing Up Data
```bash
# Create backup directory
mkdir -p backups/$(date +%Y%m%d)
# Backup database (includes all configurations)
cp data/sneakyscanner.db backups/$(date +%Y%m%d)/
# Backup scan outputs
tar -czf backups/$(date +%Y%m%d)/output.tar.gz output/
```
**Important**: The database backup includes all scan configurations, settings, schedules, and scan history. No separate configuration file backup is needed.
### Restoring Data
```bash
# Stop application
docker compose -f docker-compose.yml down
# Restore database (includes all configurations)
cp backups/YYYYMMDD/sneakyscanner.db data/
# Restore outputs
tar -xzf backups/YYYYMMDD/output.tar.gz
# Restart application
docker compose -f docker-compose.yml up -d
```
**Note**: Restoring the database file restores all configurations, settings, schedules, and scan history.
### Cleaning Up Old Scan Results
**Option A: Using the Web UI (Recommended)**
1. Navigate to **Scans** page
2. Select scans you want to delete
3. Click **"Delete"** button
4. Confirm deletion (removes database records and all associated files)
**Option B: Manual Cleanup**
```bash
# Find old scan results (older than 30 days)
find output/ -type f -name "scan_report_*.json" -mtime +30
# Delete old scan results and screenshots
find output/ -type f -mtime +30 -delete
find output/ -type d -empty -delete
# Note: Manual deletion doesn't remove database records
# Use the web UI or API for complete cleanup
```
**Option C: Using the API**
```bash
# Delete a specific scan (removes DB records + files)
curl -X DELETE http://localhost:5000/api/scans/{scan_id} \
-b cookies.txt
```
---
## API Usage Examples
SneakyScanner provides a comprehensive REST API for automation and integration. All API endpoints require authentication via session cookies.
### Authentication
```bash
# Login and save session cookie
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"password": "YourPassword"}' \
-c cookies.txt
# Logout
curl -X POST http://localhost:5000/api/auth/logout \
-b cookies.txt
```
### Config Management
```bash
# List all configs
curl http://localhost:5000/api/configs \
-b cookies.txt
# Get specific config by ID
curl http://localhost:5000/api/configs/1 \
-b cookies.txt
# Create new config
curl -X POST http://localhost:5000/api/configs \
-H "Content-Type: application/json" \
-d '{
"name": "Test Network",
"cidr": "10.0.0.0/24",
"expected_ports": [
{"port": 80, "protocol": "tcp", "service": "http"},
{"port": 443, "protocol": "tcp", "service": "https"}
],
"ping_expected": true
}' \
-b cookies.txt
# Update config
curl -X PUT http://localhost:5000/api/configs/1 \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Test Network",
"cidr": "10.0.1.0/24"
}' \
-b cookies.txt
# Delete config
curl -X DELETE http://localhost:5000/api/configs/1 \
-b cookies.txt
```
### Scan Management
```bash
# Trigger a scan (using config ID from database)
curl -X POST http://localhost:5000/api/scans \
-H "Content-Type: application/json" \
-d '{"config_id": 1}' \
-b cookies.txt
# List all scans
curl http://localhost:5000/api/scans?page=1&per_page=20 \
-b cookies.txt
# Get scan details
curl http://localhost:5000/api/scans/123 \
-b cookies.txt
# Check scan status
curl http://localhost:5000/api/scans/123/status \
-b cookies.txt
# Delete scan
curl -X DELETE http://localhost:5000/api/scans/123 \
-b cookies.txt
```
### Schedule Management
```bash
# List schedules
curl http://localhost:5000/api/schedules \
-b cookies.txt
# Create schedule (using config ID from database)
curl -X POST http://localhost:5000/api/schedules \
-H "Content-Type: application/json" \
-d '{
"name": "Daily Production Scan",
"config_id": 1,
"cron_expression": "0 2 * * *",
"enabled": true
}' \
-b cookies.txt
# Update schedule
curl -X PUT http://localhost:5000/api/schedules/1 \
-H "Content-Type: application/json" \
-d '{"enabled": false}' \
-b cookies.txt
# Manually trigger scheduled scan
curl -X POST http://localhost:5000/api/schedules/1/trigger \
-b cookies.txt
# Delete schedule
curl -X DELETE http://localhost:5000/api/schedules/1 \
-b cookies.txt
```
### Settings Management
```bash
# Get all settings (sanitized - passwords hidden)
curl http://localhost:5000/api/settings \
-b cookies.txt
# Update settings
curl -X PUT http://localhost:5000/api/settings \
-H "Content-Type: application/json" \
-d '{
"retention_days": 90,
"smtp_server": "smtp.gmail.com"
}' \
-b cookies.txt
# Test email configuration
curl -X POST http://localhost:5000/api/settings/test-email \
-b cookies.txt
# Health check (no auth required)
curl http://localhost:5000/api/settings/health
```
### Statistics
```bash
# Get dashboard summary
curl http://localhost:5000/api/stats/summary \
-b cookies.txt
# Get trend data
curl http://localhost:5000/api/stats/trends?days=30&metric=port_count \
-b cookies.txt
# Get certificate expiry overview
curl http://localhost:5000/api/stats/certificates \
-b cookies.txt
```
For complete API documentation, see `docs/API_REFERENCE.md`.
---
## Health Monitoring
### Health Check Endpoint
SneakyScanner includes a built-in health check endpoint used by Docker's healthcheck:
```bash
# Check application health
curl http://localhost:5000/api/settings/health
# Expected response (200 OK):
# {"status": "healthy"}
# This endpoint is also used by Docker Compose healthcheck
# Defined in docker-compose.yml:
# - Interval: 60s (check every minute)
# - Timeout: 10s
# - Retries: 3
# - Start period: 40s (grace period for app startup)
```
### Docker Health Status
```bash
# Check container health status
docker ps | grep sneakyscanner-web
# View health check logs
docker inspect sneakyscanner-web | grep -A 10 Health
```
### Monitoring Logs
```bash
# Watch for errors in logs
docker compose -f docker-compose.yml logs -f | grep ERROR
# Check application log file
tail -f logs/sneakyscanner.log
```
---
## Troubleshooting
### Container Won't Start
**Problem**: Container exits immediately after starting
```bash
# Check logs for errors
docker compose logs web
# Common issues:
# 1. Permission issues with volumes - check directory ownership
# 2. Port 5000 already in use - change FLASK_PORT or stop conflicting service
# 3. Database initialization failed - check logs for specific error
# Check if database initialization is stuck
docker compose logs web | grep -A 20 "First Run Detected"
# If initialization failed, clean up and retry
docker compose down
rm -rf data/.db_initialized # Remove marker file
docker compose up -d
```
### Database Initialization Fails
**Problem**: Automatic database initialization fails on first run
```bash
# Check database directory permissions
ls -la data/
# Fix permissions if needed
sudo chown -R $USER:$USER data/
# View initialization logs
docker compose logs web | grep -A 50 "Initializing database"
# Clean up and retry initialization
docker compose down
rm -rf data/sneakyscanner.db data/.db_initialized
docker compose up -d
# Or manually initialize with specific password
docker compose down
rm -rf data/sneakyscanner.db data/.db_initialized
docker compose run --rm init-db --password "YourPassword" --force
docker compose up -d
```
**Can't Find Password File**
**Problem**: Password file not created or can't be found
```bash
# Check both possible locations
cat admin_password.txt # Created by setup.sh
cat logs/admin_password.txt # Created by Docker entrypoint
# Check container logs for password
docker compose logs web | grep -i password
# If password file is missing, manually set one
docker compose down
docker compose run --rm init-db --password "YourNewPassword" --force
docker compose up -d
```
### Scans Fail with "Permission Denied"
**Problem**: Scanner cannot run masscan/nmap
```bash
# Verify container is running in privileged mode
docker inspect sneakyscanner-web | grep Privileged
# Should show: "Privileged": true
# Verify network mode is host
docker inspect sneakyscanner-web | grep NetworkMode
# Should show: "NetworkMode": "host"
# If not, verify docker-compose.yml has:
# privileged: true
# network_mode: host
```
### Can't Access Web Interface
**Problem**: Browser can't connect to http://localhost:5000
```bash
# Verify container is running
docker ps | grep sneakyscanner-web
# Check if Flask is listening
docker compose -f docker-compose.yml exec web netstat -tlnp | grep 5000
# Check firewall rules
sudo ufw status | grep 5000
# Try from container host
curl http://localhost:5000/api/settings/health
# Check logs for binding errors
docker compose -f docker-compose.yml logs web | grep -i bind
```
### Background Scans Not Running
**Problem**: Scans stay in "running" status forever
```bash
# Check scheduler is initialized
docker compose -f docker-compose.yml logs web | grep -i scheduler
# Check for job execution errors
docker compose -f docker-compose.yml logs web | grep -i "execute_scan"
# Verify APScheduler environment variables
docker compose -f docker-compose.yml exec web env | grep SCHEDULER
# Check for scan job errors
docker compose -f docker-compose.yml logs web | grep -E "(ERROR|Exception|Traceback)"
# Verify scanner executables are available
docker compose -f docker-compose.yml exec web which masscan nmap
```
### Configs Not Appearing in Web UI
**Problem**: Created configs don't show up in web interface
```bash
# Check database connectivity
docker compose -f docker-compose.yml logs web | grep -i "database"
# Verify database file exists and is readable
ls -lh data/sneakyscanner.db
# Check for errors when creating configs
docker compose -f docker-compose.yml logs web | grep -i "config"
# Try accessing configs via API
curl http://localhost:5000/api/configs -b cookies.txt
# If database is corrupted, check integrity
docker compose -f docker-compose.yml exec web sqlite3 /app/data/sneakyscanner.db "PRAGMA integrity_check;"
```
### Health Check Failing
**Problem**: Docker health check shows "unhealthy"
```bash
# Run health check manually
docker compose -f docker-compose.yml exec web \
python3 -c "import urllib.request; print(urllib.request.urlopen('http://localhost:5000/api/settings/health').read())"
# Check if health endpoint exists
curl -v http://localhost:5000/api/settings/health
# Common causes:
# 1. Application crashed - check logs
# 2. Database locked - check for long-running scans
# 3. Flask not fully started - wait 40s (start_period)
```
---
## Security Considerations
### Production Deployment Checklist
- [ ] Changed `SECRET_KEY` to random value (64+ character hex string)
- [ ] Changed `SNEAKYSCANNER_ENCRYPTION_KEY` to random Fernet key
- [ ] Set strong application password via init-db
- [ ] Set `FLASK_ENV=production`
- [ ] Set `FLASK_DEBUG=false`
- [ ] Configured proper `CORS_ORIGINS` (not `*`)
- [ ] Using HTTPS/TLS (reverse proxy recommended)
- [ ] Restricted network access (firewall rules)
- [ ] Regular backups configured (database + configs)
- [ ] Log monitoring enabled
- [ ] Scheduled scans configured with appropriate frequency
- [ ] Alert rules configured (Phase 5 - coming soon)
- [ ] Webhook/email notifications configured (Phase 5 - coming soon)
### Network Security
**Privileged Mode Considerations:**
- Container runs with `--privileged` flag for raw socket access (masscan/nmap)
- This grants extensive host capabilities - only run on trusted networks
- Restrict Docker host access with firewall rules
- Consider running on dedicated scan server
**Recommendations:**
```bash
# Restrict access to port 5000 with firewall
sudo ufw allow from 192.168.1.0/24 to any port 5000
sudo ufw enable
# Or use reverse proxy (nginx, Apache) with authentication
```
### HTTPS/TLS Setup
SneakyScanner does not include built-in TLS. For production, use a reverse proxy:
**Example nginx configuration:**
```nginx
server {
listen 443 ssl http2;
server_name scanner.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:5000;
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;
}
}
```
### File Permissions
```bash
# Ensure proper ownership of data directories
sudo chown -R $USER:$USER data/ output/ logs/
# Restrict database file permissions (contains configurations and sensitive data)
chmod 600 data/sneakyscanner.db
# Ensure database directory is writable
chmod 700 data/
```
---
## Upgrading
### Upgrading to New Version
```bash
# 1. Stop the application
docker compose -f docker-compose.yml down
# 2. Backup database
cp data/sneakyscanner.db data/sneakyscanner.db.backup
# 3. Pull latest code
git pull origin master
# 4. Rebuild Docker image
docker compose -f docker-compose.yml build
# 5. Run database migrations
docker compose -f docker-compose.yml run --rm web alembic upgrade head
# 6. Start application
docker compose -f docker-compose.yml up -d
# 7. Verify upgrade
docker compose -f docker-compose.yml logs -f
curl http://localhost:5000/api/settings/health
```
### Rolling Back
If upgrade fails:
```bash
# Stop new version
docker compose -f docker-compose.yml down
# Restore database backup
cp data/sneakyscanner.db.backup data/sneakyscanner.db
# Checkout previous version
git checkout <previous-version-tag>
# Rebuild and start
docker compose -f docker-compose.yml build
docker compose -f docker-compose.yml up -d
```
---
## Backup and Restore
### Automated Backup Script
Create `backup.sh`:
```bash
#!/bin/bash
BACKUP_DIR="backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# Stop application for consistent backup
docker compose -f docker-compose.yml stop web
# Backup database (includes all configurations)
cp data/sneakyscanner.db "$BACKUP_DIR/"
# Backup outputs (last 30 days only)
find output/ -type f -mtime -30 -exec cp --parents {} "$BACKUP_DIR/" \;
# Restart application
docker compose -f docker-compose.yml start web
echo "Backup complete: $BACKUP_DIR"
echo "Database backup includes all configurations, settings, and scan history"
```
Make executable and schedule with cron:
```bash
chmod +x backup.sh
# Add to crontab (daily at 2 AM)
crontab -e
# Add line:
0 2 * * * /path/to/SneakyScan/backup.sh
```
### Restore from Backup
```bash
# Stop application
docker compose -f docker-compose.yml down
# Restore database (includes all configurations)
cp backups/YYYYMMDD_HHMMSS/sneakyscanner.db data/
# Restore output files
cp -r backups/YYYYMMDD_HHMMSS/output/* output/
# Start application
docker compose -f docker-compose.yml up -d
```
**Note**: Restoring the database file will restore all configurations, settings, schedules, and scan history from the backup.
---
## Support and Further Reading
- **Project README**: `README.md` - General project information
- **API Documentation**: `docs/API_REFERENCE.md` - Complete REST API reference
- **Roadmap**: `docs/ROADMAP.md` - Project roadmap, feature plans, and architecture
- **Issue Tracker**: File bugs and feature requests on GitHub
---
## What's New
### Phase 4+ (2025-11-17) - Database-Backed Configuration System ✅
- **Database-Backed Configs**: All configurations stored in SQLite database (no YAML files)
- **Web-Based Config Creator**: Form-based UI for creating scan configs from CIDR ranges
- **Config Management UI**: List, view, edit, and delete configs via web interface
- **REST API**: Full config management via RESTful API with database storage
- **Schedule Protection**: Prevents deleting configs used by active schedules
- **Automatic Backups**: Configurations included in database backups
### Phase 3 (2025-11-14) - Dashboard & Scheduling ✅
- **Dashboard**: Summary stats, recent scans, trend charts
- **Scheduled Scans**: Cron-based scheduling with web UI management
- **Scan History**: Detailed scan results with full data display
- **Chart.js Integration**: Port count trends over time
### Phase 2 (2025-11-14) - Web Application Core ✅
- **REST API**: Complete API for scan management
- **Background Jobs**: APScheduler-based async execution
- **Authentication**: Session-based login system
- **Database Integration**: SQLite with SQLAlchemy ORM
### Coming Soon: Phase 5 - Email, Webhooks & Comparisons
- Email notifications for infrastructure changes
- Webhook integrations (Slack, PagerDuty, custom)
- Scan comparison reports
- Alert rule configuration
---
**Last Updated**: 2025-11-24
**Version**: Phase 4+ - Database-Backed Configuration System