You can self-host Briefkasten with Docker or manually by spinning up the Next.js app and Postgres on any host yourself. There are a few caveats to keep in mind with the self-hosted route, however. Depending on how okay you are with signing up for online services.
You can use any Postgres database you like, i.e. local, or hosted in the cloud. However, the object storage for bookmark screenshots is designed to work specifically with Supabase. That means, if you don't fill in the
SUPABASE_* environment variables, you will not have dynamic bookmark screenshots. Otherwise, the app works just fine completely self-hosted, for example with the Docker setup described below!
You can host the Briefkasten application entirely on your own via the included docker files.
This will result in your hosting two items:
- The companion PostgreSQL database
Make sure you have
- Clone the repository to your server.
git clone https://github.com/ndom91/briefkasten.git
- Setup the environment variables.
Make a copy of the
.env.example file and fill in at least the required variables with your favorite text editor. The example file has annotations for the variables.
cp .env.example .env vim .env
When using the local postgres container you should set the
DATABASE_URL environment variable to
- Start the docker-compose stack of applications
docker-compose up -d
- Setup the database
After starting the containers, you still have to manually apply the database schema. This is most easily done through the app container (
docker exec -it bk-app /bin/bash // Inside the 'bk-app' container pnpm db:push
- Now your application and database should be up and running at the default
You can continue by putting
localhost:3000 behind a reverse proxy (i.e.
nginx) which can terminate TLS for you (https) and provide access via a nice domain name of your choice. For more details, check out the Linode guide on setting up a reverse proxy with nginx.
To manually selfhost Briefkasten there are 3 required prerequisites and 1 optional one. The required items are as follows:
- A platform to host a Node.js (Next.js) application
- A Prisma compatible database (SQLite, Postgres, Mysql, etc.)
- An authentication provider
- S3-like object store (optional)
To run the actual Briefkasten application itself, you will need some sort of platform to run a Node.js 16 application on. This can be any sort of server you have access to, or a hosting platform like Vercel or Netlify. I won't go into a ton of detail here, I will assume you know how to run a node.js application and/or can setup a Vercel account if you're going to be selfhosting software.
Some things to remember here, however, are the environment variables. You will need to make sure your hosting platform has a copy of your production environment variables. Including the production
NEXTAUTH_SECRET. As well as a production
The OAuth credentials can be acquired through the instructions on the NextAuth.js site. Don't forget to set the provider
secret of your choice (i.e.
Finally, if you've opted into providing an object storage provider for bookmark images, the application is currently setup to use Supabase only. Therefore, you can pass your secrets as
SUPABASE_KEY. Make sure to use the service account key which has
write rights. More details below for using a different object storage provider.
The image uploading functionality will be skipped over entirely if you do not pass a
SUPABASE_URL environment variable. No other action is necessary.
For the database portion, you must simply provide some
write permissioned credentials to any type of database supported by Prisma, preferably not MongoDB. This setting is applied primarily through the passing of the
DATABASE_URL which should contain all the details to connect, such as hostname and username/password. This environment variable is passed through to Prisma in its
prisma/schema.prisma file. Currently this file is setup for Postgres, therefore, if you plan to use a different type of database, **you must change the
db.provider value in that file from
postgres to whichever type you want.
After setting up your database credentials, you can run the following command to apply all migrations and prepare the database for the application.
pnpm dlx prisma migrate dev # or npx prisma migrate dev
After this, the database should be ready to receive new users and bookmarks from the application!
For authentication, I've opted to use the NextAuth.js library, as I help maintain the project and am intimately familiar with it. Setup is extremely easy and I've prepared Briefkasten for the following 3 login types. You must use at least one and at most all 3. Although you can obviously adjust the code to add any more that you may wish to use.
The two OAuth providers are setup simply by passing their respective
secret's via environment variables. The email magic link provider requires just an SMTP connection string, similar to the
DATABASE_URL connection string used previously. It should contain the SMTP host, username and password, port, etc. and can be supplied via the
SMTP_SERVER environment variable.
As previously mentioned, the object storage is optional, and used only for storing bookmark screenshots. The application with function just fine without bookmark images, however, in my opinion it will be much less nice 😃
Briefkasten is setup to use Supabase and their Storage product. You can sign-up for a free Supabase account at their website and use the 1GB free storage they provide you. As mentioned in the hosting section, you then simply need to pass the
SUPABASE_KEY as environment variables for it to work.
If you want to use a different object storage provider, there are a few changes you will need to make. Including swapping out the use of the
L184 we are using the
supabase sdk client to upload the screenshot blob returned from the Briefkasten screenshot API. On
L394 we are using the same sdk client in the
DELETE endpoint handler to delete images when their bookmark is deleted as well.
Secondly, in the
L25 in the
PUT handler, we are uploading the body of the
PUT request (which should be a base64 encoded image) to Supabase using their sdk client.
Those are the only usages of the sdk client which you would theoretically need to replace with the upload logic of another object storage provider.
In addition, there is hard coded the prefix of my Supabase bucket URL in a few places in the codebase. If you search for
supabase.co/storage, you will find all places (4) which need to be replace with the URL / static part of the URL of your new provider. Be aware the bucket must be public, or you must also add code to authenticate reads.