Read "Link management software (Bookmarks)" first.
After running my Bookmark Manager locally, I wanted to make it easier to deploy, migrate and share. The goal was to have it running anywhere without manually setting up Node.js, NPM, or SQLite. So I decided to containerize the whole application with Docker, using the node:20 image as a base.
The Dockerfile:
The Dockerfile is very minimal and keeps the image small and simple (398.4 MiB currently). It installs dependencies, copies the source code, creates the data directory, and runs the app.
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
# Port
EXPOSE 3000
# Command
CMD ["node", "server.js"]
The .dockerignore file:
The .dockerignore file tells Docker which files and folders should not be copied into the image during the docker build process. This helps to
- Reduce image size
- Speed up builds
- Protect sensitive data
- Start the container only with the files it really needs
# NPM
node_modules
# Logs
npm-debug.log
yarn-error.log
# Git
.git
.gitignore
# Docker
Dockerfile
.dockerignore
# Bookmars DB
*.sqlite
Building & pushing the image:
Then I was ready to build the image itself. Navigating into the root directory of the project and running:
$ sudo docker build -t bookmarks .
Then I tagged the image and pushed it to Dockerhub:
$ docker tag bookmarks byte21516/bookmarks:latest
Then I logged into DockerHub by running:
$ sudo docker login
After that, I was ready to push the image to DockerHub. You can find it here.
Changes I made:
To make all features work on the docker platform, I had to make some small changes to the application (server.js), which include:
- Change the location of the database: For easy backups from the host system.
- Metadata Fetching inside Docker:
const db = new sqlite3.Database(path.join(__dirname, "data", "db.sqlite"));
When I first ran the application in Docker using node:20-alpine, fetching the <title> and favicons did not work reliably. The issue was not the code itself, but that Alpine uses a minimal base image with a different network client and missing libraries, which caused node-fetch and Cheerio to fail on some sites.
The full Node 20 image includes all the libraries needed for HTTPS requests and proper URL resolution. After switching, the fetch requests inside the container behave like expected.
How you can run it:
You can simply run it with docker-compose:
services:
bookmarks:
image: byte21516/bookmarks:latest
container_name: bookmarks
ports:
- "3000:3000"
volumes:
- ./bookmarks-data:/app/data
environment:
NODE_ENV: production
restart: unless-stopped
Here are some hyperlinks to the image on dockerhub and the source on GitHub (GitHub is not where development happens, it is just a mirror, to make the source code publicly available.):