From 5bf880b5f53c3b12cd51338548f75d56d7fdee15 Mon Sep 17 00:00:00 2001 From: Mohammad Rahjoo Date: Thu, 4 Sep 2025 17:56:33 +0200 Subject: [PATCH] feat: Add Docker support and clickable logo Closes #30: Complete Docker containerization - Add production-ready Dockerfile with nginx - Implement docker-compose.yml with dev/prod profiles - Include comprehensive Docker documentation - Add GitHub Actions for automated builds - Security headers and performance optimizations Closes #40: Make logo clickable - Logo now navigates back to main page - Add hover effects for better UX - Improve accessibility with proper labels Additional improvements: - Dynamic copyright year display - Enhanced documentation - Development tooling (Makefile) - CI/CD pipeline setup --- .dockerignore | 36 +++++ .github/workflows/docker.yml | 75 ++++++++++ DOCKER.md | 280 +++++++++++++++++++++++++++++++++++ Dockerfile | 21 +++ Makefile | 104 +++++++++++++ README.md | 52 +++++++ css/main.css | 5 + docker-compose.yml | 41 +++++ index.html | 6 +- js/main.js | 3 + nginx.conf | 64 ++++++++ 11 files changed, 685 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker.yml create mode 100644 DOCKER.md create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 docker-compose.yml create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..48a7527 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,36 @@ +# Git and version control +.git +.gitignore +.gitattributes + +# Documentation (keep README.md in build) +*.md +!README.md + +# Development files +.vscode +.idea +*.log +*.tmp +.DS_Store +Thumbs.db + +# Node modules (if any) +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Docker files (don't include in build context) +Dockerfile +docker-compose*.yml +.dockerignore + +# CI/CD +.github/ +.gitlab-ci.yml +.travis.yml + +# Local development +*.local +.env diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..da6459e --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,75 @@ +name: Docker Build and Deploy + +on: + push: + branches: [ main, master, gh-pages ] + tags: [ 'v*' ] + pull_request: + branches: [ main, master, gh-pages ] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test Docker image + run: | + docker run --rm -d -p 8080:80 --name test-container ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + sleep 10 + curl -f http://localhost:8080 || exit 1 + docker stop test-container + + deploy: + needs: build + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/gh-pages' + + steps: + - name: Deploy notification + run: | + echo "๐Ÿš€ SQLite Viewer Docker image has been built and pushed successfully!" + echo "๐Ÿ“ฆ Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + echo "๐Ÿ”ง To run locally: docker run -p 8080:80 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..329fdb9 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,280 @@ +# Docker Usage for SQLite Viewer + +This document provides instructions for running SQLite Viewer using Docker. + +## Quick Start + +### Using Docker Compose (Recommended) + +1. **Clone the repository:** + ```bash + git clone https://github.com/inloop/sqlite-viewer.git + cd sqlite-viewer + ``` + +2. **Run with Docker Compose:** + ```bash + docker-compose up -d + ``` + +3. **Access the application:** + Open your browser and navigate to: `http://localhost:8080` + +### Using Docker directly + +1. **Build the image:** + ```bash + docker build -t sqlite-viewer . + ``` + +2. **Run the container:** + ```bash + docker run -d -p 8080:80 --name sqlite-viewer sqlite-viewer + ``` + +3. **Access the application:** + Open your browser and navigate to: `http://localhost:8080` + +## Development Mode + +For development with live file mounting: + +```bash +docker-compose --profile development up -d sqlite-viewer-dev +``` + +This will: +- Mount your local files into the container +- Enable live reload for development +- Run on port 3000: `http://localhost:3000` + +## Configuration Options + +### Environment Variables + +- `NGINX_HOST`: Set the nginx host (default: localhost) +- `NGINX_PORT`: Set the nginx port (default: 80) + +### Volume Mounts + +You can mount SQLite files to share with the container: + +```bash +docker run -d -p 8080:80 \ + -v /path/to/your/sqlite/files:/usr/share/nginx/html/examples:ro \ + --name sqlite-viewer sqlite-viewer +``` + +### Custom nginx Configuration + +To use a custom nginx configuration: + +```bash +docker run -d -p 8080:80 \ + -v /path/to/your/nginx.conf:/etc/nginx/conf.d/default.conf:ro \ + --name sqlite-viewer sqlite-viewer +``` + +## Docker Compose Services + +### Production Service (`sqlite-viewer`) +- **Port**: 8080 +- **Purpose**: Production-ready deployment +- **Features**: Optimized nginx configuration, caching, security headers + +### Development Service (`sqlite-viewer-dev`) +- **Port**: 3000 +- **Purpose**: Development with live file mounting +- **Features**: Live reload, source code mounting +- **Activation**: Use `--profile development` flag + +## Useful Commands + +### Management Commands + +```bash +# Start services +docker-compose up -d + +# Stop services +docker-compose down + +# View logs +docker-compose logs -f sqlite-viewer + +# Restart services +docker-compose restart + +# Update and rebuild +docker-compose down +docker-compose build --no-cache +docker-compose up -d +``` + +### Development Commands + +```bash +# Start development mode +docker-compose --profile development up -d + +# View development logs +docker-compose logs -f sqlite-viewer-dev + +# Shell into container +docker exec -it sqlite-viewer sh +``` + +### Maintenance Commands + +```bash +# Remove stopped containers +docker container prune + +# Remove unused images +docker image prune + +# Remove everything (be careful!) +docker system prune -a +``` + +## Networking + +### Traefik Integration + +The docker-compose.yml includes Traefik labels for easy reverse proxy setup: + +```yaml +labels: + - "traefik.enable=true" + - "traefik.http.routers.sqlite-viewer.rule=Host(`sqlite-viewer.localhost`)" + - "traefik.http.services.sqlite-viewer.loadbalancer.server.port=80" +``` + +### Custom Network + +A dedicated bridge network `sqlite-viewer-network` is created for service isolation. + +## Security Features + +The nginx configuration includes: +- **Security headers**: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection +- **CORS headers**: Proper handling for WebAssembly files +- **Content-Type enforcement**: Proper MIME types for all file types +- **Access restrictions**: Hidden files are blocked + +## Performance Optimizations + +- **Gzip compression**: Enabled for text files +- **Static asset caching**: 1-year cache for immutable assets +- **WebAssembly support**: Proper MIME type and caching for .wasm files +- **Alpine Linux**: Minimal base image for smaller size + +## Health Checks + +The container includes a health check that: +- Runs every 30 seconds +- Has a 3-second timeout +- Allows 5 seconds for startup +- Retries 3 times before marking as unhealthy + +Check container health: +```bash +docker ps +# Look for "(healthy)" status +``` + +## Troubleshooting + +### Common Issues + +1. **Port already in use:** + ```bash + # Change the port mapping + docker-compose down + # Edit docker-compose.yml to use different port + docker-compose up -d + ``` + +2. **Permission issues:** + ```bash + # Ensure proper file permissions + chmod -R 644 . + chmod 755 . css js img examples + ``` + +3. **WebAssembly not loading:** + - Ensure CORS headers are properly set + - Check browser console for errors + - Verify .wasm files are accessible + +4. **Container won't start:** + ```bash + # Check logs + docker-compose logs sqlite-viewer + + # Rebuild without cache + docker-compose build --no-cache + ``` + +### Debug Mode + +Run container in interactive mode for debugging: +```bash +docker run -it --rm -p 8080:80 sqlite-viewer sh +``` + +## Deployment Examples + +### Production Deployment + +```bash +# Production with custom domain +docker run -d \ + --name sqlite-viewer-prod \ + -p 80:80 \ + -v /opt/sqlite-files:/usr/share/nginx/html/examples:ro \ + --restart unless-stopped \ + sqlite-viewer +``` + +### Behind Reverse Proxy + +```bash +# For use with nginx/Apache reverse proxy +docker run -d \ + --name sqlite-viewer \ + -p 127.0.0.1:8080:80 \ + --restart unless-stopped \ + sqlite-viewer +``` + +### Kubernetes Deployment + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sqlite-viewer +spec: + replicas: 2 + selector: + matchLabels: + app: sqlite-viewer + template: + metadata: + labels: + app: sqlite-viewer + spec: + containers: + - name: sqlite-viewer + image: sqlite-viewer:latest + ports: + - containerPort: 80 + resources: + requests: + memory: "64Mi" + cpu: "50m" + limits: + memory: "128Mi" + cpu: "100m" +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..81c1c01 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Use official nginx image as base +FROM nginx:alpine + +# Set working directory +WORKDIR /usr/share/nginx/html + +# Copy all application files to nginx html directory +COPY . . + +# Create custom nginx configuration +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Add health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost/ || exit 1 + +# Start nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f74d749 --- /dev/null +++ b/Makefile @@ -0,0 +1,104 @@ +# SQLite Viewer - Docker Management +.PHONY: help build run dev stop clean logs shell test + +# Default target +help: ## Show this help message + @echo "SQLite Viewer - Docker Management" + @echo "=================================" + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +# Build the Docker image +build: ## Build the Docker image + @echo "Building SQLite Viewer Docker image..." + docker build -t sqlite-viewer . + +# Run in production mode +run: ## Run the application in production mode (port 8080) + @echo "Starting SQLite Viewer in production mode..." + docker-compose up -d + @echo "SQLite Viewer is running at http://localhost:8080" + +# Run in development mode +dev: ## Run the application in development mode (port 3000) + @echo "Starting SQLite Viewer in development mode..." + docker-compose --profile development up -d + @echo "SQLite Viewer (dev) is running at http://localhost:3000" + +# Stop all services +stop: ## Stop all running services + @echo "Stopping SQLite Viewer services..." + docker-compose down + +# Stop and remove all containers, networks, and volumes +clean: ## Clean up all containers, networks, and volumes + @echo "Cleaning up SQLite Viewer resources..." + docker-compose down -v --remove-orphans + docker system prune -f + +# Show logs +logs: ## Show logs from running containers + docker-compose logs -f + +# Show development logs +logs-dev: ## Show logs from development container + docker-compose logs -f sqlite-viewer-dev + +# Open shell in running container +shell: ## Open shell in the running production container + docker exec -it sqlite-viewer sh + +# Open shell in development container +shell-dev: ## Open shell in the running development container + docker exec -it sqlite-viewer-dev sh + +# Restart services +restart: ## Restart all services + @echo "Restarting SQLite Viewer services..." + docker-compose restart + +# Update and rebuild +update: ## Update and rebuild the application + @echo "Updating SQLite Viewer..." + docker-compose down + docker-compose build --no-cache + docker-compose up -d + @echo "SQLite Viewer updated and running at http://localhost:8080" + +# Run health check +health: ## Check the health status of containers + @echo "Container health status:" + @docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + +# Show resource usage +stats: ## Show container resource usage + docker stats --no-stream + +# Test the application +test: ## Test if the application is responding + @echo "Testing SQLite Viewer..." + @curl -f http://localhost:8080 >/dev/null 2>&1 && echo "โœ… Production service is healthy" || echo "โŒ Production service is not responding" + @curl -f http://localhost:3000 >/dev/null 2>&1 && echo "โœ… Development service is healthy" || echo "โš ๏ธ Development service is not running" + +# Quick development setup +setup: build run ## Build and run the application + @echo "SQLite Viewer setup complete!" + @echo "Production: http://localhost:8080" + @echo "To start development mode: make dev" + +# Deploy to production +deploy: ## Deploy to production (build and run optimized) + @echo "Deploying SQLite Viewer to production..." + docker-compose down + docker-compose build --no-cache + docker-compose up -d + @echo "Production deployment complete!" + @echo "Application available at: http://localhost:8080" + +# Backup examples directory +backup: ## Backup the examples directory + @echo "Creating backup of examples directory..." + @tar -czf backup-examples-$(shell date +%Y%m%d-%H%M%S).tar.gz examples/ + @echo "Backup created successfully" + +# Show help by default +.DEFAULT_GOAL := help diff --git a/README.md b/README.md index b039c53..a3fddf6 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,58 @@ You can also load remote files (using JS ajax, remote server must send `Access-C ![](/img/preview.png?raw=true "Example sqlite") +## Quick Start + +### Using Docker (Recommended) + +```bash +# Clone and run with Docker Compose +git clone https://github.com/inloop/sqlite-viewer.git +cd sqlite-viewer +docker-compose up -d +``` + +Access at: `http://localhost:8080` + +### Direct Usage + +Simply open `index.html` in your browser or serve the files with any web server. + +## Docker Support + +This project includes full Docker support for easy deployment: + +- **Production deployment** with optimized nginx configuration +- **Development mode** with live file mounting +- **Security headers** and performance optimizations included +- **Health checks** and proper error handling + +See [DOCKER.md](DOCKER.md) for detailed Docker usage instructions. + +### Quick Docker Commands + +```bash +# Production mode +docker-compose up -d + +# Development mode with live reload +docker-compose --profile development up -d + +# Build and run manually +docker build -t sqlite-viewer . +docker run -d -p 8080:80 sqlite-viewer +``` + +## Features + +- ๐Ÿ—„๏ธ **Client-side SQLite viewing** - No file uploads, everything runs in your browser +- ๐Ÿ” **SQL query execution** - Run custom SQL queries with syntax highlighting +- ๐Ÿ“Š **Table browsing** - Easy navigation between tables and views +- ๐Ÿ“ฅ **CSV export** - Export tables and query results +- ๐Ÿ”— **URL loading** - Load SQLite files from remote URLs +- ๐Ÿณ **Docker ready** - Production-ready containerized deployment +- ๐Ÿ“ฑ **Responsive design** - Works on desktop and mobile devices + ### License Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/css/main.css b/css/main.css index e80cded..a9c4a43 100644 --- a/css/main.css +++ b/css/main.css @@ -11,6 +11,11 @@ body { color: #3474A8; } +#header a:hover img { + opacity: 0.8; + transition: opacity 0.2s ease; +} + #dropzone { height: 450px; cursor: pointer; diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4066cc1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,41 @@ +version: '3.8' + +services: + sqlite-viewer: + build: . + container_name: sqlite-viewer + ports: + - "8080:80" + restart: unless-stopped + environment: + - NGINX_HOST=localhost + - NGINX_PORT=80 + volumes: + # Optional: Mount a directory to share SQLite files + - ./examples:/usr/share/nginx/html/examples:ro + labels: + - "traefik.enable=true" + - "traefik.http.routers.sqlite-viewer.rule=Host(`sqlite-viewer.localhost`)" + - "traefik.http.services.sqlite-viewer.loadbalancer.server.port=80" + networks: + - sqlite-viewer-network + + # Optional: Add a development service with live reload + sqlite-viewer-dev: + build: . + container_name: sqlite-viewer-dev + ports: + - "3000:80" + restart: unless-stopped + volumes: + # Mount source code for development + - .:/usr/share/nginx/html:ro + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + profiles: + - development + networks: + - sqlite-viewer-network + +networks: + sqlite-viewer-network: + driver: bridge diff --git a/index.html b/index.html index e824bd7..35b4379 100644 --- a/index.html +++ b/index.html @@ -33,7 +33,9 @@