Font HOWTO: install, choose and tune fonts on Linux
On Linux, one library, fontconfig, decides which font every desktop program uses. To add a font, put the file in ~/.local/share/fonts (or install a package) and run fc-cache. To change which font is used, set your choice in the desktop settings or in a small fontconfig file. This page covers both, plus the usual fixes for missing emoji and boxes in place of Chinese, Japanese or Korean text.
The classic Font HOWTO dealt with X font paths, the xfs font server and converting TrueType to Type 1 for printing. None of that is needed any more. Programs now draw fonts themselves using fontconfig, FreeType (which draws the letters) and HarfBuzz (which places them correctly for each script).
Where fonts live
| Directory | Who uses it |
|---|---|
/usr/share/fonts | Fonts installed by packages. Do not put your own files here. |
/usr/local/share/fonts | Fonts an administrator adds by hand, for all users |
~/.local/share/fonts | Your own fonts (fontconfig's per-user directory) |
~/.fonts | Old per-user location. Still read, but fontconfig marks it for removal. Move fonts to ~/.local/share/fonts. |
OpenType (.otf) and TrueType (.ttf, .ttc) files work everywhere, including variable fonts, where one file holds every weight. Web fonts (.woff2) are meant for browsers. For desktop use, get the .ttf or .otf version.
Install fonts from packages
Packages are the best choice: they update, and they include licenses. Useful sets:
# Debian, Ubuntu
sudo apt install fonts-noto-core fonts-noto-cjk fonts-noto-color-emoji fonts-liberation2
# Fedora
sudo dnf install google-noto-sans-fonts google-noto-sans-cjk-fonts \
google-noto-color-emoji-fonts liberation-fonts-all
# Arch
sudo pacman -S noto-fonts noto-fonts-cjk noto-fonts-emoji ttf-liberation
Noto covers almost every script, and Noto Color Emoji provides emoji. Liberation fonts have the same letter widths as Arial, Times New Roman and Courier New, so documents from Windows keep their layout. Microsoft's own core fonts are in Debian and Ubuntu as ttf-mscorefonts-installer (Debian contrib, Ubuntu multiverse). It downloads the fonts from the Internet and asks you to accept Microsoft's license.
Install a font by hand
Say you downloaded a font family as a ZIP file:
mkdir -p ~/.local/share/fonts/inter
unzip ~/Downloads/Inter.zip -d /tmp/inter
cp /tmp/inter/*.ttf ~/.local/share/fonts/inter/
fc-cache -f ~/.local/share/fonts
fc-list | grep -i inter
The last command should list the new files. Restart programs that were already open, since most only read the font list at start-up. For every user on the machine, copy the files to /usr/local/share/fonts/ instead (with sudo), make them readable (sudo chmod 644), and run sudo fc-cache -f.
To remove a font, delete its files and run fc-cache -f again. Check the license of any font you download. Many good ones are free under the SIL Open Font License.
See what fontconfig knows
fc-list : family # every font family installed
fc-list : family style file # with styles and file paths
fc-list :lang=ja family # fonts that can show Japanese
fc-match sans-serif # the font used for "sans-serif"
fc-match -s monospace | head # fallback order for monospace
fc-match Helvetica # what you get when a page asks for Helvetica
Typical output:
$ fc-match sans-serif
NotoSans-Regular.ttf: "Noto Sans" "Regular"
Programs ask fontconfig for a generic name (sans-serif, serif, monospace, emoji) or a specific family. fontconfig answers with the best installed match. If the font lacks a character, the program moves down the fallback list from fc-match -s until a font has it.
Choose your fonts
For interface fonts, start with your desktop settings. On GNOME, use GNOME Tweaks or the font options in Settings, depending on the version. KDE Plasma has them in System Settings, Text & Fonts. Those settings apply to that desktop's menus and windows.
To change the generic families for every program, create ~/.config/fontconfig/fonts.conf:
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
<!-- Preferred fonts for the generic families -->
<alias>
<family>sans-serif</family>
<prefer>
<family>Noto Sans</family>
<family>Noto Sans CJK JP</family>
<family>Noto Color Emoji</family>
</prefer>
</alias>
<alias>
<family>serif</family>
<prefer><family>Noto Serif</family></prefer>
</alias>
<alias>
<family>monospace</family>
<prefer><family>DejaVu Sans Mono</family></prefer>
</alias>
</fontconfig>
Use the family names exactly as fc-list : family prints them. Run fc-match sans-serif to check the result. The file takes effect for programs started afterward. The old location, ~/.fonts.conf, is deprecated.
Rendering: sharp or smooth
Three settings control how text looks on screen:
- Antialiasing smooths edges. Leave it on.
- Hinting fits letters to the pixel grid. Slight keeps letter shapes true and is the usual default. Full looks sharper on low-resolution screens but distorts shapes.
- Subpixel rendering (
rgba) uses the red, green and blue parts of LCD pixels for extra sharpness. It can cause colored fringes, and it does not suit rotated screens or OLED panels. On high-resolution screens it matters little.
Set these in GNOME Tweaks or KDE's font settings where possible. To force them for all programs, add this inside <fontconfig> in the same file:
<match target="font">
<edit name="antialias" mode="assign"><bool>true</bool></edit>
<edit name="hinting" mode="assign"><bool>true</bool></edit>
<edit name="hintstyle" mode="assign"><const>hintslight</const></edit>
<edit name="rgba" mode="assign"><const>none</const></edit>
</match>
For subpixel rendering, replace none with rgb (the most common panel layout). Rendering edits always use target="font". Check the result with fc-match -v sans-serif | grep -E 'hintstyle|rgba|antialias'.
Emoji and CJK text
Empty boxes or "tofu" in place of characters mean no installed font has them. The fixes:
- Emoji show as boxes or black-and-white: install Noto Color Emoji (package names above). Check with
fc-match emoji, which should printNoto Color Emoji. - Chinese, Japanese or Korean show as boxes: install Noto CJK (
fonts-noto-cjk,google-noto-sans-cjk-fontsornoto-fonts-cjk). Check withfc-list :lang=zh-cn family. - Japanese text uses Chinese-style characters (or the reverse): the same code point is drawn differently in each language. Put the right regional font first in your
sans-seriflist (Noto Sans CJK JP,SC,TC,HKorKR), or set your locale to that language. - A script such as Devanagari or Arabic looks broken: install the matching Noto font. HarfBuzz handles the shaping.
Troubleshooting
- New font not listed: run
fc-cache -f -vand check that the directory appears in the output. Check file permissions for system-wide fonts. - Settings ignored: run
fc-conflistto see which configuration files are loaded. A typo in your XML makes fontconfig print an error when you run anyfc-command. - Why was this font picked?
FC_DEBUG=4 fc-match sans-serifprints every edit applied during matching. - Corrupt cache after a crash:
fc-cache -rerases and rebuilds your caches.
The text console uses its own bitmap fonts, not fontconfig. See Framebuffer HOWTO. The classic Font HOWTO is kept by the Linux Documentation Project at tldp.org.
Sources
- fonts.conf: font configuration files (fontconfig user documentation), freedesktop.org
- fc-cache(1), fc-list(1), fc-match(1) and fc-conflist(1), Debian
- fonts-noto-color-emoji, fonts-noto-cjk and ttf-mscorefonts-installer, Debian packages
- google-noto-fonts, google-noto-sans-cjk-fonts and google-noto-color-emoji-fonts and liberation-fonts, Fedora Packages
- noto-fonts, noto-fonts-cjk and noto-fonts-emoji, Arch Linux packages