This document describes how to setup a functional instance of a JMdictDB server including loading dictionary data. An instance of JMdictDB can be installed for development or production or both.

For information about the operation and maintenance of a JMdictDB instance, including performing code and database upgrades, see the Operations Guide.

For information about doing development work on JMdictDB see the Development Guide.

For information on changing the set of tags that can be applied to JMdictDB entries see the Tags Guide.

A project description page is at:
The JMdictDB source code is available at:
Discussion takes place on the Google Groups Edict-JMdict mailing list ( | |

1. Installing and Configuring JMdictDB

Although the JMdictDB software was written and is maintained primarily to support Jim Breen’s JMdict and wwwjdic projects at, you may wish to install a local copy of this software to:

  • Run a local JMdictDB server for your own use.

  • Contribute development work to the JMdict project.

  • Use or adapt the code to a project of your own.

This document describes how to setup a functional instance of a JMdictDB server including loading dictionary data. An instance of JMdictDB can be installed for development or production or both. The primary difference is that for development the code is run directly from a developer’s local directory and web pages served using a private web server built into the JMdictDB code. For production use, the code is installed to dedicated system locations: the jmdictdb Python package to a library directory with other Python packages, the log and configuration files to directories with other such files, the command line programs to /usr/local/bin/, etc., and web pages are served using separate, high-capacity, robust webserver.

The two primary external pieces of software that JMdictDB uses, a Postgresql database server and Apache (or other WSGI-capable) web server provide many different configuration options. How they are configured will depend on individual site policies and preferences. These instructions describe one possible set of choices based on the author’s experience; you should adjust them as needed for your environment.

2. Requirements

The JMdictDB code is currently developed and tested on Ubuntu Linux using Apache-2.4/mod_wsgi as a web server and Postgresql as the database server. The JMdictDB web application should be runnable with any WSGI-capable web server but to date has only been tested with Apache.

Earlier versions of this software generated web pages using CGI scripts rather than a WSGI application as is used currently. CGI support was removed in rev 230825-d65ac09.
Regarding Microsoft Windows: Up to mid 2014 the code also ran and was supported on Microsoft Windows XP. However, lack of access to a Windows machine necessitated dropping Windows support. Please be aware that lingering references to Microsoft Windows in this and other documentation are outdated and unsupported.

JMdictDB requires Python 3; Python 2 is no longer supported although the last working Python 2 version is available in the code repository in the branch, "py2".

Some additional Python modules are also needed. Version numbers are the versions currently in use in the author’s development environment circa 2022; the software may work fine with earlier or later versions, but this has not been verified.

If you plan on doing development of JMdictDB some additional software, used by the test scripts or in various build chains, is also required. Please see Appendix A of the Development Guide.

Note 1: JMdictDB should work with any WSGI-capable web server. This documentation assumes Apache only because that is what the author is familiar with.

3. Document conventions and placeholders

In the sections that follow the following placeholders should be replaced with actual values:


The local development directory where the JMdictDB code has been checked out to from Git. Example value: ~/devel/jmdictdb/


URL root that the Apache web server will be configured to serve the JMdictDB pages under. Example value: /jmdictdb (the web server will serve the JMdictDB pages under the URLs https://localhost/jmdictdb/, e.g., https://localhost/jmdictdb/


The location to install the web component files to. and where the web server will be configured to look for them at. Example value: /usr/local/jmdictdb/. The default value is /var/www/jmdictdb/.


Path and filename of the .wsgi file (see section 6.2.4, “Create a .wsgi file”).

4. Users and Authentication

This section describes the three types of users involved when installing and using JBdictDB and their authentication requirements as background for the procedures presented later.

The three types are:

  • Operating system — You will have an OS user account you log into when installing or maintaining JMdictDB. Additionally, some activities my require root access, either by logging into the system’s root account, or using sudo or su from your normal account.

  • Database — The Postgresql database server has its own set of users, independent of the OS users (although it’s common for a user to use the same user name as both an OS login and a database login for convenience.)

  • JMdictDB — has a third set of users called editors that are maintained using the tool or the Users web page.

4.1. Database Authentication

The term "database server" refers to the entire Postgresql instance. JMdictDB uses multiple, separate databases within the database server. For example, the database "jmdict" is typically the "production" database while database "jmnew" is used for loading dictionaries from source files. There may also be a "jmdev" database for development as well as others.

Any program that accesses the database server needs a username and possibly a password to do so. Note that these usernames and passwords are distinct from both the usernames/passwords used to log into the operating system and the usernames/passwords used to log in as an editor on the JMdictDB web pages.

Database server usernames in Postgresql are common to the entire server, they are not unique per database.

Postgresql provides very flexible control over how database used authenticate with the server. On a freshly installed Postgresql instance, "local" users (those connecting without specifying a --host value) will use "peer" authentication; connections will be via an OS socket and are authenticated if the database username matches the OS username. For "host" users (those connecting with a --host value, even if it is "localhost") the connection is made via tcp/ip, any database user name can be used and authentication is via a password. It is common for Postgresql to be configured after install to require passwords for all users with "peer" authentication reserved for the "postgres" super-user. Many other authentication methods are also possible (gssapi, ssl certificates, ldap, etc).

The database server is accessed by the JMdictDB system in two contexts:

  1. When the web server receives an HTTP request for a JMdictDB page and accesses the database in the course of generating the web page response.

  2. When Postgresql and JMdictDB command line tools are run by a user. This includes their execution by the makefiles during installation.

In case (1) JMdictDB backend code will use database usernames and passwords defined in the jmdictdb-pvt.ini file which will be described in more detail below.

In the second case, the database username and password may be given on the command line (in the database URI) but allowing Postgresql to default to the same username as the your OS username usually removes the need to specify it explicitly. If Postgresql if configured for

A detailed discussion of Postgresql authentication methods is out of scope here but Appendix B: Postgresql authentication documentation provides some further references.

4.2. Editor Authentication

JMdictDB provides a separate, application-level authentication scheme for web access. Users can login as Admin, Editor or access the system anonymously by not logging in. The web pages allow anonymous users to submit unapproved edited or new entries, but to approve or reject entries, a user must be logged in as an Editor. A user logged in as Admin can additionally manage other users.

JMdictDB users and their access levels are stored in a separate separate database named "jmsess". This database need only be setup once. Management of the user accounts in "jmsess" may be done by the program bin/ (see section 7, “Add JMdictDB editors and admins” in this document and section 2. User management in the Operations Guide), or, after the install is completed, by the web page.

5. JMdictDB Installation

Setting up a JMdictDB instance involves:

  1. Clone the JMdictDB software into a local directory.

  2. Configure the Postgresql database server.

  3. Use the JMdictDB tools to load the database with dictionary data.

  4. Configure the JMdictDB .ini file(s).

  5. Configure the Apache web server.

  6. Install the JMdictDB software. This step installs the jmdictdb library package, command line programs and web scripts to locations independent of the development directory allowing the latter to be changed or deleted without affecting the operation of the installed version.

  7. Configure the .ini file(s) for the production server.

Makefiles are provided that automate loading the database (Makefile-db) and installing the JMdictDB software (Makefile).

5.1. Get the code

There are two main branches in the code:

  • master: the latest version and the branch new development should generally be based on.

  • edrdg: the version currently (or soon to be) running at

Clone the JMdictDB repository from GitLab. {{DEVDIR}} must not exist or must be empty.

$ git clone {{DEVDIR}}
$ cd {{DEVDIR}}
$ tools/
$ tools/
post-checkout and post-commit hooks installed
The JMdictDB install process involves building a Python package with a version number that includes the Git revision number. Therefore you’ll need the actual cloned Git repository to install JMdictDB; a download (e.g., .tar.gz) of the current files is not sufficient.
From here on, unless indicated otherwise, we assume the current directory is the {{DEVDIR}} directory.

The two tools/…​ commands need only be done once after cloning a fresh JMdictDB repository (although running them multiple times or at any time is harmless). They update a version file (jmdictdb/ with the current Git revision number. That version number is later used when building an installable Python package and shown in the web page. The second command installs two Git hooks that will automatically update the version number in the future. They need to be installed manually because Git provides no way to receive hooks automatically when cloning a repository.

5.2. Configure the Postgresql database server

This section assumes that Postgresql has been installed with its default configuration which allows local (socket-based) password-less access to any database user from a OS host user account with the same name and remote (tcpip-based) access to any database user who has a password set.

We also assume that the database account

5.2.1. Get access to the Postgresql server

If you do not have your own Postgresql database login yet (e.g., after a fresh install of Postgresql), create one.

# sudo -u postgres createuser -drP {{DBLOGIN}}

Replace {{DBLOGIN}} with your operating system login name. Using your operating system login name for the database login name is convenient since most Postgresql tools will default to that value; using something else is possible but will require you to explicitly supply it when running Postgresql commands. The -dr options give the login the CREATEROLE and CREATEDB privileges.

The CREATEROLE privilege is very powerful and can be leveraged to get superuser access to the database. It is only needed for the next step ( 5.2.2, “Create the jmdictdb users and session database”) and can be dropped after it is completed.

You will be prompted (twice) to enter a password for the new login.

5.2.2. Create the jmdictdb users and session database

JMdictDB accesses its database using two dedicated Postgresql database user accounts, by default named "jmdictdb" (for read-write access) and "jmdictdbv" (for read-only access) although you can choose alternate names (in which case substitute them for jmdictdb/jmdictdbv throughout the rest of this document.)

$ createuser jmdictdb

You will be prompted to enter a password for the new user. Record it since you will need to enter it in a configuration file later. Repeat again to create the jmdictdbv user.

$ createuser jmdictdbv

Authorize yourself to act as the jmdictdb user:

$ psql -d postgres -c 'GRANT jmdictdb TO {{DBLOGIN}}

JMdictDB uses a small database, conventionally named "jmsess" to store information about JMdictDB users and their active sessions.

$ psql -d postgres -f db/mksess.sql
You need (and should) only do these steps once when installing JMdictDB on a machine for the first time, even if you reinstall the JMdictDB software multiple times.

5.2.3. Create a .pgpass file

Many install and maintenance scripts will perform multiple database operations as user "jmdictdb" and will result in frequent prompts for the "jmdictdb" password. To avoid this you can create a ~/.pgpass file in your home directory.

$ cd && cat >>.pgpass
$ chmod 600 .pgpass

Replace <password> with the real password that was set for user "jmdictdb" in section 5.2.2, “Create the jmdictdb users and session database” above. The chmod command is required as Postgresql will ignore .pgpass files that are group or world readable.

If your own Postgresql account requires a password to login you can add a line for that too:


5.3. Load the database

By default, the main "production" database is named "jmdict". Other databases are used when loading data, for testing, etc. The makefile targets that load data do so into a database named "jmnew" so as to not damage any working database in the event of a problem. A make target, "activate" is provided to move a newly loaded database to "jmdict".

The process is:

$ make -f Makefile-db jmnew

Repeat the following, where "loadXX" is one of loadjm (JMdict), loadne (JMnedict), loadkd (kanjidic2), loadex (Tatoeba examples) for as many of the those sources as you want to load. Each of the "loadXX" targets will download the appropriate source file to the data/ directory, parse it and load the data into the "jmnew" database.

$ make -f Makefile-db loadXX

Then as the last step:

$ make -f Makefile-db postload

As a shortcut, the target loadall will do the above for all four of the dictionaries.

No provision is made for concurrent access while loading data; we assume that the only access to the database being loaded is by the procedures used for the loading. However, use of databases other than the one being loaded (which is usually "jmnew") can continue as usual during loading.

5.4. Activate the loaded database

If everything went well above you can do:

$ make -f Makefile-db activate

which simply renames the "jmnew" database to "jmdict".

At this point you can use the command line tools in bin/ and tools/. For example:

$ bin/ -q 1002570

If you don’t care about setting up a production instance with web access via Apache web server server right now and just want to try out the web UI privately, then configure and run the Flask debug server as described in the development Guide: Setting up a development environment You can come back to the next 6, “JMdictDB Web UI Configuration” section later.

Or, continue to the next section to set up access via the Apache web server.

6. JMdictDB Web UI Configuration

This section will describe how to install the JMdictDB software so it is available system-wide and configure an Apache web server to provide public access to the JMdictDB web pages.

The steps here represent only one way of accomplishing this; Apache can be configured in many different ways and sites have different policies on how it should be done. You will need to adapt these steps to the policies in place where you are installing it.

Most of the commands in this section need to be run by a root user, indicated by a preceding "#". You can do this by logging into a root account or running the command with 'su' or 'sudo'.

6.1. Install the JMdictDB software

"Installing" the JMdictDB code mostly means installing the JMdictDB python package to the system location where third-party python packages are usually kept, copying the command line tools to a conventional location like /usr/local/bin/, and copying the web UI files (eg *.html, *.css) to a location accessible to the web server.

To install the JMdictDB code do the following.

The root user’s git needs to be told it is ok to run git commands in the jmdictdb directory owned by someone else. [1] The following command need be run only one time as it adds the setting to root’s ~/.gitconfig file.

Run the following as the root user, perhaps using 'sudo'.

# git config --global --add {{DEVDIR}}


# cd {{DEVDIR}}
# make WEBROOT={{WEBROOT}} install-sys

The WEBROOT=…​ part says where to install the web components and may be left out if installing to the default location of /var/www/jmdictdb/.

It is also possible to install the software to per-user specific locations (see below) using make install-user. However this can lead to library confusions when running the development server and is not recommended.

The 'install-sys' target will, by default, install to the following locations:

  • Web files


    Admin files


    Command line programs


    Python library modules

    /usr/local/lib/pythonX.Y/dist-packages/ [**]

For 'install-user' the locations are:

  • Web files


    Admin files


    Command line programs


    Python library modules

    ~/.local/lib/pythonX.Y/site-packages/jmdictdb/ [**]

    [**] — The exact location is determined by OS distribution and Python. X and Y are the major and minor version numbers of the installed Python.

Next you will need to tell the Apache web server where to find the web components and at what URL to serve them.

6.2. Configuration files.

The JMdictDB configuration and log files for the production server are located by default in {{WEBROOT}}/lib/. The locations may be changed as described below.

6.2.1. Create the jmdictdb.ini file

# cd {{WEBROOT}}/lib/

Copy jmdictdb.ini-sample to jmdictdb.ini and edit it, guided by the comments. Note that relative file locations in the config files are relative to the config file directory. In particular the following should be changed:

In the [web] section, uncomment the line:


and provide an appropriate value, for example:


In the [logging] the LOG_FILENAME item is commented out which will cause logging messages to go to stdout; most web servers will write such messages to the web server log file. If you wish the messages (there can be a lot of them depending on log level settings) to go to a dedicated log file instead, uncomment the line and set the value to the log file’s filename. If the filename is not an absolute path it is relative to the configuration file directory. Thus

LOG_FILENAME = jmdictdb.log

will write to the log file, {{WEBROOT}}/lib/jmdictdb.log

LOG_FILENAME = /var/log/apache2/jmdictdb.log

might be another option.

6.2.2. Create the jmdictdb-pvt.ini file

This file defines which Postgresql databases can be accessed though the web UI and provide access credentials for them.

Copy jmdictdb-pvt.ini-sample to jmdictdb-pvt.ini and edit it.

In the [flask] section, in the line:

key = xxxxxxxxxxxxxxxx

replace the string of x’s with a passphrase or better, a string of random characters, ideally longer than 16 characters. A convenient way to generate such a string is with any of the online password generator websites.

Uncomment the ";pw =" and ";sel_pw = " lines in the DEFAULT section and replace the "yyyyyy" and "zzzzzz" values with the passwords assigned to the Postgresql "jmdictdb" and "jmdictdbv" users in section 5.2.2, “Create the jmdictdb users and session database”. (If you used different user names, you should also change the values of "user =" and "sel_user =" to match.) These settings can also be used in each individual "db_*" section to override the default values for that section.

Make sure that jmdictdb-pvt.ini is not world-readable but is readable by the Apache webserver process:

# chmod 640 jmdictdb-pvt.ini
# chgrp www-data jmdictdb-pvt.ini

where "www-data" is the web server process user (typical for Debian-derived systems, may be different in other distributions.)

6.2.3. Create the log file.

The logfile must be manually created, the JMdictDB server will not create it automatically and will not try to write to it if it doesn’t exist.

Assuming the {{LOGFILE}} is the filename as given in the jmdictdb.ini file, then:

# cd {{WEBROOT}}/lib/
# touch {{LOGFILE}}
# chgrp www-data {{LOGFILE}}
# chmod 664 {{LOGFILE}}

"www-data" is the user name the web server typically runs under on Debian-derived systems; you may need to change it to something different on other OS distributions.

The JMdictDB software tries not to write sensitive information like passwords to the log file but like all software is not perfect. Additionally different sites will have different definitions of "sensitive". You may wish to use a permissions value of 660 rather than 664 on the log file.

6.2.4. Create a .wsgi file

This file is a shim between Apache and the JMdictDB software. Its name is specified in the Apache configuration directives (see below) and its job is to load the JMdictDB Flask module into Apache’s mod_wsgi processes when they are started. To minimize changes in the following instructions it is most conveniently located in:


but it can have any filename and be can be located anywhere accessible to the web server if corresponding adjustments are made in the following instructions. The path and filename chosen are referred to as {{WSGI}} below.

Create the {{WSGI}} file with the following contents:

import sys, os, os.path as p, jmdictdb
our_directory = p.dirname (__file__)
sys.wsgi_file = __file__   # See comments in views/
if not os.environ.get('JMDICTDB_CFGFILE'):
    cfgfile = p.normpath (p.join (our_directory, '../lib/jmdictdb.ini'))
    os.environ['JMDICTDB_CFGFILE'] = cfgfile
from jmdictdb.flaskapp import App as application
If you placed this file in a directory other than a sibling directory of {{WEBROOT}}/lib/ or you chose to use a configuration filename other than jmdictdb.ini, you will need to adjust the relative path and/or filename in the ‘cfgfile=…​’ line in the .wsgi file above.

6.3. Configure the Apache webserver

Many sites will already have Apache installed with established policies regarding configuration. You may have to adapt the instructions below to conform to those policies.

6.3.1. Load the mod_wsgi module

  1. Make sure the mod_wsgi module package is installed. On Debian-derived systems this can by done by:

    # apt install libapache2-mod-wsgi-py3

    On other OSes the command and package name may be different. The mod_wsgi website had general installation instructions:

  2. Make sure it is loaded into the Apache web server. On Debian/Ubuntu:

    # a2enmod wsgi

    On other systems you may need to edit the Apache configuration file and add a 'LoadModule …​' line.

When the web server starts, it will run the .wsgi file which in turn will load the JMdictDB code. Apache will then call that code whenever a JMdictDB request is received. The directives here tell Apache where the .wsgi file is and what URL is the root for the JMdictDB pages.

The following configuration directives can go in the main Apache configuration file, or at most sites, in a separate .conf file in a configuration directory. Refer to the Apache documentation for specifics. Note that the paths in the Alias directive must end with a "/" character.

WSGIDaemonProcess jmwsgi processes=2 threads=10 \
    display-name=apache2-jmwsgi locale=en_US.UTF-8 lang=en_US.UTF-8
WSGIProcessGroup jmwsgi
WSGIScriptAlias {{URLROOT}} {{WSGI}} process-group=jmwsgi

  # Serve static files directly without using the app.
Alias {{URLROOT}}/web/ {{WEBROOT}}/
<Directory {{WEBROOT}}>
    DirectoryIndex disabled
    Require all granted

The number of process and threads can be adjusted depending on server capacity (number of cores, amount of memory, etc) and expected request load. For more information see:

If you placed the directives above in a separate .conf file, make sure that the main Apache configuration file has an #Include directive or similar to read it.

Restart the web server.

6.3.3. Verify web access

You should now be able to view any of the JMdictDB web pages in your web browser at the URL:


7. Add JMdictDB editors and admins

The JMdictDB web interface allows anyone to view entries and to submit provisional entries. To approve entries one must login as an Editor and to manage other users (add, delete, modify, etc.) one must login as an Admin. User management can be done from the web page but you need to create an initial Admin user before you can access that page.

To add an initial admin user:

$ bin/ -d jmsess add <username> -pa --pw

You will be prompted to enter a password for the user. You can now visit http://localhost/{{URLROOT}}/ with a web browser. The page will initially say that access is not allowed but if you login with the username and password of the user you just added, you will get access and be able to change that user’s details (add a full name for example) and add and modify other users. Or if you prefer you can continue to manage users directly with the program.

For full details on using, view its help:

$ bin/ --help

8. Upgrading the JMdictDB software

The process for upgrading JMdictDB is covered in the Upgrading JMdictDB section of the Operations Guide.

Appendix A: Common problems

  1. Flask server fails with traceback

    This will happen when tools/ hasn’t been run (see section 5.1, “Get the code”)

    Traceback (most recent call last):
      File "tools/", line 45, in <module>
      File "tools/", line 32, in main
        from jmdictdb import flaskapp
      File "/home/stuart/jmdictdb/tools/../jmdictdb/", line 1, in <module>
        from . import __version__
    ImportError: cannot import name '__version__' from partially initialized module 'jmdictdb' (most likely due to a circular import) (/home/stuart/jmdictdb/tools/../jmdictdb/
  2. "500 - Server Error" web page returned

    Check the web server’s error log. There will often be a Python stack dump from the JMdictDB code that will identify the problem.

  3. JMdictDB error page: "Unavailable service (xxxx)"

    Either the service name given in the "svc=…​" URL parameter ("xxxx" in the example) is not defined in config-pvt.ini (or the equivalent file) or the database in the service definition does not exist in the Postgresql server.

  4. file not found: …​/jmdictdb.ini

    There needs to be a lib/jmdictdb.ini file, even if it is empty.

  5. file not found: …​/config.ini

    Prior to the switch from CGI to WSGI (November 2021 WSGI Upgrade) the recommended name for the configuration files was config.ini (which typically referenced config-pvt.ini for private information). Those file names are still fine and an existing jmdictdb.ini can be renamed to config.ini (assuming that is the name the existing .wsgi file looks for) or the .wsgi file can be edited to look for jmdictdb.ini.

  6. error: connection to server on socket "…​" failed: FATAL: Peer authentication failed for user "jmdictdb"

    Postgresql is configured by default to accept local connections from an OS account of the same name as the PG username. Run the command with a --host=localhost option (or equivalent), set an environment variable: export PGHOST=localhost, or edit /etc/postgres/…​/pg_hba and allow passworded logins for local (socket) connections as well as tcp/ip connections.

  7. postgresql authentication error / fe_sendauth: no password supplied


    postgresql authentication error
    fe_sendauth: no password supplied

    The db access section named [db_foo] is either missing from the config-pvt.ini or config.ini file or it is present but the username and/or password for the database server are wrong.

  8. api requires updates xxxxxx / db has updates xxxxxx

    The version of the API (in jmdictdb/ in different than the database version (in table "db" or more conveniently viewable in view "dbx"). If the API version is newer, you need to apply the appropriate updates from db/updates/. If older, since there is no easy way to "downgrade" a database, you’ll need to find an older database of the correct version or load a database from source files (eg JMdict XML).

  9. No entries in jmdictdb log file

    • Check the web server’s error log file. If the JMdictDB log file can’t be opened for writing an error message to that effect will be written to stderr which should appear in the web server error log file.

    • Check the config.ini file. The default log file name and location is web/lib/jmdictdb.logout can be overridden in the config.ini file.

    • Make sure the log file is writable by the web server process.

Appendix B: Postgresql authentication documentation

For more information on Postgresql usernames, passwords and the .pgpass file, see the Postgresql docs:

33.15 Client Interfaces / libpq / The Password File

31.1 Client Interfaces / libpq / Database Connection - Control Functions

20 Server Administration / Client Authentication

sec VI Reference / Postgresql Client Applications / psql / Usage / Connecting to a Database

Note that chapter numbers may vary between Postgresql versions and these are for Postgresql version 10.

1. The 'git config' command is needed to override security protections added to Git in April 2022. For more details see: If you wish, you can undo the Git configuration change after the install is done with git config --global --unset {{DEVDIR}}