A simple and efficient web application for saving and managing your favorite links. Link Saver automatically extracts page title, description and optionally screenshots from URLs and provides a web interface for organizing your bookmarks.
You can also save short notes which are not connected to any particular URL along with your bookmarks.
In addition to the built-in web interface, there is also
- Save Links: Add URLs with automatic title and description extraction and screenshots from web pages
- Save Nodes: Write short notes and save them among your bookmarks.
- SQLite Storage: Lightweight, file-based database with no external dependencies
- Docker Support: Easy deployment with Docker containers
- HTTP basic auth: Protect the application with username and password
- Build the image:
docker build -t linksaver . - Run the container without authentication, listing on localhost only:
docker run --mount "type=bind,src=$(pwd)/data,dst=/data" --cap-drop ALL --security-opt no-new-privileges -p 127.0.0.1:8080:8080 linksaver - Run the container with HTTP basic authentication, listing externally:
htpasswd -cBC 12 pwfile my_username docker run --mount "type=bind,src=$(pwd)/pwfile,dst=/pwfile" --mount "type=bind,src=$(pwd)/data,dst=/data" --cap-drop ALL --security-opt no-new-privileges -p 8080:8080 linksaver -basic-auth-file /pwfile -basic-auth-realm my-realm
Note: This is only secure if you also use https.
The application will store data in the directory mounted at /data, using data/linksaver.sqlite as the database file
and store screenshots in data/screenshots.
- Build the standalone executable
go build -tags netgo -v ./cmd/linksaver/
- Run it without authentication, listing on localhost only:
./linksaver -port 8080 -addr 127.0.0.1 -data data
- Run it with HTTP basic authentication, listing externally:
htpasswd -cBC 12 pwfile my_username ./linksaver -port 8080 -data data -basic-auth-file pwfile -basic-auth-realm my-realm
Note: This is only secure if you also use https.
The application will store data in the ./data directory, using ./data/linksaver.sqlite as the database file.
You can use the apparmor-profile file as a template for an Apparmor profile, you need to substitute
${PATH_TO_EXECUTABLE} and ${PATH_TO_DATA} with absolute paths.
This has only been tested on Ubuntu and Debian Linux.
Once the application is running, open your web browser and navigate to:
http://localhost:8080(or your configured port)
From the web interface, you can:
- Add a new link: Enter a URL in the input field and click "Add Link"
- Add a new note: Enter title and text in the input fields and click "Add Note"
- View all links: All saved links/notes are displayed on the main page
- Delete a link: Click the delete button next to any link/note to remove it
├── cmd/linksaver/ # Main application
│ ├── main.go # Application entry point
│ ├── handlers.go # HTTP request handlers
│ ├── handlers_test.go # Handler tests
│ └── db/ # Database layer
│ ├── db.go # Database operations
│ └── db_test.go # Database tests
├── ui/ # User interface assets
│ ├── templates/ # HTML templates
│ └── static/ # CSS, JavaScript files
├── Dockerfile # Docker configuration
├── run.sh # Start script for Docker image
├── go.mod # Go module definition
├── apparmor-profile # Apparmor profile template
└── README.md # This file
To run all tests:
go test ./...The application provides the following HTTP endpoints:
GET /- Display all saved linksGET /?s=term- Search for linksPOST /- Add a new link/noteGET /{id}- Get a specific linkPATCH /{id}- Edit a specific linkDELETE /{id}- Delete a specific link
- Go 1.25
- modernc.org/sqlite: Pure Go SQLite driver
- htmx: High power tools for HTML
- _hyperscript: An easy & approachable language for modern web front-ends
- missing.css: The Missing CSS Stylesheet
- chromedp: Run headless Chrome browser to fetch page, extract title, description and take screenshot
Copyright 2025 Mikael Ståldal.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.