A self-hosted notes application inspired by Google Keep. Create, edit, organize, and collaborate on your notes with an intuitive, feature-rich user interface.
- ✅ Create, edit, and delete notes with confirmation dialogs
- 🎨 12 different colors for your notes
- 📌 Pin/unpin notes for quick access
- 🏷️ Tags/labels for better organization with drag-and-drop support
- 🔍 Full-text search in title and content
- 📋 Todo lists/checklists within notes
- 🔗 Automatic link preview generation
- 📦 Archive notes (hide without deleting)
- 🎯 Drag and drop to organize and reorder notes
- 👥 Multi-user support with JWT authentication
- 🤝 Friend system with friend requests
- 🔄 Share and collaborate on notes with friends
- 👁️ Visual indicators showing who has access to shared notes
- 🔐 Granular sharing permissions
- 🌍 Internationalization (English & German)
- 🌙 Dark mode with theme persistence
- 🖤 OLED mode for AMOLED displays
- 📱 Fully responsive design (works on desktop and mobile)
- 🚀 Fast and intuitive interface
- 🎯 Toast notifications for instant feedback
- ⌨️ Keyboard shortcuts for power users
- 🔒 Advanced security (XSS protection, CSRF tokens, CORS, Rate Limiting)
- 👨💼 Admin console for user management
- 🔐 User registration control (enable/disable)
- 📊 Statistics and usage analytics
- 💾 MongoDB database integration
- 🐳 Docker & Docker Compose support
- 📦 Unraid ready with templates
- 🔄 Easy updates and maintenance
- React 18 with Hooks (useState, useEffect, useContext, etc.)
- React Context API for state management (Auth, Language)
- Axios for HTTP requests
- CSS3 with Grid Layout, Flexbox & CSS Variables for theming
- DOMPurify for XSS protection
- i18n with custom translation system
- Service Worker for offline capability
- Node.js & Express.js
- MongoDB & Mongoose ODM
- JWT (JSON Web Tokens) for authentication
- bcrypt for password hashing
- CSRF protection with csurf
- Helmet for security headers
- Express Rate Limit for DDoS protection
- XSS sanitization
- CORS with origin control
- Session management with express-session
The easiest way to run KeepLocal is using Docker Compose:
- Docker
- Docker Compose
-
Clone the repository
git clone https://github.com/zwaetschge/KeepLocal.git cd KeepLocal -
Start with Docker Compose
docker-compose up -d
-
Access the application
Open your browser and navigate to:
http://localhost:3000
That's it! The application will automatically:
- Set up MongoDB
- Configure the backend server
- Build and serve the frontend
- Handle all networking between services
# Start the application
docker-compose up -d
# Stop the application
docker-compose down
# View logs
docker-compose logs -f
# Restart services
docker-compose restart
# Stop and remove all data (including database)
docker-compose down -v- Install the Docker Compose Manager plugin from Community Applications
- Create a new stack in Docker Compose Manager
- Copy the contents of
docker-compose.ymlfrom this repository - Click "Compose Up"
- Access via
http://[UNRAID-IP]:3000
Choose between installing individual containers or using the compose stack:
Option A: Individual Containers
- Go to Docker tab in Unraid
- Click Add Container
- Under Template repositories, add:
https://github.com/zwaetschge/KeepLocal/tree/main/unraid - Install containers in this order:
- KeepLocal-MongoDB (database)
- KeepLocal-Server (backend API)
- KeepLocal-Client (web interface)
- Configure each container:
- Update IP addresses in environment variables
- Ensure ports don't conflict (27017, 5000, 3000)
- Set MongoDB data path:
/mnt/user/appdata/keeplocal/mongodb
- Click Apply for each container
Option B: Docker Compose Stack
Use the template file at unraid/keeplocal-compose.xml with the Docker Compose Manager plugin.
For detailed instructions, see the Unraid README.
After installation, you may need to update the CORS settings:
- Go to Docker tab
- Click on KeepLocal container
- Edit the ALLOWED_ORIGINS variable
- Add your Unraid server IP:
http://[UNRAID-IP]:3000 - Click Apply
- Node.js (Version 14 or higher)
- npm or yarn
- MongoDB (local or MongoDB Atlas)
-
Clone the repository
git clone https://github.com/zwaetschge/KeepLocal.git cd KeepLocal -
Configure MongoDB
Create a
.envfile in theserver/directory:cd server cp .env.example .envEdit the
.envfile and set your MongoDB URI:PORT=5000 NODE_ENV=development MONGODB_URI=mongodb://localhost:27017/keeplocal ALLOWED_ORIGINS=http://localhost:3000
-
Install and start the server
npm install npm start
The server runs on:
http://localhost:5000 -
Install and start the client (new terminal window)
cd ../client npm install npm startThe app opens automatically at:
http://localhost:3000
- Access the application at
http://localhost:3000 - Create your admin account on the setup page
- Log in with your credentials
- Click on the input field "Take a note..." or click anywhere in the note form
- Add a title (optional)
- Enter your note content or create a todo list
- Add tags (comma-separated) for organization
- Select a color from the palette
- Click "Save" or press
Ctrl+Enter
- Click on any note to open the edit modal
- Edit the title, content, tags, or color
- Switch between regular note and todo list mode
- Click "Save" or press
Ctrl+Enter
- Pin/Unpin: Click the pin icon to keep notes at the top
- Archive: Click the archive icon to hide notes without deleting
- Share: Click the share icon to collaborate with friends
- Delete: Click the trash icon and confirm deletion
- Click the checkbox icon when creating/editing a note
- Add items to your todo list
- Check items off as you complete them
- Press
Enterto add new items - Press
Backspaceon empty items to delete them
- Add Friends: Click "Freunde" (Friends) in the sidebar
- Send Requests: Search for users and send friend requests
- Share Notes: Click the share icon on any note
- Manage Access: Add or remove collaborators
- View Shared Notes: See avatar indicators on shared notes
- Use the search bar at the top for full-text search
- Click on tags in the sidebar to filter by category
- Drag tags onto notes to add them
- Click "Archiviert" to view archived notes
- Click the theme toggle icon
- Cycle through: Light → Dark → OLED → Light
- Your preference is automatically saved
- Click the language selector (🇩🇪/🇬🇧)
- Choose between German and English
- All UI text updates instantly
Ctrl+N: Focus on new note inputCtrl+F: Focus on search barCtrl+K: Toggle themeCtrl+Shift+L: LogoutCtrl+Enter: Save note (in modal)Esc: Close modal
- Click on your username (admin only)
- View statistics and user management
- Create new users manually
- Delete users or change admin status
- Enable/disable user registration
POST /api/auth/setup- Initial admin account creationPOST /api/auth/register- Register new user (if enabled)POST /api/auth/login- User login (returns JWT)POST /api/auth/logout- User logoutGET /api/auth/me- Get current user infoGET /api/csrf-token- Get CSRF token
GET /api/notes- Get all notes (own + shared)- Query params:
search,tag,page,limit,archived
- Query params:
GET /api/notes/:id- Get single notePOST /api/notes- Create new notePUT /api/notes/:id- Update noteDELETE /api/notes/:id- Delete notePOST /api/notes/:id/pin- Toggle pin statusPOST /api/notes/:id/archive- Toggle archive statusPOST /api/notes/:id/share- Share note with userDELETE /api/notes/:id/share/:userId- Unshare note
GET /api/friends- Get friends listGET /api/friends/requests- Get pending friend requestsPOST /api/friends/request- Send friend requestPOST /api/friends/accept/:requestId- Accept friend requestPOST /api/friends/reject/:requestId- Reject friend requestDELETE /api/friends/:friendId- Remove friendGET /api/friends/search- Search users
GET /api/admin/stats- Get system statisticsGET /api/admin/users- Get all usersPOST /api/admin/users- Create new userDELETE /api/admin/users/:id- Delete userPOST /api/admin/users/:id/toggle-admin- Toggle admin statusGET /api/admin/settings- Get system settingsPUT /api/admin/settings- Update system settings
GET /api/link-preview- Fetch link preview data- Query param:
url
- Query param:
All endpoints (except auth and setup) require authentication via JWT token.
KeepLocal/
├── client/ # React Frontend
│ ├── public/
│ │ ├── service-worker.js # PWA Service Worker
│ │ └── manifest.json
│ ├── src/
│ │ ├── components/ # React Components
│ │ │ ├── AdminConsole.js # Admin panel
│ │ │ ├── CollaborateModal.js # Note sharing UI
│ │ │ ├── ColorPicker.js # Color selection
│ │ │ ├── ConfirmDialog.js # Confirmation dialogs
│ │ │ ├── FriendsModal.js # Friend management
│ │ │ ├── LanguageSelector.js # i18n switcher
│ │ │ ├── LinkPreview.js # URL preview cards
│ │ │ ├── Login.js # Login form
│ │ │ ├── Logo.js # App logo
│ │ │ ├── Note.js # Individual note card
│ │ │ ├── NoteForm.js # New note input
│ │ │ ├── NoteList.js # Notes grid
│ │ │ ├── NoteModal.js # Note editor modal
│ │ │ ├── Register.js # Registration form
│ │ │ ├── SearchBar.js # Search input
│ │ │ ├── Setup.js # Initial setup
│ │ │ ├── Sidebar.js # Navigation sidebar
│ │ │ ├── ThemeToggle.js # Theme switcher
│ │ │ └── Toast.js # Notifications
│ │ ├── contexts/ # React Context
│ │ │ ├── AuthContext.js # Authentication state
│ │ │ └── LanguageContext.js # i18n state
│ │ ├── translations/ # i18n files
│ │ │ ├── de.js # German translations
│ │ │ ├── en.js # English translations
│ │ │ └── index.js
│ │ ├── utils/ # Utility functions
│ │ │ ├── colorMapper.js # Color theme mapping
│ │ │ └── sanitize.js # XSS protection
│ │ ├── services/
│ │ │ └── api.js # API client
│ │ ├── App.js
│ │ ├── App.css
│ │ └── index.js
│ ├── Dockerfile
│ ├── nginx.conf
│ └── package.json
│
├── server/ # Express Backend
│ ├── config/
│ │ └── database.js # MongoDB connection
│ ├── middleware/
│ │ ├── auth.js # JWT authentication
│ │ ├── errorHandler.js # Error handling
│ │ └── sanitizeInput.js # Input sanitization
│ ├── models/
│ │ ├── Note.js # Note schema
│ │ ├── Settings.js # System settings schema
│ │ └── User.js # User schema
│ ├── routes/
│ │ ├── admin.js # Admin endpoints
│ │ ├── auth.js # Authentication
│ │ ├── friends.js # Friend management
│ │ ├── linkPreview.js # Link previews
│ │ └── notes.js # Note CRUD
│ ├── utils/
│ │ └── sanitize.js
│ ├── Dockerfile
│ ├── server.js
│ └── package.json
│
├── unraid/ # Unraid templates
│ ├── keeplocal-compose.xml
│ └── README.md
├── docker-compose.yml # Docker Compose config
├── .env.example # Environment template
├── .gitignore
└── README.md
cd server
npm run devUses nodemon for automatic reloading on changes.
cd client
npm run buildCreates an optimized production build in the client/build/ directory.
KeepLocal implements multiple security layers:
- Authentication: JWT-based authentication with secure token storage
- Password Security: bcrypt hashing with salt rounds
- CSRF Protection: csurf middleware with token validation
- XSS Protection: Input sanitization on server and client (DOMPurify)
- CORS Control: Configurable allowed origins
- Rate Limiting: Protection against brute-force attacks (100 requests/15min)
- Security Headers: Helmet.js for additional HTTP header security
- Input Validation: Mongoose schema validation on all inputs
- Payload Limits: Request size restrictions
- Session Security: Secure session management with express-session
- SQL Injection: Protected via Mongoose ODM parameterized queries
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 5000 |
NODE_ENV |
Environment mode | development |
MONGODB_URI |
MongoDB connection string | mongodb://localhost:27017/keeplocal |
ALLOWED_ORIGINS |
Comma-separated CORS origins | http://localhost:3000 |
SESSION_SECRET |
Session encryption key | Random string |
JWT_SECRET |
JWT token signing key | Auto-generated |
CSRF_SECRET |
CSRF token secret | Auto-generated |
- Notes are stored persistently in MongoDB
- Ensure MongoDB is running before starting the server
- The
.envfile contains sensitive configuration and should not be committed - For Docker deployments, MongoDB is automatically configured
- All data is stored in Docker volumes for persistence
Port already in use:
# Change the port in docker-compose.yml
ports:
- "8080:80" # Use port 8080 instead of 3000Cannot connect to MongoDB:
# Check if MongoDB container is running
docker-compose ps
# View MongoDB logs
docker-compose logs mongodbReset everything:
# Stop and remove all containers and volumes
docker-compose down -v
# Start fresh
docker-compose up -dCannot access WebUI:
- Check if the container is running
- Verify port mapping in container settings
- Update ALLOWED_ORIGINS with your Unraid IP
- Check firewall settings
Database not persisting:
- Ensure the appdata path is correctly configured
- Check permissions on
/mnt/user/appdata/keeplocal/
- 🖼️ Image and file attachments in notes
- 🔄 Real-time synchronization with WebSockets
- 📤 Export/Import functionality (JSON, Markdown, PDF)
- 📱 Progressive Web App (PWA) improvements
- 🔔 Reminders & notifications
- 📧 Email notifications for shared notes
- 🔍 Advanced search filters (by date, color, collaborator)
- 🏷️ Nested tags/folders
- 📊 Note statistics and analytics
- 🎨 Custom color themes
- 🌐 Additional languages
- 🔗 Browser extensions (Chrome, Firefox)
- 📱 Native mobile apps (iOS/Android)
- 🔐 Two-factor authentication (2FA)
- 💬 Comments on shared notes
- 📝 Rich text editor with formatting
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
MIT License
Created with ❤️ and Claude Code
- Inspired by Google Keep
- Built with React and Express
- MongoDB for data persistence
- Docker for easy deployment