Skip to content

Installation

  • https: (Required) The web app rely heavily on service worker (notably to stream content) and sign-in binds your session to the device using the Web Crypto API. Browsers only expose both of these on secure contexts, so you need to serve the web app through https — on plain http (e.g. http://<lan-ip>) sign-in will fail outright. It can be self signed certificate. It will also work without https on localhost. The provided docker image for the web app does not embed self signed certificate.
  • same site: (Required) The web app and the API must be served from the same site, meaning the same registrable domain. Serving both from one hostname on different ports is the default (oboku.example.com and oboku.example.com:3000). Separate subdomains also work (oboku.example.com and oboku-api.example.com) as long as you point VITE_API_URL at the API origin and APP_PUBLIC_URL at the web app's, since the API only accepts credentialed requests from APP_PUBLIC_URL's hostname. Auth rides on SameSite=Lax httpOnly cookies, so an API served from a different site (oboku.app / oboku-api.dev) never receives them and sign-in fails.
  • HTTP/2: (Recommended) The database is reached through the API, and replicating many collections needs many parallel connections. HTTP/1 caps connections per origin and will block some requests, so serve the API behind an HTTP/2 reverse proxy. Without HTTP/2 you must instead expose several API origins (see VITE_API_URL_2/3/4 in Environment Variables).
  • dropbox: (Optional) To have a dropbox support, you will need to create a developer account and configure credentials.
  • google drive: (Optional) To have a google drive support, you will need to create a developer account and configure credentials

By default, there are strong limitations put in place to reduce memory / CPU usage. This allow the stack to run on cheaper servers. You can change some settings if you have a beefier server. If you plan on intensive usage with lot of books, visit our Enable features section. Some options can help you reduce the costs of hosting.

Section titled “Installation with docker compose (recommended)”

This setup assume this final minimal structure on your server:

Terminal window
/oboku
.env
docker-compose.yml
/secrets # created on first start
jwt_private_key.pem
jwt_public_key.pem

Provide the minimum required env variables for your compose file.

.env
# couchdb is exposed publicly so you should consider a strong password.
COUCHDB_PASSWORD=createastrongpassword
# postgres does not need to be exposed publicly but you should
# still consider a strong password.
POSTGRES_PASSWORD=createastrongpassword

oboku signs its sessions with an RSA key pair. CouchDB generates one into ./secrets the first time the stack starts, so a normal install has nothing to do here.

To use your own key pair instead, create it before the first start and it will be left alone:

Terminal window
mkdir -p ./secrets
openssl genrsa -out ./secrets/jwt_private_key.pem 4096
openssl rsa -in ./secrets/jwt_private_key.pem -pubout -outform PEM -out ./secrets/jwt_public_key.pem

You can also supply the keys base64 encoded through JWT_PRIVATE_KEY and JWT_PUBLIC_KEY rather than as files.

You can then create a docker compose for the project. We have a default one here

After creating your docker compose, run this command in the same directory

Terminal window
docker compose up -d
Terminal window
docker compose pull
docker compose up -d

Cosmos runs the same images as the docker compose installation above and serves them through its own reverse proxy.

By default Cosmos hardens the headers of every URL it serves. On the API that breaks the web app: Cosmos drops the API's Access-Control-Allow-Origin and Access-Control-Allow-Credentials headers and sends its own, set to the URL's hostname, so the browser rejects every API response. In the settings of the URL that serves the API, turn on Disable Header Hardening so the API's own CORS headers reach the browser. The web app and admin panel URLs can keep hardening.

Setting a CORS origin on the URL is not enough: Cosmos would send that one origin on every response, and the admin panel's requests come from another origin.