| .claude | ||
| cmd | ||
| internal | ||
| .dockerignore | ||
| .gitignore | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| push.sh | ||
| README.md | ||
Home Links
A self-hosted, minimalistic bookmark manager with a beautiful Trello-like interface. Built with Go and designed for containerized deployment.
Features
- Trello-like Interface: Organize bookmarks in draggable lists with horizontal and vertical drag-and-drop
- Card Flip UI: Clean configuration interface - click the gear icon (⚙️) to flip cards and edit
- Mobile-Optimized: Touch-friendly with long-press to drag (200ms), always-visible controls, 44px touch targets
- Drag-to-Scroll: Click and drag the whitespace to smoothly scroll through your lists horizontally
- Keyboard Shortcuts: ESC to close configuration panels, Enter to save changes
- Collapsible Lists: Save screen space by collapsing lists to vertical tabs
- Adaptive Compression: Bookmark URLs automatically hide when lists have 7+ bookmarks for compact display
- Automatic Favicons: Automatically fetches and displays favicons for your bookmarks
- Multi-user Support: Each user has their own isolated bookmarks
- Import/Export: Backup and restore your bookmarks as JSON
- Dark Mode: Beautiful dark theme with readable color palette
- Stealth UI: Minimal, unobtrusive navigation that fades in when needed
- Minimal Footprint: Docker image < 15MB
- Secure: Argon2id password hashing, secure cookie-based sessions
- Fast: Lightweight Go backend with SQLite database
Quick Start
Docker (Recommended)
-
Start the container:
docker-compose up -d -
Create your first user:
docker exec -it home-links /user create adminYou'll be prompted to enter a password.
-
Access the application: Open your browser to http://localhost:8080
Docker Run
# Create a volume for data persistence
docker volume create home-links-data
# Run the container
docker run -d \
--name home-links \
-p 8080:8080 \
-v home-links-data:/data \
home-links:latest
# Create a user
docker exec -it home-links /user create admin
Local Development
-
Prerequisites:
- Go 1.23 or later
- Make (optional)
-
Clone and build:
git clone <repository-url> cd home-links go mod download go build -o bin/server ./cmd/server go build -o bin/user ./cmd/user -
Create a user:
./bin/user create admin -
Run the server:
./bin/server -
Access the application: Open http://localhost:8080
Configuration
Configuration is done via environment variables:
| Variable | Description | Default |
|---|---|---|
DATABASE_PATH |
Path to SQLite database file | ./data/bookmarks.db |
PORT |
HTTP server port | 8080 |
SESSION_KEY |
32-byte hex key for session signing | Auto-generated |
ENCRYPTION_KEY |
32-byte hex key for cookie encryption | Auto-generated |
SESSION_MAX_AGE |
Session duration in seconds | 31536000 (1 year) |
SECURE_COOKIE |
Enable secure cookies (HTTPS only) | false |
Generating Secure Keys (Production)
# Generate session key
openssl rand -hex 32
# Generate encryption key
openssl rand -hex 32
Add these to your docker-compose.yml or environment:
environment:
- SESSION_KEY=your_generated_session_key
- ENCRYPTION_KEY=your_generated_encryption_key
- SECURE_COOKIE=true # If behind HTTPS
User Management
The user CLI tool provides user management commands:
# Create a new user
./bin/user create <username>
# Delete a user
./bin/user delete <username>
# List all users
./bin/user list
# Reset a user's password
./bin/user reset-password <username>
With Docker:
docker exec -it home-links /user <command>
Usage Guide
Creating Lists
- Click the "+ Add List" button on the right
- A new list card appears, flipped to show the configuration panel
- Enter a title (required)
- Optionally change the color from the default (Blue)
- Click "Save" to create the list, or "Cancel" / press ESC to discard
- Saving with an empty title will cancel the operation
Adding Bookmarks
- Click "+ Add Bookmark" at the bottom of any list
- A new bookmark card appears, flipped to show the configuration panel
- Enter a URL (required) and title (required)
- Click "Save" to create the bookmark, or "Cancel" / press ESC to discard
- Saving with empty fields will cancel the operation
- Favicon will be fetched automatically after creation
Organizing
- Drag lists horizontally by their header to reorder them (auto-scrolls near edges)
- Drag-to-scroll: Click and drag on list whitespace or container background to scroll horizontally
- Drag bookmarks vertically within and between lists
- Click list header to collapse/expand (lists collapse to vertical tabs)
- Configure lists: Click the gear icon (⚙️) to flip the card and:
- Edit list title
- Change color from 8-color inline picker
- Delete list (with confirmation)
- Configure bookmarks: Click the gear icon (⚙️) to flip the card and:
- Edit bookmark title and URL
- Delete bookmark (with confirmation)
- Keyboard shortcuts:
ESC- Close any open configuration panelEnter- Save changes (when in input fields)
- Mobile: Long-press (200ms) to initiate drag, tap normally to open links or configurations
Import/Export
- Export: Click "Export" to download your bookmarks as JSON
- Import: Click "Import", choose a file, and select merge or replace mode
- Merge: Adds new data, updates existing by ID
- Replace: Deletes all data and imports fresh
Architecture
Technology Stack
Backend:
- Go 1.23+
- Chi router (lightweight HTTP router)
- SQLite (modernc.org/sqlite - pure Go, CGO-free)
- Gorilla sessions (secure cookie-based sessions)
- Argon2id (password hashing)
Frontend:
- Vanilla JavaScript (no frameworks)
- Pico.css (minimal CSS framework, ~10KB)
- SortableJS (drag-and-drop, ~2KB)
Deployment:
- Docker multi-stage build
- Scratch base image for minimal size
- Single binary deployment
Project Structure
home-links/
├── cmd/
│ ├── server/ # Main server application
│ │ ├── main.go
│ │ └── static/ # Embedded frontend assets
│ └── user/ # User management CLI
├── internal/
│ ├── api/ # HTTP handlers
│ ├── auth/ # Authentication & sessions
│ ├── db/ # Database layer
│ ├── favicon/ # Favicon fetching
│ └── models/ # Data models
├── Dockerfile
├── docker-compose.yml
└── README.md
Security Considerations
- HTTPS: Use a reverse proxy (Caddy, nginx, Traefik) for HTTPS in production
- Secure Cookies: Set
SECURE_COOKIE=truewhen using HTTPS - Session Keys: Generate and set
SESSION_KEYandENCRYPTION_KEYin production - Rate Limiting: Consider adding rate limiting at the reverse proxy level
- Backups: Regularly backup your SQLite database and exported JSON
Reverse Proxy Setup
Caddy Example
bookmarks.example.com {
reverse_proxy localhost:8080
}
nginx Example
server {
listen 443 ssl http2;
server_name bookmarks.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8080;
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;
}
}
Color Palette
Darker, more readable colors optimized for dark mode:
- Blue:
#3D6D95 - Green:
#4D7831 - Orange:
#B85720 - Red:
#A43529 - Purple:
#6B3D7D - Pink:
#924F7D - Teal:
#358178 - Gray:
#697374
Database Schema
users
id- Primary keyusername- Unique usernamepassword_hash- Argon2id hashcreated_at- Timestamp
lists
id- Primary keyuser_id- Foreign key to userstitle- List titlecolor- Hex color codeposition- Sort ordercollapsed- Boolean collapsed statecreated_at- Timestamp
bookmarks
id- Primary keylist_id- Foreign key to liststitle- Bookmark titleurl- Bookmark URLfavicon_url- Cached favicon URLposition- Sort order within listcreated_at- Timestamp
Troubleshooting
Cannot access the application
- Check if the server is running:
docker ps - Check logs:
docker logs home-links - Verify port is not in use:
lsof -i :8080
User creation fails
- Ensure database directory exists and is writable
- Check container logs for database errors
Favicons not loading
- Favicon fetching uses Google's favicon service
- Requires outbound HTTPS access
- Some sites may not have favicons
Session expires too quickly
- Check
SESSION_MAX_AGEenvironment variable - Default is 1 year (31536000 seconds)
Performance
- Targets 20-30 bookmarks per list, ~10 lists
- Supports up to 1000 bookmarks per user
- Sub-50ms API response times
- Minimal memory footprint (~20MB runtime)
License
MIT License - feel free to use and modify as needed.
Contributing
This is a personal project, but suggestions and bug reports are welcome!
Roadmap
Future enhancements to consider:
- Browser extension for quick bookmark additions
- Bookmark tags and search
- Bookmark screenshots/thumbnails
- Shared lists between users
- API keys for automation
- Mobile app
Built with ❤️ using Go and vanilla JavaScript.