On current Fedora the text console you reach with Ctrl+Alt+F3 is no longer drawn by the kernel. It is kmscon, a userspace terminal that draws through the kernel’s DRM display interface and runs the login on a pseudo-terminal, which is why setfont still exits cleanly and changes nothing you can see.
The confusion comes from the tools. Fedora still ships kbd, /etc/vconsole.conf still says KEYMAP=us, and nothing warns you that kmscon reads a different setting. This guide follows one keystroke and one font request through the new stack, shows which setting actually wins, and gives you the exact way back to getty and fbcon on one VT or on all of them. Everything below was run on a Fedora 45 Cloud VM with kmscon 10.0.4 and a virtio GPU in October 2026.
kmscon owns every VT by default
Fedora does not replace getty by editing it. It swaps the unit that systemd-logind starts when you switch to an unused VT. A vendor preset enables [email protected], and that unit carries [email protected] in its install section, so enabling it points the autovt@ alias at kmscon instead of getty. Follow one keypress, Ctrl+Alt+F3, through the chain in order.
- logind sees the switch to tty3
- it starts
[email protected] - the alias resolves to
[email protected] - kmscon takes the DRM device and opens a pty
/bin/login -pruns on that pty
You can see the first link in the chain in /etc, because that is where systemctl enable writes aliases. List it.
ls -l /etc/systemd/system/[email protected]
On a fresh install it points at kmscon, and /usr/lib/systemd/system ships no [email protected] of its own:
lrwxrwxrwx. 1 root root 41 Sep 5 18:04 /etc/systemd/system/[email protected] -> /usr/lib/systemd/system/[email protected]
The preset that creates it lives in /usr/lib/systemd/system-preset/90-default.preset, and it also disables getty explicitly, because systemd’s own 90-systemd.preset would otherwise enable it:
grep -rn "getty@\|kmsconvt@" /usr/lib/systemd/system-preset/
Both presets show up. Fedora’s file wins because 90-default sorts before 90-systemd and the first matching rule counts:
/usr/lib/systemd/system-preset/90-default.preset:27:# Enable [email protected] as implementation for [email protected].
/usr/lib/systemd/system-preset/90-default.preset:28:# Explicitly disable [email protected] which is enabled by systemd.
/usr/lib/systemd/system-preset/90-default.preset:30:enable [email protected]
/usr/lib/systemd/system-preset/90-default.preset:31:disable [email protected]
/usr/lib/systemd/system-preset/90-systemd.preset:20:enable [email protected]
So what happens if kmscon cannot start on your hardware? The unit answers that itself, and the serial console sits outside the chain entirely.
OnFailure=getty@%i.servicestarts the old getty on that VT if kmscon failsConditionPathExists=/dev/tty0skips kmscon on machines with no VTs[email protected]stays active, so a hypervisor serial terminal is unchanged
That fallback is why you rarely end up with no login prompt at all. A kmscon that fails to start gives you a plain getty on the same VT, and a VM you manage through its serial console keeps the same serial getty it always had. The fallback only covers a crash, though. A kmscon that runs but draws nothing on your GPU triggers nothing, so keep SSH or the serial console as your way in on unusual hardware. The preset ships in redhat-systemd-presets-common rather than in an edition package, and Workstation and COSMIC installs tested for this series showed the same kmsconvt@tty1 enabled, getty@tty1 disabled split, so expect this chain on a machine set up with the Fedora installers too.
Your shell sits on a pseudo-terminal
kmscon is a terminal emulator, not a console driver. It maps keys with xkbcommon, draws glyphs with FreeType, and hands your login a pty, much like a terminal window does on the desktop. Its own journal lines name both libraries, so you can confirm that on your machine. The issue banner already gives it away, since the login prompt says (pts/0) where getty would print (tty1).

Logged in on tty1, the shell confirms it. Run this from the kmscon session itself, not over SSH, to see what the console login is attached to:
tty; echo $TERM; ps -o pid,tty,comm -p $$ $PPID
The terminal is /dev/pts/0, TERM is kmscon, and login has no controlling tty at all:
/dev/pts/0
kmscon
PID TT COMMAND
1693 ? login
1727 pts/0 bash
Anything you wrote that tests whether tty prints /dev/ttyN to decide it runs on the console now takes the wrong branch. Look for these in your own files.
- shell profile lines that compare
$(tty)with/dev/tty1 - scripts that switch behaviour when
TERMislinux - monitoring checks that count logins on
tty*lines inwho
logind still records your session on seat0, so loginctl list-sessions is the reliable way to tell a console login from an SSH one. On the test VM the kmscon login showed up there as a seat0 session on pts/0, while the SSH session had no seat. Fix the check rather than the console, because a script that keys on the seat keeps working whether the VT runs kmscon or getty.
setfont and loadkeys miss the target
The old tools were written for the kernel’s virtual terminal, and kmscon replaces what you see with its own font and its own keymap. Neither tool knows that, so one reports success, the other errors out, and the screen ignores both. Run both inside a kmscon session and record their exit codes:
sudo setfont lat9w-16; echo setfont_rc=$?
sudo loadkeys de; echo loadkeys_rc=$?
setfont reports success and loadkeys exits with an error after a run of keymap warnings, trimmed here to the first and last of them:
setfont_rc=0
unknown keysym 'trademark'
lk_add_key called with bad keycode -1
loadkeys_rc=1
Typing yz afterwards still printed yz, so the layout stayed US, and the font on screen did not change. Nothing else changes either: a getty VT brought up on tty5 right afterwards also still typed with the US layout. Both settings now belong to kmscon, which has its own configuration file and listens to a different localectl field, so the fix for either one is to stop using kbd on a kmscon VT.
Fonts come from kmscon.conf
kmscon reads /etc/kmscon/kmscon.conf, and Fedora does not create one. The package ships a commented template at /etc/kmscon/kmscon.conf.example with the common options, and man kmscon.conf lists the rest. With no file, kmscon picks FreeType, the monospace fontconfig match and a size based on the screen. On a 1280×800 virtio display it chose Adwaita Mono, logged a first pass at 16 pixels and settled on 20, a 10×20 cell that fills the screen with 128 columns and 40 rows. The journal records the choice every time kmscon starts:
sudo journalctl -u kmsconvt@tty1 -b --no-pager | grep font_freetype
Changing it takes three things, in this order.
- a monospace font installed system-wide, under
/usr/share/fonts - its exact family name from
fc-list : family - a restart of kmscon on the VT
kmscon runs as root and asks fontconfig, so a font in your home directory is invisible to it. Font names also need the FreeType backend, which lives in the kmscon-freetype subpackage that kmscon only recommends, so check it’s there with rpm -q kmscon-freetype on a minimal install. Then install Cascadia Mono to see the change on your own console:
sudo dnf install cascadia-mono-fonts
Create the configuration file with nano, Fedora’s default editor:
sudo nano /etc/kmscon/kmscon.conf
Add the font name exactly as fontconfig spells it, and a height in pixels:
font-name=Cascadia Mono
font-size=20
Restart kmscon on the VT you are testing. Restarting the unit ends any login on that VT, so save your work there first:
sudo systemctl restart kmsconvt@tty1
The same journal query now ends with the new face and the cell size it produced, after the lines from earlier starts:
Oct 21 21:55:10 client01 kmscon[1011]: font_freetype: Using [Cascadia Mono Regular] / [Cascadia Mono Bold] size 20 -> cell size 10x20
Other VTs pick the file up the next time their kmscon starts, which is the next switch to an unused VT or the next boot, so you do not have to restart every VT by hand. Leave font-name out if you only want bigger text, because font-size=24 alone kept Adwaita Mono and gave a 12×24 cell. A larger cell also means fewer columns, so pick the size against your monitor rather than by eye from a laptop panel.
Installing a font can change your console with no configuration at all. With Cascadia Mono installed and kmscon.conf deleted, kmscon still started in Cascadia Mono, because the default font-name is the generic monospace and fontconfig now resolved that name to the new font. Ask fontconfig what kmscon will get:
fc-match monospace
On the test VM the answer had moved from Adwaita Mono to the font that was just installed:
CascadiaMono-Regular.otf: "Cascadia Mono" "Regular"
The old setting has no say in this either. Adding FONT=eurlatgr to /etc/vconsole.conf and restarting both systemd-vconsole-setup.service and kmscon left the journal reporting Cascadia Mono, so a FONT line you carried over from an older install does nothing on a kmscon VT.
The keymap is the X11 layout
This is the easiest setting to get wrong, because localectl status shows two keymaps and kmscon only reads one of them. localectl set-keymap normally writes both, so they agree and the difference never shows. To find out which one kmscon follows, the test VM had the two fields split with localectl set-keymap --no-convert and set-x11-keymap --no-convert for the first two rows, and set together with plain set-keymap for the other two. kmscon was restarted after each change, and the same four keys (q w y z on a US keyboard) were typed at its login prompt each time:
| VC Keymap | X11 Layout | kmscon.conf | Typed | Layout kmscon used |
|---|---|---|---|---|
| us | de | no xkb line | qwzy | German |
| de | us | no xkb line | qwyz | US |
| de | de | no xkb line | qwzy | German |
| us | us | xkb-layout=fr | azyw | French |
kmscon ignores the VC keymap completely. It applies the layout settings in this order, from strongest to weakest.
xkb-layoutinkmscon.conf- the X11 layout from systemd-localed
- the VC keymap, which kmscon never reads
For you that means one rule. Set the layout with localectl, and only pin it in kmscon.conf if your console must differ from your desktop. localectl writes both fields at once unless you pass --no-convert, so the everyday command keeps the desktop and the console in agreement. kmscon reads only the X11 layout, so localectl set-x11-keymap de is the direct way to change it.
The localectl path is also live. With no xkb-layout in the file, this changed the layout in an already logged-in kmscon session, without a restart:
sudo localectl set-keymap de
The next line typed in the session came out with German keys. The US hyphen key produced ß, y and z swapped, and the colon came out as Ö.

Once xkb-layout=fr was in the file, the same live localectl set-keymap de changed nothing and the login prompt stayed French. Pinning goes further than the layout line. Any xkb- option in the file switches off live tracking: with only xkb-options=ctrl:nocaps set, a live switch to de left the console typing US. So a laptop that moves between keyboards is better served by localectl alone, with no xkb- lines in kmscon.conf.
One place still uses the old setting. Early boot, including the LUKS passphrase prompt, runs before kmscon starts and reads the copy of /etc/vconsole.conf that dracut baked into the initramfs. localectl does not rebuild that copy: after localectl set-keymap de the initramfs on the test VM still said KEYMAP=us, and only a rebuild changed it:
sudo dracut -f
Plain dracut -f rebuilds the image for the running kernel only. If a newer kernel is installed but not yet booted, dracut(8) documents sudo dracut -f --regenerate-all for every installed kernel. Check the result before you reboot, because the next prompt you type a passphrase into will use it:
sudo lsinitrd -f etc/vconsole.conf
On the test VM the rebuilt image carried the new layout:
# Written by systemd-localed(8) or systemd-firstboot(1), read by systemd-localed
# and systemd-vconsole-setup(8). Use localectl(1) to update this file.
KEYMAP=de
XKBLAYOUT=de
XKBMODEL=pc105
XKBOPTIONS=terminate:ctrl_alt_bksp
If you skip the rebuild, the next kernel update rebuilds the initramfs anyway, and the layout at the passphrase prompt changes then without warning. That matters most if you unlock an encrypted disk by typing a passphrase, so test it on a reboot you’re watching.
Scrollback and blanking behave differently
kmscon brings back console scrollback, which the kernel console lost years ago. It keeps its own buffer, so these keys work on any kmscon VT.
- Shift+PageUp and Shift+PageDown scroll by a screen
- Shift+Up and Shift+Down scroll by a line
sb-sizesets the buffer length, 1,000 lines by default (the example file shows 10000, which is not the default)
After seq 1 300, two presses of Shift+PageUp on the 40-row test screen showed lines 182 to 221, so each press moved exactly one screen.
The other change catches you if you leave a console open on a server monitor. kmscon turns the display off after 600 seconds without keyboard or mouse input, the dpms-timeout default in kmscon.conf(5). On the test VM the console was still showing output at 9 minutes, and at 11 minutes QEMU reported that the display output was no longer active. Keyboard or mouse input turns it back on, according to the same man page.
For a rack console or a wall display that must stay lit, set the timeout to zero in /etc/kmscon/kmscon.conf, next to any font lines you already have:
dpms-timeout=0
Restart kmscon on the VT with sudo systemctl restart kmsconvt@tty1, which again ends any login there. With that line in place the test VM still showed its login prompt after 11 and a half idle minutes, so the zero really does switch blanking off rather than stretching it.
Go back to getty and fbcon
Do you need to give up kmscon everywhere? Usually not, and you have three levels to choose from.
- one getty VT for troubleshooting, the rest on kmscon
- getty on every VT
- getty on every VT, protected from future preset runs
Keeping one getty VT is the gentler option, because you keep a plain kernel console for troubleshooting while the rest stay on kmscon. Mask kmscon for that VT and enable getty on it:
sudo systemctl mask [email protected]
sudo systemctl enable --now [email protected]
This is the order Fedora Magazine’s kmscon introduction uses. You mask first, so kmscon cannot claim the VT, and then enable getty on it. systemd writes the mask and both getty links.
Created symlink '/etc/systemd/system/[email protected]' → '/dev/null'.
Created symlink '/etc/systemd/system/[email protected]' → '/usr/lib/systemd/system/[email protected]'.
Created symlink '/etc/systemd/system/getty.target.wants/[email protected]' → '/usr/lib/systemd/system/[email protected]'.
Ctrl+Alt+F5 now lands on the classic bitmap font with (tty5) in the banner. In that session tty printed /dev/tty5, TERM was linux, and setfont eurlatgr visibly changed the font, because there is no kmscon in the way. That makes tty5 a useful control when you debug a console problem, since you can compare the same command on a kmscon VT and a getty VT side by side.

To leave kmscon entirely, move the autovt@ alias back to getty for every VT:
sudo systemctl disable [email protected]
sudo systemctl enable [email protected]
The first command removes kmscon’s alias and its tty1 link, and the second points both at getty:
Removed '/etc/systemd/system/[email protected]'.
Removed '/etc/systemd/system/getty.target.wants/[email protected]'.
Created symlink '/etc/systemd/system/[email protected]' → '/usr/lib/systemd/system/[email protected]'.
Created symlink '/etc/systemd/system/getty.target.wants/[email protected]' → '/usr/lib/systemd/system/[email protected]'.
Reboot, switch to tty3 once so logind starts something there, and check which units are running. On the test VM both VTs ran getty and no kmscon process was left:

That change is only as durable as the next preset run, though. systemctl preset reapplies Fedora’s 90-default.preset, and running it for these two units on the test VM flipped every VT straight back to kmscon. A local preset file stops that. systemd reads preset files from /etc and /usr/lib in filename order and the first matching rule wins, so a file named 10- beats Fedora’s 90-default.preset. Create the directory, which does not exist on a fresh install:
sudo mkdir -p /etc/systemd/system-preset
Open a new preset file:
sudo nano /etc/systemd/system-preset/10-console-getty.preset
Add the two rules that reverse Fedora’s:
disable [email protected]
enable [email protected]
Apply the presets for both units, which now lands on getty instead of undoing it:
sudo systemctl preset [email protected] [email protected]
Confirm the pin took before you reboot:
systemctl is-enabled [email protected] [email protected]
getty should read enabled and kmscon disabled, in that order:
enabled
disabled
To return to Fedora’s default later, delete 10-console-getty.preset and run the same systemctl preset line. Undoing the single-VT method takes more than a preset, because presets never touch an instance mask. On the test VM a preset run removed the tty5 getty links but left [email protected] masked, so nothing would have started on that VT. Unmask it and drop the getty instance first:
sudo systemctl unmask [email protected]
sudo systemctl disable --now [email protected]
sudo systemctl preset [email protected] [email protected]
The preset line at the end matters too, because systemctl disable [email protected] leaves its [email protected] link behind and only the preset run removed it on the test VM.
Which setting wins
Every console setting now has an old home and a new one, and only one of them is read. Use this as the lookup when something on the console does not change.
| What you want | Read by kmscon | Ignored by kmscon | Takes effect |
|---|---|---|---|
| Keyboard layout | X11 layout from localectl, or xkb-layout in kmscon.conf (wins) | KEYMAP in vconsole.conf, loadkeys | Live for localectl (no xkb- lines in kmscon.conf), restart for kmscon.conf |
| Font | font-name, font-size in kmscon.conf | FONT in vconsole.conf, setfont | Next kmscon start on that VT |
| Console program per VT | autovt@ alias, masks on kmsconvt@ttyN | Not a kmscon setting | Next start of that VT |
| Which VTs default to kmscon | Preset files, first match in filename order | Not a kmscon setting | Next systemctl preset |
| Early boot and LUKS prompt | Not kmscon, the initramfs copy of vconsole.conf | kmscon.conf | After dracut -f or the next kernel update |
kmscon also holds the DRM device exclusively while it runs. A program that needs the GPU, such as startx or a DRM video player, has to be started through kmscon-launch-gui from a kmscon VT, according to the Fedora Magazine article and the kmscon Change page. The same exclusivity is the root of the login loop in our COSMIC on Fedora guide, where a greeter unit with a misspelled kmscon name starts while kmscon still owns tty1. If you are new to this release, our rundown of what’s new in Fedora covers the rest of the changes that arrived alongside kmscon, our post-install checklist is the place to set the keyboard layout on a new machine, and enabling SSH on Fedora gives you a way in if a console experiment leaves you without a login prompt.