Why run your own grammar checker
The job is simple: check spelling, grammar and style in what you write, on a server you rent rather than one somebody else runs. LanguageTool, the open-source proofreader, comes with an embedded HTTP server for exactly this, and its browser add-on can be told to use it.
Know what you give up before you start. The official server page says your own copy is a basic server: the AI-based rules are only available in the cloud. The Windows desktop app will not work with a server you run yourself, and the add-on cannot offer synonyms from it. The same page also says this route is aimed at advanced users who are at home on the command line.
Will a small server do?
For the basic checker, disk is barely a question: the current snapshot download is around 263 MB, and the files inside it add up to about 420 MB (we summed the archive's file list). The project does not publish a memory figure, so watch how much it uses on your own texts.
The optional n-gram data changes the picture. It helps LanguageTool spot words that are easy to mix up, like their and there, and it is big:
- English: the download is about 9 GB, which the docs round to roughly 8 GB. Unpacked, its files total about 15.4 GB by our count.
- German 1.7 GB, Spanish 1.7 GB, French 1.8 GB, as downloads.
- The docs ask for a fast disk, meaning an SSD; without one, they warn, LanguageTool can become much slower.
Our own sum: while the English file unpacks, the ZIP and its contents sit side by side, so leave about 25 GB free.
The server that fits
Pick from our dedicated servers by the disks first. If you want the n-gram data, choose one whose storage says SSD or NVMe; the plain checker needs well under 1 GB of disk on any of them; watch memory on your own texts. You get the whole machine and log in as root, so the grammar server can share it with your own wiki, such as a BookStack install.
- A ready server is handed over within 30 minutes of approval, and you can reinstall the operating system yourself from the control panel.
- On rack servers and blades, and on two cartridges (m510, m710x), you get a console reached out of band: the screen and power button even when SSH is down. Every other cartridge offers just remote power control.
- Leave the ARM cartridge aside here: it installs Ubuntu 16.04 or 18.04 only, and this guide assumes Ubuntu 24.04.
- You manage the server; we keep the hardware and the network running.
Up and running in an evening
- Order the server with Ubuntu 24.04 and log in over SSH with a user that can use sudo.
- Install Java 21 and fetch the latest snapshot. The official server page still says Java 8 or later, but that is out of date: since 6.6 LanguageTool requires Java 17, and the change log inside the current snapshot (6.9) says 17 up to 21. Java 21 is the only Java these commands install, so
/usr/bin/javain the service points at it; checkjava -versionif you ever add another. The commands below create a no-login account calledltto run it. - Add the systemd service further down, then start it.
sudo apt update && sudo apt install -y openjdk-21-jre-headless unzip curl
sudo useradd --system --user-group --no-create-home --shell /usr/sbin/nologin lt
sudo mkdir -p /srv/languagetool
cd /srv/languagetool
sudo curl -fLO https://languagetool.org/download/snapshots/LanguageTool-latest-snapshot.zip
sudo unzip -q -o LanguageTool-latest-snapshot.zip -d build-$(date +%Y%m%d)
sudo ln -sfn "$(ls -d /srv/languagetool/build-$(date +%Y%m%d)/LanguageTool-*)" /srv/languagetool/app
sudo touch /srv/languagetool/server.properties
The empty server.properties file is on purpose: the official page says to create one when you skip the optional fastText setup. On Linux they strongly recommend fastText for better language detection; their page links to the build steps and the lid.176.bin model, and you then add fasttextModel and fasttextBinary lines to that file.
Now the service. Put it in /etc/systemd/system/languagetool.service, then run sudo systemctl daemon-reload and sudo systemctl enable --now languagetool.
[Unit]
Description=LanguageTool grammar server
After=network.target
[Service]
User=lt
Group=lt
WorkingDirectory=/srv/languagetool/app
ExecStart=/usr/bin/java -cp /srv/languagetool/app/languagetool-server.jar org.languagetool.server.HTTPServer --port 8081 --config /srv/languagetool/server.properties --allow-origin
Restart=on-failure
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
Never start the checker as root. Its source code prints a warning when it is started that way, and the service above uses the lt account instead.
Reaching it from your laptop
Out of the box, the server is invisible from outside. Its source code binds it to localhost and answers only 127.0.0.1 and ::1 unless you add --public, and the official page says the same in plain words. An SSH tunnel through your own login brings it to your computer without opening anything:
# on your own computer: keep this window open while you write
ssh -N -L 8081:127.0.0.1:8081 you@your-server
# in a second window, on the same computer
curl -d "language=en-US" -d "text=a simple test" http://localhost:8081/v2/check
A reply in JSON means you are connected. Then open the add-on's settings with the cog icon, go to Experimental settings and pick Local server. That is why the service starts with --allow-origin: the docs say the add-on needs it. Given with no value, it allows any website (the server's help text), so remove it if you only use scripts.
Safari, the docs note, seems to require HTTPS: you would put a reverse proxy in front and enter its address, ending in /v2, as Other server.
Sharing it with your team
The basic checker does not ask callers to sign in. Started with --public, it warns that anyone can use the API without restrictions; that warning is in its source code (HTTPServer.java). To share it, keep it local-only and put a web server such as nginx on the same machine, with a password (HTTP basic auth works) and an HTTPS certificate; the official page recommends Apache or nginx for the TLS part.
Open the firewall only for what you serve. Set IPV6=yes in /etc/default/ufw before adding rules, then allow OpenSSH and 80,443/tcp and switch it on with sudo ufw --force enable. The proxy runs directly on the host, so without the 80/443 rule it stays blocked on both IPv4 and IPv6. Keep the password file readable by root and the web server only. If you use the requestLimit setting, add trustXForwardForHeader=true so each person is counted, not the proxy.
Already sharing documents with the same people? Outline as a team wiki can live on this server too.
Better suggestions with n-gram data
Download the file for your language from languagetool.org/download/ngram-data/ (for English, ngrams-en-20150817.zip) into a folder such as /srv/languagetool/ngrams, and unzip it there. You get an en folder holding 1grams, 2grams and 3grams.
Then add one line to server.properties, languageModel=/srv/languagetool/ngrams, naming the folder that holds en, not en itself, and restart with sudo systemctl restart languagetool. The docs include an English test sentence that writes breaks where brakes is meant; after the restart, it should be flagged.
Keeping it current
There are no numbered releases to wait for any more: the change log says 6.6 was the last ZIP release and the project moved to daily snapshots. To update, rerun the download and unzip lines from the setup block on a new day, which unpacks into a fresh build- folder and moves the app link, then restart the service. The older folder stays put if you need to switch back.
- Licence: LanguageTool's core code is LGPL-2.1-or-later; a few bundled dictionaries and data sets carry their own licences, listed in the README.md inside the download.
- Docker: the project publishes no image of its own. Its README links three community-made ones; if you use one, keep its published port bound to 127.0.0.1. Left without an address, the port goes out on 0.0.0.0 and [::]. IPv4 visitors then get past ufw; IPv6 visitors get through only if you have switched on Docker's IPv6 networking. From Engine 28 onward, Docker keeps a 127.0.0.1 binding reachable from this machine alone.
- Keep a copy of
server.propertiesand the service file somewhere other than the server.
Questions people ask
- Do I need the n-gram data?
- No, the checker works without it. The data adds rules for commonly confused words, such as their and there, in English, German, French and Spanish. For English it costs about 9 GB of download and roughly 15 GB of SSD space once unpacked, by our count.
- Can I change port 8081?
- Yes. 8081 is the default named in the server's help output, and
--portsets another one in the service line. If you use the SSH tunnel, change both numbers in the ssh command to match. - Is LanguageTool free to run on my own server?
- The core is open source under the LGPL, version 2.1 or later, and the snapshot download costs nothing. What you pay for is the server it runs on. The AI-based rules are not part of the download.
- Can I use a Docker container instead of the ZIP?
- You can, but none of the images is official: the project's README lists three community-made projects. The ZIP with Java is the route the official docs describe. With any container, keep its published port on 127.0.0.1.
- Will the add-on work in Safari?
- According to the docs, Safari seems to require HTTPS. You would need a reverse proxy with a certificate in front of the server and enter that address, ending in /v2, as Other server in the add-on.