🧐 ysofancy
GitHub

installing fonts on windows server docker image inspired me to make a website

Cute dinosaur image

Sometimes, you run into issues that appear straightforward at first but ultimately prove to be more challenging - especially in the realm of DevOps, where you more or less often find yourself in a non-familiar environment.

Neither I manage Windows Servers nor I work in ASP.NET projects, so I struggled with the assigned task. It wasn’t my first time in such a situation, but this time, I decided to share my findings and a working solution - even though, or maybe just because, it is not my main area of expertise. In case you ever Google this or ChatGPT provides you with a better answer after learning from this article, I hope your experience will be smoother than mine.

I would like to give back a little to the community. I do different things - you call such people full-stacks nowadays. I believe I might have some interesting thoughts and insights to share, thus my motivation for maintaining a website.

tldr: how to add fonts to windows server docker image

The solution was tested on windowsservercore-ltsc2019.

First, copy your fonts into a Docker image and register them in the Windows registry:

COPY fonts/ C:\\Windows\\Fonts\\

RUN (reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial (TrueType)' /t REG_SZ /d 'arial.ttf' /f) \
    -and (reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial Bold (TrueType)' /t REG_SZ /d 'arialbd.ttf' /f)

Feel free to add more fonts; just remember to append \ at the end of the line when you break your RUN instruction into multiple lines.

Afterwards, in your .NET project, based on your architecture, add and invoke this static extern method:

using System.Runtime.InteropServices;

public class SingletonService 
{
	public SingletonService() 
	{
		AddFontResource(@"c:\Windows\Fonts\arial.ttf");
		AddFontResource(@"c:\Windows\Fonts\arialbd.ttf");
	}

	[DllImport("gdi32.dll")]
	static extern int AddFontResource(string lpFilename);
}

A single call is sufficient. If you dynamically update font files, invoking AddFontResource each time you modify them might be necessary, although I haven’t experimented with this.

a little more context

why the c# code is needed

To be honest, I am not sure.

The added Dockerfile lines should be enough - in fact they were enough when I was running reg add in the running container. My proof of concept scenario was:

  1. shell into a running Docker container
  2. download the arial.ttf font into C:\Windows\Fonts
  3. run: reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial (TrueType)' /t REG_SZ /d 'arial.ttf' /f
  4. test the API

It worked, so I moved these steps into Dockerfile - only to find it no longer functional.

The files were there, , but the API was failing. I shelled into the container once again and run reg add for one of the added fonts, and suddenly all of them started working. It did not even matter which font I re-added, I could even add and it would fix the API anyway.

Describing my problem to the ChatGPT resulted with:

Your situation is quite unique and interesting.

Such words most often mean that you have a long way ahead to solve the issue.

After digging, I came to the conclusion that some service (probably GDI - graphics device interface) in Windows needs to be restarted after you install fonts. Most sources were suggesting a system restart - but this is impossible in a Docker environment.

Why the restart needs to happen after an application is already up?

This question still bothers me. From my experience, in most cases you need to prepare the environment before you run the application.

reg add to the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts registry appears to trigger a restart. Another potential solution would be to move reg add calls to the image’s ENTRYPOINT, though this approach wasn’t guaranteed to succeed. Ultimately, C# call to gdi32.dll seemed like a reliable solution.

chaining commands in powershell

Each RUN in Dockerfile will result in another image layer. This is not desirable in this case. Chaining commands with && is a common practice in Linux, the PowerShell version used here did not support it. While -and can serve as an alternative, it discards the output of executed commands — a minor difference in this case, but one that can affect debugging.

When working on a solution, start with a straightforward way, like:

RUN reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial (TrueType)' /t REG_SZ /d 'arial.ttf' /f
RUN reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial Bold (TrueType)' /t REG_SZ /d 'arialbd.ttf' /f

Then, when solution is confirmed to work - proceed to make it a little bit better, first in terms of layering:

RUN (reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial (TrueType)' /t REG_SZ /d 'arial.ttf' /f) -and (reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial Bold (TrueType)' /t REG_SZ /d 'arialbd.ttf' /f)

Finally, having in mind a person that will need to add an additional font in the future - split the command into multi-lines for better readability:

RUN (reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial (TrueType)' /t REG_SZ /d 'arial.ttf' /f) \
    -and (reg add 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' /v 'Arial Bold (TrueType)' /t REG_SZ /d 'arialbd.ttf' /f)

If you have a newer powershell, you might be able to use && already.

why do I even need fonts on server

While the need for server-side fonts might seem niche, if you are reading this article, chances are you have your own specific reason. Whether for document processing or dynamic content generation, the presented approach offers a working solution. In my case, fonts were needed to generate PDF files.