{"id":13780334,"url":"https://github.com/ajslater/codex","last_synced_at":"2026-04-05T09:02:24.505Z","repository":{"id":37885964,"uuid":"289168726","full_name":"ajslater/codex","owner":"ajslater","description":"Codex is a web based comic archive browser and reader","archived":false,"fork":false,"pushed_at":"2026-01-26T20:19:13.000Z","size":69675,"stargazers_count":282,"open_issues_count":26,"forks_count":15,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-01-27T07:48:20.434Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ajslater.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-08-21T03:30:16.000Z","updated_at":"2026-01-26T20:11:24.000Z","dependencies_parsed_at":"2024-03-22T01:46:11.379Z","dependency_job_id":"4e896050-f0bd-4c16-bae4-a90acd4c03f4","html_url":"https://github.com/ajslater/codex","commit_stats":{"total_commits":2225,"total_committers":2,"mean_commits":1112.5,"dds":"0.00044943820224718767","last_synced_commit":"f2d898b67889e06f26ed2d5e709c7ab9b426f08e"},"previous_names":[],"tags_count":185,"template":false,"template_full_name":null,"purl":"pkg:github/ajslater/codex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajslater%2Fcodex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajslater%2Fcodex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajslater%2Fcodex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajslater%2Fcodex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ajslater","download_url":"https://codeload.github.com/ajslater/codex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ajslater%2Fcodex/sbom","scorecard":{"id":174946,"data":{"date":"2025-08-11","repo":{"name":"github.com/ajslater/codex","commit":"749fdcfd51ec5edfc5d51d9f32e55a09ab1ae7de"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":10,"reason":"15 commit(s) and 4 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: docker/Dockerfile:3","Warn: containerImage not pinned by hash: docker/Dockerfile:14","Warn: containerImage not pinned by hash: docker/base.Dockerfile:1: pin your Docker image by updating ajslater/python-debian:3.13.0-slim-bookworm_0 to ajslater/python-debian:3.13.0-slim-bookworm_0@sha256:faaea8219a2c76d7bbe328a2a6809f752b6065245661fa9cfade8b21de017729","Warn: containerImage not pinned by hash: docker/builder-base.Dockerfile:1: pin your Docker image by updating nikolaik/python-nodejs:python3.13-nodejs24 to nikolaik/python-nodejs:python3.13-nodejs24@sha256:9557a244d40542c0f0b5d73fb0e9ff489d256e8094c0ee194b06f7d3586acba0","Warn: containerImage not pinned by hash: docker/dev.Dockerfile:1","Warn: containerImage not pinned by hash: docker/dist-builder.Dockerfile:2","Warn: pipCommand not pinned by hash: docker/Dockerfile:12","Warn: pipCommand not pinned by hash: docker/base.Dockerfile:26","Warn: pipCommand not pinned by hash: docker/builder-base.Dockerfile:33","Warn: pipCommand not pinned by hash: docker/dev.Dockerfile:15-16","Warn: npmCommand not pinned by hash: docker/dist-builder.Dockerfile:23","Warn: npmCommand not pinned by hash: docker/dist-builder.Dockerfile:28","Warn: pipCommand not pinned by hash: bin/circleci/old/circleci-set-skip-dist-build.sh:4","Warn: pipCommand not pinned by hash: bin/circleci/old/circleci-set-skip-dist-build.sh:5","Warn: npmCommand not pinned by hash: bin/update-deps.sh:7","Warn: pipCommand not pinned by hash: docker/docker-create-multiarch-codex.sh:12","Warn: pipCommand not pinned by hash: docker/docker-env.sh:8","Warn: downloadThenRun not pinned by hash: docker/install-uv.sh:7","Warn: npmCommand not pinned by hash: frontend/bin/update-deps.sh:4","Info:   0 out of   8 pipCommand dependencies pinned","Info:   0 out of   4 npmCommand dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned","Info:   0 out of   6 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T17:28:52.519Z","repository_id":37885964,"created_at":"2025-08-16T17:28:52.519Z","updated_at":"2025-08-16T17:28:52.519Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28996568,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T23:10:54.274Z","status":"ssl_error","status_checked_at":"2026-02-01T23:10:47.298Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T18:01:14.639Z","updated_at":"2026-04-05T09:02:24.490Z","avatar_url":"https://github.com/ajslater.png","language":"Python","readme":"# Codex\n\nA comic archive browser and reader.\n\n\u003cimg src=\"/img/logo.svg\" style=\"\nheight: 128px;\nwidth: 128px;\nborder-radius: 128px;\n\" /\u003e\n\n## 🚨 Announcement 🚨\n\n### Docker\n\nThe Docker image has moved to\n[ghcr.io/ajslater/codex](https://github.com/ajslater/codex/pkgs/container/codex).\nA final docker.io image has been released on dockerhub.\n\n## ✨ Features\n\n- Codex is a web server.\n- Full text search of comic metadata and bookmarks.\n- Filter and sort on all comic metadata and unread status per user.\n- Browse a tree of Publishers, Imprints, Series, Volumes, or your own folder\n  hierarchy, or by tagged Story Arc.\n- Read comics in a variety of aspect ratios and directions that fit your screen.\n- Watches the filesystem and automatically imports new or changed comics.\n- Anonymous browsing and reading or reigistered users only, to your preference.\n- Per user bookmarking \u0026 settings, even before you make an account.\n- Private Libraries accessible only to certain groups of users.\n- Reads CBZ, CBR, CBT, and PDF formatted comics.\n- Syndication with OPDS 1 \u0026 2, streaming, search and authentication.\n- Add custom covers to Folders, Publishers, Imprints, Series, and Story Arcs.\n- Remote-User HTTP header SSO support.\n- Runs in 1GB of RAM, faster with more.\n- GPLv3 Licenced.\n\n### Examples\n\n- _Filter by_ Story Arc and Unread, _Order by_ Publish Date to create an event\n  reading list.\n- _Filter by_ Unread and _Order by_ Added Time to see your latest unread comics.\n- _Search by_ your favorite character to find their appearances across different\n  comics.\n\n## 👀 Demonstration\n\nYou may browse a [live demo server](https://demo.codex-reader.app/) to get a\nfeel for Codex.\n\n## 📜 News\n\nCodex has a [NEWS file](NEWS.md) to summarize changes that affect users.\n\n## 🕸️ HTML Docs\n\n[HTML formatted docs are available here](https://codex-comic-reader.readthedocs.io)\n\n## 📦 Installation\n\n### Install \u0026 Run with Docker\n\nRun the official\n[Docker Image](https://github.com/ajslater/codex/pkgs/container/codex) at\nghcr.io/ajslater/codex.\n\nRead the [Docker instructions](docs/DOCKER.md)\n\nYou'll then want to read the [Administration](#administration) section of this\ndocument.\n\n### Install \u0026 Run on HomeAssistant server\n\nIf you have a [HomeAssistant](https://www.home-assistant.io/) server, Codex can\nbe installed with the following steps :\n\n- Add the `https://github.com/alexbelgium/hassio-addons` repository by\n  [clicking here](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)\n- Install the addon :\n  [click here to automatically open the addon store, then install the addon](https://my.home-assistant.io/redirect/supervisor)\n- Customize addon options, then then start the add-on.\n\n### Install \u0026 Run as a Native Application\n\nYou can also run Codex as a natively installed python application with pip.\n\n#### Binary Dependencies\n\nYou'll need to install the appropriate system dependencies for your platform\nbefore installing Codex.\n\n##### Linux Dependencies\n\n###### Debian Dependencies\n\n...and Ubuntu, Mint, MX, Window Subsystem for Linux, and others.\n\n```sh\napt install build-essential libimagequant0 libjpeg-turbo8 libopenjp2-7 libssl libyaml-0-2 libtiff6 libwebp7 python3-dev python3-pip sqlite3 unrar zlib1g\n```\n\nVersions of packages like libjpeg, libssl, libtiff may differ between flavors\nand versions of your distribution. If the package versions listed in the example\nabove are not available, try searching for ones that are with `apt-cache` or\n`aptitude`.\n\n```sh\napt-cache search libjpeg-turbo\n```\n\n###### Alpine Dependencies\n\n```sh\napk add bsd-compat-headers build-base jpeg-dev libffi-dev libwebp openssl-dev sqlite yaml-dev zlib-dev\n```\n\n##### Install unrar Runtime Dependency on non-debian Linux\n\nCodex requires unrar to read CBR formatted comic archives. Unrar is often not\npackaged for Linux, but here are some instructions:\n[How to install unrar in Linux](https://www.unixtutorial.org/how-to-install-unrar-in-linux/)\n\nUnrar as packaged for Alpine Linux v3.14 seems to work on Alpine v3.15+\n\n##### macOS Dependencies\n\nUsing [Homebrew](https://brew.sh/):\n\n```sh\nbrew install jpeg libffi libyaml libzip openssl python sqlite unrar webp\n```\n\n#### Installing Codex on Linux on ARM (AARCH64) with Python 3.13\n\nPymupdf has no pre-built wheels for AARCH64 so pip must build it and the build\nfails on Python 3.13 without this environment variable set:\n\n```sh\nPYMUPDF_SETUP_PY_LIMITED_API=0 pip install codex\n```\n\nYou will also have to have the `build-essential` and `python3-dev` or equivalent\npackages installed on on your Linux.\n\n#### Windows Installation\n\nWindows users are encouraged to use Docker to run Codex, but it will also run\nnatively on the Windows Subsystem for Linux.\n\nInstallation instructions are in the\n[Native Windows Dependencies Installation Document](docs/WINDOWS.md).\n\n#### Run Codex Natively\n\nOnce you have installed codex, the codex binary should be on your path. To start\ncodex, run:\n\n```sh\ncodex\n```\n\n### Use Codex\n\nOnce installed and running you may navigate to \u003chttp://localhost:9810/\u003e\n\n## 👑 Administration\n\n### Navigate to the Admin Panel\n\n- Click the hamburger menu ☰ to open the browser settings drawer.\n- Log in as the 'admin' user. The default administrator password is also\n  'admin'.\n- Navigate to the Admin Panel by clicking on its link in the browser settings\n  drawer after you have logged in.\n\n### Change the Admin password\n\nThe first thing you should do is log in as the admin user and change the admin\npassword.\n\n- Navigate to the Admin Panel as described above.\n- Select the Users tab.\n- Change the admin user's password using the small lock button.\n- You may also change the admin user's name with the edit button.\n- You may create other users and grant them admin privileges by making them\n  staff.\n\n### Add Comic Libraries\n\nThe second thing you will want to do is log in as an Administrator and add one\nor more comic libraries.\n\n- Navigate to the Admin Panel as described above.\n- Select the Libraries tab in the Admin Panel\n- Add a Library with the \"+ LIBRARY\" button in the upper left.\n\n### Reset the admin password\n\nIf you forget all your superuser passwords, you may restore the original default\nadmin account by running codex with the `CODEX_RESET_ADMIN` environment variable\nset.\n\n```sh\nCODEX_RESET_ADMIN=1 codex\n```\n\nor, if using Docker:\n\n```sh\ndocker run -e CODEX_RESET_ADMIN=1 -v host-parent-dir/config:/config ajslater/codex\n```\n\n### Private Libraries\n\nIn the Admin Panel you may configure private libraries that are only accessible\nto specific groups.\n\nA library with _no_ groups is accessible to every user including anonymous\nusers.\n\nA library with _any_ groups is accessible only to users who are in those groups.\n\nUse the Groups admin panel to create groups and the Users admin panel to add and\nremove users to groups.\n\n#### Include and Exclude Groups\n\nCodex can make groups for libraries that exclude groups of users or exclude\neveryone and include only certain groups of users.\n\n### PDF Metadata\n\nCodex reads PDF metadata from the filename, PDF metadata fields and also many\nformats of common complex comic metadata if they are embedded in the PDF\n`keywords` field.\n\nIf you decide to include PDFs in your comic library, I recommend taking time to\nrename your files so Codex can find some metadata. Codex recognizes several file\nnaming schemes. This one has good results:\n\n`{series} v{volume} #{issue} {title} ({year}) {ignored}.pdf`\n\nComplex comic metadata, such as ComicInfo.xml, can be also be embedded in the\nkeywords field by using the [comicbox](https://github.com/ajslater/comicbox)\ncommand line tool. Codex will read this data because it relies on comicbox\ninternally. Not many people use comicbox or embedded metadata in PDFs in this\nfashion, so you likely won't find it unless you've added it yourself.\n\n### 🗝️ API with Key Access\n\nCodex has a limited number of API endpoints available with API Key Access. The\nAPI Key is available on the admin/stats tab.\n\n## 🎛️ Configuration\n\n### Config Dir\n\nThe default config directory is `config/` directly under the working directory\nyou run codex from. You may specify an alternate config directory with the\nenvironment variable `CODEX_CONFIG_DIR`.\n\nThe config directory contains a file named `codex.toml` where you can specify\nports and bind addresses. If no `codex.toml` is present Codex copies a default\none to that directory on startup. e.g.\n\n```toml\n[server]\nhost = \"0.0.0.0\"\nport = 9810\nurl_path_prefix = \"\"\n```\n\nThe config directory also holds the main sqlite database, a Django cache and\ncomic book cover thumbnails.\n\n### Environment Variables\n\nEnvironment variables override values set in the TOML config file.\n\n#### General\n\n- `TIMEZONE` or `TZ` will explicitly set the timezone in long format (e.g.\n  `\"America/Los Angeles\"`). This is useful inside Docker because codex cannot\n  automatically detect the host machine's timezone.\n- `DEBUG_TRANSFORM` will show verbose information about how the comicbox library\n  reads all archive metadata sources and transforms it into a the comicbox\n  schema.\n- `CODEX_CONFIG_DIR` will set the path to codex config directory. Defaults to\n  `$CWD/config`\n\n##### Server\n\n- `GRANIAN_HOST` the IP or hostname to serve Codex from. Defaults to \"0.0.0.0\",\n  all interfaces.\n- `GRANIAN_PORT` the port to serve Codex from. Defaults to 9810.\n- `GRANIAN_WORKERS` Number of worker processes. 1 recommended for containerized\n  environments.\n- `GRANIAN_HTTP` HTTP protocol to use. \"auto\", \"1\" or \"2\". Defaults to \"auto\".\n  Generally you want to serve codex from behind nginx or traefik which will\n  handle the protocol, even HTTP 3, so this should stay on \"auto\".\n- `GRANIAN_WEBSOCKETS` Enable websockets. Required for codex live updates.\n  Default true.\n- `GRANIAN_URL_PATH_PREFIX` HTTP path prefix for codex (e.g. \"/codex\" for\n  reverse proxy sub-path). Defaults to \"\".\n\n##### Repair\n\n- `CODEX_RESET_ADMIN=1` will reset the admin user and its password to defaults\n  when codex starts.\n- `CODEX_FIX_FOREIGN_KEYS=1` will check for and try to repair illegal foreign\n  keys on startup.\n- `CODEX_INTEGRITY_CHECK=1` will perform database integrity check on startup.\n- `CODEX_FTS_INTEGRITY_CHECK=1` will perform an integrity check on the full text\n  search index.\n- `CODEX_FTS_REBUILD=1` will rebuild the full text search index.\n\n#### Logging\n\n- `LOGLEVEL` will change how verbose codex's logging is. Valid values are\n  `CRITICAL`, `ERROR`, `WARNING`, `SUCCESS`, `INFO`, `DEBUG`, and the overly\n  noisy `TRACE`. The default is `INFO`.\n- `CODEX_LOG_DIR` sets a custom directory for saving logfiles. Defaults to\n  `$CODEX_CONFIG_DIR/logs`\n- `CODEX_LOG_RETENTION` how long to keep logs. Defaults to \"6 months\".\n- `CODEX_LOG_TO_FILE=0` will not log to files.\n- `CODEX_LOG_TO_CONSOLE=0` will not log to the console.\n\n##### Browser\n\n- `CODEX_BROWSER_MAX_OBJ_PER_PAGE` the maximum number of objects per page.\n  Defaults to 100.\n\n#### Throttling\n\nCodex contains some experimental throttling controls. The value supplied to\nthese variables will be interpreted as the maximum number of allowed requests\nper minute. For example, the following settings would limit each described group\nto 2 queries per second.\n\n- `CODEX_THROTTLE_ANON=30` Anonymous users\n- `CODEX_THROTTLE_USER=30` Authenticated users\n- `CODEX_THROTTLE_OPDS=30` The OPDS v1 \u0026 v2 APIs (Panels uses this for search)\n- `CODEX_THROTTLE_OPENSEARCH=30` The OPDS v1 Opensearch API\n\n#### Authentication\n\n- `CODEX_AUTH_REMOTE_USER` will allow unauthenticated logins with the\n  Remote-User HTTP header. This can be very insecure if not configured properly.\n  Please read the Remote-User docs devoted to it below.\n\n### Reverse Proxy\n\n[nginx](https://nginx.org/) is often used as a TLS terminator and subpath proxy.\n\nHere's an example nginx config with a subpath named '/codex'.\n\n```nginx\n# HTTP\nproxy_set_header   Host $http_host;\nproxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;\nproxy_set_header   X-Forwarded-Host $server_name;\nproxy_set_header   X-Forwarded-Port $server_port;\nproxy_set_header   X-Forwarded-Proto $scheme;\nproxy_set_header   X-Real-IP $remote_addr;\nproxy_set_header   X-Scheme $scheme;\n# Websockets\nproxy_http_version 1.1;\nproxy_set_header   Upgrade $http_upgrade;\n\nproxy_set_header Connection \"Upgrade\" location /codex {\n    proxy_pass       http://codex:9810;\n    # Codex reads http basic authentication.\n    # If the nginx credentials are different than codex credentials use this line to\n    #   not forward the authorization.\n    proxy_set_header Authorization \"\";\n}\n```\n\nSpecify a reverse proxy sub path (if you have one) in `config/codex.toml`\n\n```toml\n[server]\nurl_path_prefix = \"/codex\"\n```\n\n#### Nginx Reverse Proxy 502 when container refreshes\n\nNginx requires a special trick to refresh dns when linked Docker containers\nrecreate. See this\n[nginx with dynamix upstreams](https://tenzer.dk/nginx-with-dynamic-upstreams/)\narticle.\n\n#### Single Sign On and Third Party Authentication\n\n##### OAuth \u0026 OIDC\n\nCodex is not an OIDC client at this time. However the following Remote-User and\nToken Authentication methods may assist other services in providing Single Sign\nOn.\n\n##### Remote-User Authentication\n\nRemote-User authentication tells Codex to accept a username from the webserver\nand assume that authentication has already been done. This is very insecure if\nyou haven't configured an authenticating reverse proxy in front of Codex.\n\nHere's a snipped for configuring nginx with tinyauth to provide this header.\nThis snipped it incomplete and assumes that the rest of nginx tinyauth config\nhas been done:\n\n```nginx\nauth_request_set $tinyauth_remote_user $upstream_http_remote_user;\nproxy_set_header Remote-User $tiny_auth_user;\n```\n\n⚠️ Only turn on the `CODEX_AUTH_REMOTE_USER` environment variable if your\nwebserver sets the `Remote-User` header itself every time for the Codex\nlocation, overriding any malicious client that might set it themselves. ⚠️\n\n##### HTTP Token Authentication\n\nYou can also configure your proxy to add token authentication to the headers.\nCodex will read “Bearer” prefixed authorization tokens. The token is unique for\neach user and may be found in the Web UI sidebar. You must configure your proxy\nor single sign on software to send this token.\n\n```nginx\nset              user_token 'user-token-taken-from-web-ui';\nproxy_set_header Authorization \"Bearer $user_token\";\n```\n\n### Restricted Memory Environments\n\nCodex can run with as little as 1GB available RAM. Large batch jobs –like\nimporting and indexing tens of thousands of comics at once– will run faster the\nmore memory is available to Codex. The biggest gains in speed happen when you\nincrease memory up to about 6GB. Codex batch jobs do get faster the more memory\nit has above 6GB, but with diminishing returns.\n\nIf you must run Codex in an admin restricted memory environment you might want\nto temporarily give Codex a lot of memory to run a very large import job and\nthen restrict it for normal operation.\n\n## 📖 Use\n\n### 👤 Sessions \u0026 Accounts\n\nOnce your administrator has added some comic libraries, you may browse and read\ncomics. Codex will remember your preferences, bookmarks and progress in the\nbrowser session. Codex destroys anonymous sessions and bookmarks after 60 days.\nTo preserve these settings across browsers and after sessions expire, you may\nregister an account with a username and password. You will have to contact your\nadministrator to reset your password if you forget it.\n\n### ᯤ OPDS\n\nCodex supports OPDS syndication and OPDS streaming. You may find the OPDS url in\nthe side drawer. It should take the form:\n\n`http(s)://host.tld(:9810)(/path_prefix)/opds/v1.2/`\n\nor\n\n`http(s)://host.tld(:9810)(/path_prefix)/opds/v2.0/`\n\n#### OPDS v1 Clients\n\n- iOS\n    - [Panels](https://panels.app/)\n    - [PocketBooks](https://pocketbook.ch/)\n    - [KYBook 3](http://kybook-reader.com/)\n    - [Chunky Comic Reader](https://apps.apple.com/us/app/chunky-comic-reader/id663567628)\n- Android\n    - [Moon+](https://play.google.com/store/apps/details?id=com.flyersoft.moonreader)\n    - [Librera](https://play.google.com/store/apps/details?id=com.foobnix.pdf.reader)\n\nKybook 3 does not seem to support http basic authentication, so Codex users are\nnot supported.\n\n#### OPDS v2 Clients\n\nOPDS 2.0 is a newer protocol that is only just starting to be supported by new\nclients.\n\n- [Stump (Alpha Test)](https://www.stumpapp.dev/guides/mobile/app)\n- [Readest](https://readest.com/) (No page streaming yet, download only)\n\n#### OPDS Authentication\n\n##### OPDS Login\n\nThe few clients that implement the OPDS 1.0 Authentication spec present the user\nwith a login screen for interactive authentication.\n\n##### HTTP Basic\n\nSome OPDS clients allow configuring HTTP Basic authentication in their OPDS\nserver settings. If the don't, you will have to add your username and password\nto the URL. In that case the OPDS url will look like:\n\n`http(s)://username:password@codex-server.tld(:9810)(/path_prefix)/opds/v1.2/`\n\n##### HTTP Token\n\nSome clients allow adding a unique login token to the HTTP headers. Codex will\nread \"Bearer\" prefixed authorization tokens. The token is unique for each user\nand may be found in the Web UI sidebar.\n\n#### Supported OPDS Specifications\n\n##### OPDS v1\n\n- [OPDS 1.2](https://specs.opds.io/opds-1.2.html)\n- [OPDS-PSE 1.2](https://github.com/anansi-project/opds-pse/blob/master/v1.2.md)\n- [OPDS Authentication 1.0](https://drafts.opds.io/authentication-for-opds-1.0.html)\n\n##### OPDS v2\n\n- [OPDS 2.0 (draft)](https://drafts.opds.io/opds-2.0.html)\n- [OPDS 2.0 Digital Visual Narratives Profile (DiViNa)](https://github.com/readium/webpub-manifest/blob/master/profiles/divina.md)\n- [OPDS 2.0 Authentication (proposal)](https://github.com/opds-community/drafts/discussions/43)\n- [OPDS 2.0 Progression (proposal)](https://github.com/opds-community/drafts/discussions/67)\n\n##### OpenSearch v1\n\n- [OpenSearch 1.1 (draft)](https://github.com/dewitt/opensearch)\n\n## [🩺 Troubleshooting](#troubleshooting)\n\n### 📒 Logs\n\nCodex collects its logs in the `config/logs` directory. Take a look to see what\nth e server is doing.\n\nYou can change how much codex logs by setting the `LOGLEVEL` environment\nvariable. By default this level is `INFO`. To see more verbose messages, run\ncodex like:\n\n```sh\nLOGLEVEL=DEBUG codex\n```\n\n### Watching Filesystem Events with Docker\n\nCodex tries to watch for filesystem events to instantly update your comic\nlibraries when they change on disk. But these native filesystem events are not\ntranslated between macOS \u0026 Windows Docker hosts and the Docker Linux container.\nIf you find that your installation is not updating to filesystem changes\ninstantly, you might try enabling polling for the affected libraries and\ndecreasing the `poll_every` value in the Admin console to a frequency that suits\nyou.\n\n### Emergency Database Repair\n\nIf the database becomes corrupt, Codex includes a facility to rebuild the\ndatabase. Place a file named `rebuild_db` in your Codex config directory like\nso:\n\n```sh\ntouch config/rebuild_db\n```\n\nShut down and restart Codex.\n\nThe next time Codex starts it will back up the existing database and try to\nrebuild it. The database lives in the config directory as the file\n`config/db.sqlite3`. If this procedure goes kablooey, you may recover the\noriginal database at `config/backups/codex.sqlite3.before-rebuild`. Codex will\nremove the `rebuild_db` file.\n\n### Warnings to Ignore\n\n#### StreamingHttpResponse Iterator Warning\n\n```pycon\npackages/django/http/response.py:517: Warning: StreamingHttpResponse must consume synchronous iterators in order to serve them asynchronously. Use an asynchronous iterator instead.\n```\n\nThis is a known warning and does not represent anything bad happening. It's an\nartifact of the Django framework slowly supporting asynchronous server endpoints\nand unfortunately isn't practical to remove yet.\n\n## 📚Alternatives to Codex\n\n- [Kavita](https://www.kavitareader.com/) has light metadata filtering/editing,\n  supports comics, eBooks, and features for manga.\n- [Komga](https://komga.org/) has light metadata editing and duplicate page\n  elimination.\n- [Ubooquity](https://vaemendis.net/ubooquity/) reads both comics and eBooks.\n\n## 🔧 Popular comic utilities\n\n- [Mylar](https://github.com/mylar3/mylar3) is the best comic book manager which\n  also has a built in reader.\n- [Comictagger](https://github.com/comictagger/comictagger) is a comic metadata\n  editor. It comes with a command line and desktop GUI. It will tag identified\n  comics from online database sources.\n- [Metron Tagger](https://github.com/Metron-Project/metron-tagger) is a command\n  line comic metadata editor. It will tag identified comics from online database\n  sources.\n- [Comicbox](https://github.com/ajslater/comicbox) is a powerful command line\n  comic metadata editor and multi metadata format synthesizer. It is what Codex\n  uses under the hood to read comic metadata.\n\n## 🤝 Contributing\n\n### 🐛 Bug Reports\n\nIssues and feature requests are best filed on the\n[Github issue tracker](https://github.com/ajslater/codex/issues).\n\n## 💬 Support\n\nI and other Codex users answer questions on the\n[Codex Comic Server Discord](https://discord.gg/CU5kKxv7kg)\n\n### 🛠 Develop\n\nCodex's git repo is mirrored on [Github](https://github.com/ajslater/codex/)\n\nCodex is a Django Python webserver with a VueJS front end.\n\n`/codex/codex/` is the main django app which provides the webserver and\ndatabase.\n\n`/codex/frontend/` is where the vuejs frontend lives.\n\nMost of Codex development is now controlled through the Makefile. Type `make`\nfor a list of commands.\n\n## 🔗 Links\n\n- [Docker Image](https://github.com/ajslater/codex/pkgs/container/codex)\n- [PyPi Package](https://pypi.org/project/codex/)\n- [GitHub Project](https://github.com/ajslater/codex/)\n\n## 🙏🏻 Thanks\n\n- Thanks to [Aurélien Mazurie](https://pypi.org/user/ajmazurie/) for allowing me\n  to use the PyPi name 'codex'.\n- To [ProfessionalTart](https://github.com/professionaltart) for providing\n  native Windows installation instructions.\n- Thanks to the good people of\n  [#mylar](https://github.com/mylar3/mylar3#live-support--conversation) for\n  continuous feedback and comic ecosystem education.\n\n## 😊 Enjoy\n\n![These simple people have managed to tap into the spiritual forces that mystics and yogis spend literal lifetimes seeking. I feel... ...I feel...](docs/strange.jpg)\n","funding_links":[],"categories":["\u003ca id=\"tag-internet\" href=\"#tag-internet\"\u003eInternet\u003c/a\u003e"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajslater%2Fcodex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fajslater%2Fcodex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fajslater%2Fcodex/lists"}