SSHD(8)

πŸ“¦
version 10.2p1 Β· 2 versions
, in fedora 44

πŸ’– SSHD(8) β€” the manual page, but make it bestie πŸ’–

System Manager's Manual Β· SSHD(8)

okay so. sit down. grab a snack. we're talking about sshd today and honestly? she's the moment. the whole server-side queen. let's get into it πŸ’…


✨ NAME ✨

sshd β€” the OpenSSH daemon. that's it, that's her. the daemon 🌈


πŸŽ€ SYNOPSIS πŸŽ€

sshd [-46DdeGiqTtV] [-C connection_spec] [-c host_certificate_file]
     [-E log_file] [-f config_file] [-g login_grace_time]
     [-h host_key_file] [-o option] [-p port] [-u len]

like, look at all those flags. she's got range. πŸ‘‘


πŸ’œ DESCRIPTION πŸ’œ

sshd (short for OpenSSH Daemon) is the daemon program for ssh(1). bestie, what she does is genuinely iconic: she provides secure encrypted communications between two untrusted hosts over an insecure network. yes, over the insecure network. she does not care. she's built different. πŸ”₯

sshd listens for connections from clients. she's normally started at boot from /etc/rc. and here's the cute part: she forks a new daemon for each incoming connection. every single one gets her full attention, no cap. those forked daemons are the ones doing the actual work β€” handling key exchange, encryption, authentication, command execution, and data exchange. multitasking queen fr fr πŸ¦‹

you can configure sshd two ways: command-line options, or a configuration file (by default sshd_config(5)). and command-line options override values specified in the configuration file, so keep that hierarchy in mind, iykyk. also β€” she rereads her configuration file whenever she gets a hangup signal, SIGHUP, by executing herself with the name and options she was started with, like /usr/sbin/sshd. self-care is re-reading your own config. πŸ’–

the options are as follows, and yes we're doing all of them:

  • -4 β€” forces sshd to use IPv4 addresses only. v4 girls, stand up 🫢
  • -6 β€” forces sshd to use IPv6 addresses only. v6 girlies, this one's for you ✨
  • -C connection_spec β€” specifies the connection parameters to use for the -T extended test mode. if you provide this, any Match directives in the configuration file that would apply get applied before the configuration is written to standard output. the connection parameters come as keyword=value pairs and can be supplied in any order β€” either with multiple -C options or as a comma-separated list. the keywords are addr, user, host, laddr, lport, and rdomain, and they correspond to source address, user, resolved source host name, local address, local port number and routing domain respectively. additionally the invalid-user flag (which does not take a value argument) may be specified to simulate a connection from an unrecognised username. sneaky but valid πŸ’€
  • -c host_certificate_file β€” specifies a path to a certificate file to identify sshd during key exchange. the certificate file must match a host key file specified using the -h option or the HostKey configuration directive. they have to be a matching set, like besties with coordinated outfits πŸŽ€
  • -D β€” when this option is specified, sshd will not detach and does not become a daemon. this allows easy monitoring of sshd. she stays right there in the foreground where you can see her. main character energy, refuses to leave the group chat πŸ’…
  • -d β€” debug mode. the server sends verbose debug output to standard error, and does not put itself in the background. the server also will not fork(2) and will only process one connection. this option is only intended for debugging for the server. multiple -d options increase the debugging level. maximum is 3. don't be greedy, three's the limit πŸ™ˆ
  • -E log_file β€” append debug logs to log_file instead of the system log.
  • -e β€” write debug logs to standard error instead of the system log.
  • -f config_file β€” specifies the name of the configuration file. the default is /etc/gsissh/sshd_config. and ngl, sshd refuses to start if there is no configuration file. no config, no service. she has standards. 😭
  • -G β€” parse and print configuration file. check the validity of the configuration file, output the effective configuration to stdout and then exit. optionally, Match rules may be applied by specifying the connection parameters using one or more -C options. basically a vibe check for your config ⭐
  • -g login_grace_time β€” gives the grace time for clients to authenticate themselves (default 120 seconds). if the client fails to authenticate the user within this many seconds, the server disconnects and exits. a value of zero indicates no limit. zero means no limit, she's patient when you ask her to be πŸ•
  • -h host_key_file β€” specifies a file from which a host key is read. this option must be given if sshd is not run as root (as the normal host key files are normally not readable by anyone but root). the default is /etc/gsissh/ssh_host_ecdsa_key, /etc/gsissh/ssh_host_ed25519_key and /etc/gsissh/ssh_host_rsa_key. it is possible to have multiple host key files for the different host key algorithms. collect them all like pokΓ©mon, no cap πŸ”‘
  • -i β€” specifies that sshd is being run from inetd(8). old school, but make it fashion ✨
  • -o option β€” can be used to give options in the format used in the configuration file. this is useful for specifying options for which there is no separate command-line flag. for full details of the options, and their values, see sshd_config(5). the catch-all, the "we got you" option 🫢
  • -p port β€” specifies the port on which the server listens for connections (default 22). multiple port options are permitted. ports specified in the configuration file with the Port option are ignored when a command-line port is specified. ports specified using the ListenAddress option override command-line ports. yes, the precedence here is a whole drama, keep up πŸ’€
  • -q β€” quiet mode. nothing is sent to the system log. normally the beginning, authentication, and termination of each connection is logged. sometimes she just doesn't want to post about it 🀫
  • -T β€” extended test mode. check the validity of the configuration file, output the effective configuration to stdout and then exit. optionally, Match rules may be applied by specifying the connection parameters using one or more -C options. this is similar to the -G flag, but it includes the additional testing performed by the -t flag. it's -G but with extra steps, and the extra steps are the point 🌸
  • -t β€” test mode. only check the validity of the configuration file and sanity of the keys. this is useful for updating sshd reliably as configuration options may change. please run this before you restart things, bestie, i am begging πŸ™
  • -u len β€” this option is used to specify the size of the field in the utmp structure that holds the remote host name. if the resolved host name is longer than len, the dotted decimal value will be used instead. this allows hosts with very long host names that overflow this field to still be uniquely identified. specifying -u0 indicates that only dotted decimal addresses should be put into the utmp file. -u0 may also be used to prevent sshd from making DNS requests unless the authentication mechanism or configuration requires it. authentication mechanisms that may require DNS include HostbasedAuthentication and using a from="pattern-list" option in a key file. configuration options that require DNS include using a USER@HOST pattern in AllowUsers or DenyUsers. okay that one was long but every word mattered πŸ’…
  • -V β€” display the version number and exit. the little "hi, who am i" move πŸ‘‘

πŸ” AUTHENTICATION πŸ”

the OpenSSH SSH daemon supports SSH protocol 2 only. one protocol. the good one. periodt.

every host has a host-specific key, used to identify the host. whenever a client connects, the daemon responds with its public host key. the client compares the host key against its own database to verify that it has not changed β€” like checking if your bestie changed their whole personality overnight, and if they did, red flag, alert, do not proceed. 🚨

forward secrecy is provided through a Diffie-Hellman key agreement. this key agreement results in a shared session key. the rest of the session is encrypted using a symmetric cipher. the client selects the encryption algorithm to use from those offered by the server. additionally, session integrity is provided through a cryptographic message authentication code (MAC). she's layered, she's thorough, she's that girl ✨

finally, the server and the client enter an authentication dialog. the client tries to authenticate itself using:

  • host-based authentication,
  • public key authentication,
  • GSSAPI authentication,
  • challenge-response authentication, or
  • password authentication.

so many options and every single one is valid πŸ’–

regardless of the authentication type, the account is checked to ensure that it is accessible. an account is not accessible if it is locked, listed in DenyUsers or its group is listed in DenyGroups.

the definition of a locked account is system dependent. some platforms have their own account database (eg AIX) and some modify the passwd field:

  • '*LK*' on Solaris and UnixWare
  • '*' on HP-UX
  • containing 'Nologin' on Tru64
  • a leading '*LOCKED*' on FreeBSD
  • a leading '!' on most Linuxes

if there is a requirement to disable password authentication for the account while allowing still public-key, then the passwd field should be set to something other than these values (eg 'NP' or '*NP*'). write that down. seriously. πŸ“

if the client successfully authenticates itself, a dialog for preparing the session is entered. at this time the client may request things like allocating a pseudo-tty, forwarding X11 connections, forwarding TCP connections, or forwarding the authentication agent connection over the secure channel. she's flexible like that πŸ¦‹

after this, the client either requests an interactive shell or execution of a non-interactive command, which sshd will execute via the user's shell using its -c option. the sides then enter session mode. in this mode, either side may send data at any time, and such data is forwarded to/from the shell or command on the server side, and the user terminal in the client side. it's giving ✨ collaboration ✨

when the user program terminates and all forwarded X11 and other connections have been closed, the server sends command exit status to the client, and both sides exit. clean goodbye. no lingering. she knows when to log off πŸ’…


πŸŽ€ LOGIN PROCESS πŸŽ€

when a user successfully logs in, sshd does the following, in order, and yes we are listing all of them:

  1. if the login is on a tty, and no command has been specified, prints last login time and /etc/motd (unless prevented in the configuration file or by ~/.hushlogin; see the β€œFILES” section).
  2. if the login is on a tty, records login time. ⏰
  3. checks /etc/nologin; if it exists, prints contents and quits (unless root). the bouncer at the door, basically πŸšͺ
  4. changes to run with normal user privileges. drop the root energy, we're being humble now 🫢
  5. sets up basic environment. 🌱
  6. reads the file ~/.ssh/environment, if it exists, and users are allowed to change their environment. see the PermitUserEnvironment option in sshd_config(5). conditional queen ✨
  7. changes to user's home directory. 🏠
  8. if ~/.ssh/rc exists and the sshd_config(5) PermitUserRC option is set, runs it; else if /etc/gsissh/sshrc exists, runs it; otherwise runs xauth(1). the β€œrc” files are given the X11 authentication protocol and cookie in standard input. see β€œSSHRC”, below. yes there's a whole chain of if/else here, that's the vibe πŸ’œ
  9. runs user's shell or command. all commands are run under the user's login shell as specified in the system password database. and that's the finale 🎬

(more of this absolute saga coming in part 2, bestie, don't go anywhere) 🌈

πŸŽ€ SSHRC πŸŽ€

okay so, if ~/.ssh/rc exists, sh(1) runs it β€” and the timing here is very specific bestie: right after reading the environment files, but before it starts the user's shell or command. No early, no late. πŸ’…

Real talk though: it must not produce any output on stdout. Like, none. If you need to say something, stderr must be used instead. That's the rule. 😭

If X11 forwarding is in use, your script will receive the "proto cookie" pair in its standard input (and DISPLAY shows up in its environment 🌈). And the script must call xauth(1), because sshd will not run xauth automatically to add X11 cookies. It's giving "you're on your own, bestie" and honestly? Respect. πŸ™ˆ

The primary purpose of this whole file β€” its main character moment β€” is to run any initialization routines which may be needed before the user's home directory becomes accessible. AFS is a particular example of such an environment. πŸ¦‹

So yeah, this file will probably contain some initialization code followed by something similar to:

          if read proto cookie && [ -n "$DISPLAY" ]; then
                  if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then
                          # X11UseLocalhost=yes
                          echo add unix:`echo $DISPLAY |
                              cut -c11-` $proto $cookie
                  else
                          # X11UseLocalhost=no
                          echo add $DISPLAY $proto $cookie
                  fi | xauth -q -
          fi

And the fallback chain? Iconic, honestly. If ~/.ssh/rc does not exist, /etc/gsissh/sshrc is run instead. And if that one doesn't exist either? Then xauth is used to add the cookie. Three-tier queen behaviour, periodt. βœ¨πŸ‘‘

✨ AUTHORIZED_KEYS FILE FORMAT ✨

Okay bestie, this is THE file that decides which keys get in. AuthorizedKeysFile tells sshd which files hold the public keys used for public key auth β€” and if you don't set that option, it just defaults to ~/.ssh/authorized_keys and ~/.ssh/authorized_keys2. No cap.

Every single line in the file = one key. Empty lines? Ignored. Lines starting with a #? Those are comments, also ignored. Iconic behaviour honestly. πŸŽ€

A public key is made of these fields, all separated by spaces:

options keytype base64-encoded key comment

The options field is optional, the rest are not. And the key types that are supported are, in order:

sk-ecdsa-sha2-nistp256@openssh.com
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
sk-ssh-ed25519@openssh.com
ssh-ed25519
ssh-rsa

The comment field? Literally does nothing. It's not used for anything at all β€” it's just there so you can tell which key is which, which is lowkey very thoughtful of it. 🫢

Now, heads up: lines in this file can be several hundred bytes long (that's just how big the public key encoding is), and they can go all the way up to a limit of 8 kilobytes, which is enough for RSA keys up to 16 kilobits. Please, for the love of everything, do NOT type these in by hand. πŸ’€ Just copy the id_ecdsa.pub, id_ecdsa_sk.pub, id_ed25519.pub, id_ed25519_sk.pub, or the id_rsa.pub file and edit that.

⚠️ Also: sshd enforces a minimum RSA key modulus size of 1024 bits. So no baby keys.

🌸 The Options Field, aka the fun part

If the options are there, they're a bunch of option specifications separated by commas. No spaces allowed β€” except inside double quotes, where spaces are fine.

And a lil note before we go in: option keywords are case-insensitive. So type them however your heart desires.


  • agent-forwarding β€” Turns authentication agent forwarding back ON, for when it was previously switched off by the restrict option.
  • cert-authority β€” Says this listed key is a certification authority (CA) that's trusted to validate signed certificates for user authentication. ✨

Certificates can also carry access restrictions similar to these key options. And if BOTH certificate restrictions and key options are present, you get the most restrictive union of the two applied. Union of restrictions, babe. The strictest version wins.

  • command="command" β€” Says this exact command gets executed whenever this key is used for auth. Whatever command the user tried to supply? Ignored. Gone. Not happening. πŸ™ˆ

The command runs on a pty if the client asks for a pty; otherwise it runs without a tty. If you need an 8-bit clean channel, you must not request a pty, or you should specify no-pty. And if you want a quote inside the command itself, quote it with a backslash.

This option is lowkey useful for locking certain public keys down to one specific operation. Classic example: a key that permits remote backups and literally nothing else. Note that the client can still specify TCP and/or X11 forwarding unless those are explicitly prohibited β€” e.g. with the restrict key option.

The command the client originally supplied? You can still find it in the SSH_ORIGINAL_COMMAND environment variable. Note that this option applies to shell, command, or subsystem execution. And also note that this command may be superseded by an sshd_config(5) ForceCommand directive. πŸ‘‘

One more thing: if a command is specified here AND a forced-command is embedded in a certificate used for authentication, then the certificate is accepted only if the two commands are identical. Identical, bestie. Character for character.

  • environment="NAME=value" β€” Says this string gets added to the environment when you log in using this key. Environment variables set this way override other default environment values. Multiple options of this type are permitted. πŸ“

But heads up: environment processing is disabled by default and is controlled via the PermitUserEnvironment option.

  • expiry-time="timespec" β€” Specifies a time after which the key will not be accepted. The time can be a YYYYMMDD[Z] date or a YYYYMMDDHHMM[SS][Z] time. Dates and times get interpreted in the system time zone, unless there's a Z suffix β€” then they're interpreted in the UTC time zone. ⭐
  • from="pattern-list" β€” Says that on top of public key auth, either the canonical name of the remote host or its IP address must show up in this comma-separated list of patterns. (For more on patterns, see PATTERNS in ssh_config(5).)

Beyond the wildcard matching you can do on hostnames or addresses, a from stanza can also match IP addresses using CIDR address/masklen notation.

Why does this exist? To optionally bump up security. Public key auth on its own doesn't trust the network, or name servers, or anything β€” just the key. But if somebody somehow steals that key, the key alone lets an intruder log in from literally anywhere on the planet. 😭 This extra option makes using a stolen key way harder (the name servers and/or routers would have to be compromised in addition to the key itself).

  • no-agent-forwarding β€” Forbids authentication agent forwarding when this key is used for auth.
  • no-port-forwarding β€” Forbids TCP forwarding when this key is used for auth. Any port forward request from the client returns an error. This might get used, like, in connection with the command option.
  • no-pty β€” Prevents tty allocation. So a request to allocate a pty will fail.
  • no-user-rc β€” Disables execution of ~/.ssh/rc.
  • no-X11-forwarding β€” Forbids X11 forwarding when this key is used for auth. Any X11 forward request from the client returns an error.
  • permitlisten="[host:]port" β€” Limits remote port forwarding with the ssh(1) -R option so it can only listen on the specified host (that part's optional) and port. IPv6 addresses can be specified by wrapping the address in square brackets. Multiple permitlisten options can be applied, separated by commas. Hostnames may include wildcards as described in the PATTERNS section in ssh_config(5). A port specification of * matches any port.

Note that the setting of GatewayPorts may further restrict listen addresses. And note that ssh(1) will send a hostname of localhost if a listen host wasn't specified when the forwarding was requested β€” and that name is treated differently from the explicit localhost addresses 127.0.0.1 and ::1. πŸ’…

  • permitopen="host:port" β€” Limits local port forwarding with the ssh(1) -L option so it can only connect to the specified host and port. IPv6 addresses can be specified by wrapping the address in square brackets. Multiple permitopen options can be applied, separated by commas. No pattern matching or name lookup is performed on the specified hostnames β€” they must be literal host names and/or addresses. A port specification of * matches any port.
  • port-forwarding β€” Turns port forwarding back ON, for when it was previously switched off by the restrict option.
  • principals="principals" β€” On a cert-authority line, this specifies allowed principals for certificate auth as a comma-separated list. At least one name from that list has to appear in the certificate's own list of principals for the certificate to be accepted. This option gets ignored for keys that aren't marked as trusted certificate signers using the cert-authority option.
  • pty β€” Permits tty allocation again, for when it was previously disabled by the restrict option.
  • no-touch-required β€” Don't require demonstration of user presence for signatures made with this key. This option only makes sense for the FIDO authenticator algorithms ecdsa-sk and ed25519-sk. πŸ”₯
  • verify-required β€” Requires that signatures made using this key attest that they verified the user β€” like, via a PIN. This option only makes sense for the FIDO authenticator algorithms ecdsa-sk and ed25519-sk.
  • restrict β€” Enables ALL the restrictions. i.e. it disables port, agent and X11 forwarding, plus disables PTY allocation and execution of ~/.ssh/rc. And if any future restriction capabilities get added to authorized_keys files, they'll be included in this set too. Foresight, honestly. ✨
  • tunnel="n" β€” Forces a tun(4) device on the server. Without this option, the next available device gets used if the client requests a tunnel.
  • user-rc β€” Enables execution of ~/.ssh/rc again, for when it was previously disabled by the restrict option.
  • X11-forwarding β€” Permits X11 forwarding again, for when it was previously disabled by the restrict option.

🌈 An example authorized_keys file

Straight from the source, no edits, look at her:

# Comments are allowed at start of line. Blank lines are allowed.
# Plain key, no restrictions
ssh-rsa ...
# Forced command, disable PTY and all forwarding
restrict,command="dump /home" ssh-rsa ...
# Restriction of ssh -L forwarding destinations
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-rsa ...
# Restriction of ssh -R forwarding listeners
permitlisten="localhost:8080",permitlisten="[::1]:22000" ssh-rsa ...
# Configuration for tunnel forwarding
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa ...
# Override of restriction to allow PTY allocation
restrict,pty,command="nethack" ssh-rsa ...
# Allow FIDO key without requiring touch
no-touch-required sk-ecdsa-sha2-nistp256@openssh.com ...
# Require user-verification (e.g. PIN or biometric) for FIDO key
verify-required sk-ecdsa-sha2-nistp256@openssh.com ...
# Trust CA key, allow touch-less FIDO if requested in certificate
cert-authority,no-touch-required,principals="user_a" ssh-rsa ...

Ate. Every single one. πŸŽ€

✨ SSH_KNOWN_HOSTS FILE FORMAT ✨

okay bestie, this is the part where we talk about the sacred little address book of host keys πŸ’– The /etc/gsissh/ssh_known_hosts and ~/.ssh/known_hosts files hold host public keys for every host you know about. The global one is the admin's job to set up (and it's optional!), while the per-user one just... maintains itself. Every time you connect to a host you've never met before, its key gets added to your personal file. It's giving "auto-saved contacts" energy, fr fr. πŸ“‡βœ¨

Every single line in these files has these fields, in this exact order: marker (optional), hostnames, keytype, base64-encoded key, comment. And they're all separated by spaces. Periodt. πŸ’…

The marker is optional, BUT β€” and this is the important bit β€” if it is there, it has to be one of these two:

  • @cert-authority β€” means this line contains a certification authority (CA) key πŸ‘‘
  • @revoked β€” means the key on this line is revoked and must never ever be accepted, no exceptions πŸ’€

Only one marker per key line, okay? Don't be greedy.

Hostnames is a comma-separated list of patterns (* and ? do the wildcard thing), and each pattern gets matched against the host name one by one. When sshd is authenticating a client β€” like with HostbasedAuthentication β€” this is the canonical client host name. When ssh(1) is authenticating a server, this is whatever host name the user gave, or the value of ssh(1)'s HostkeyAlias if that was specified, or the canonical server hostname if ssh(1)'s CanonicalizeHostname option was used. So many paths, iykyk. πŸ¦‹

A pattern can also start with ! for negation: if the host name matches a negated pattern, that line won't accept it β€” even if it also matched some other pattern on the same line. Sneaky but fair. And a hostname or address can optionally be wrapped in [ and ] brackets and then followed by : and a non-standard port number. Cute AND specific. πŸŽ€

Alternately β€” plot twist β€” hostnames can be stored in a hashed form that hides host names and addresses in case the file's contents get leaked. Hashed hostnames start with a | character. But here's the catch: only one hashed hostname may appear on a single line, and none of that negation or wildcard stuff applies. No mixing, no matching, no drama. πŸ™ˆ

The keytype and base64-encoded key are taken directly from the host key β€” you can grab them, for example, from /etc/gsissh/ssh_host_rsa_key.pub. The optional comment field just runs to the end of the line and, honestly, isn't used for anything. It's decorative. It's the accessory. πŸ‘œ

Lines starting with # and empty lines? Ignored, they're comments. πŸ’¬


🫢 how the actual authentication decision goes down

When host authentication happens, it's accepted if any matching line has the proper key β€” either one that matches exactly, or, if the server presented a certificate for authentication, the key of the certification authority that signed that certificate. But for a key to be trusted as a certification authority, it must use the @cert-authority marker we talked about above. No marker, no CA powers. 🧚

The known hosts file also gives you a way to mark keys as revoked β€” super useful when you find out the associated private key has been stolen 😭 Revoked keys get the @revoked marker at the beginning of the key line, and they are never accepted for authentication or as certification authorities. Instead, ssh(1) will throw a warning at you when it runs into them. Consider yourself warned. ⚠️

It is permissible (but not recommended) to have several lines, or different host keys, for the same names. And honestly it'll happen whether you want it or not, because short forms of host names from different domains end up in the same file. The files might even contain conflicting information β€” and in that case, authentication is accepted if valid information can be found from either file. Chaotic? Yes. Working as intended? Also yes. πŸ’€

note that the lines in these files are typically hundreds of characters long, and you definitely do not want to type in the host keys by hand. Bestie, please. πŸ™

Instead, generate them with a script, with ssh-keyscan(1), or by taking something like /etc/gsissh/ssh_host_rsa_key.pub and slapping the host names on the front. ssh-keygen(1) also offers some basic automated editing for ~/.ssh/known_hosts β€” including removing hosts that match a host name, and converting all host names to their hashed representations. It's the glow-up your known_hosts deserved. ✨

An example ssh_known_hosts file, for the visual learners:

# Comments allowed at start of line
cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=
# A hashed hostname
|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa
AAAA1234.....=
# A revoked key
@revoked * ssh-rsa AAAAB5W...
# A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...

🌈 ENVIRONMENT 🌈

sshd will normally set the following environment variables. Yes bestie, it's setting these for you, you don't have to lift a finger πŸ’…

  • GRIDMAP β€” Applies to GSI authentication/authorization. Specifies the location of the gridmapfile. If you don't specify it, the gridmap file is assumed to be sitting at /etc/grid-security/grid-mapfile for services running as root, and at HOME/.gridmap for services running as non-root β€” where HOME is the home directory of the effective user, taken from the password file entry. Two whole different defaults, depending on who you are. πŸ‘‘
  • X509_CERT_DIR β€” Used for GSI authentication. Specifies a non-standard location for the CA certificates directory. πŸŽ€
  • X509_USER_CERT β€” Used for GSI authentication. Specifies a non-standard location for the certificate to be used for authentication to the client. πŸ¦‹
  • X509_USER_KEY β€” Used for GSI authentication. Specifies a non-standard location for the private key to be used for authentication to the client. πŸ”‘
  • X509_USER_PROXY β€” Used for GSI authentication. Specifies a non-standard location for the proxy credential to be used for authentication to the client. 🫢

πŸ—‚οΈ FILES ✨

okay so this is the part where we go through literally every file sshd touches, and bestie, there are so many. buckle up πŸ’–

  • ~/.hushlogin β€” drop this file in and it suppresses printing the last login time and /etc/motd β€” but only if PrintLastLog and PrintMotd (respectively) are enabled. it does not suppress printing of the banner specified by Banner. so if you're trying to go fully silent, this ain't it, queen πŸ™ˆ
  • ~/.rhosts β€” this one's for host-based authentication (peep ssh(1) for more). on some machines this file may need to be world-readable if the user's home directory is on an NFS partition, because sshd reads it as root. also it must be owned by the user, and must not have write permissions for anyone else. recommended permission for most machines is read/write for the user, and not accessible by others. no cap πŸ”’
  • ~/.shosts β€” used in exactly the same way as .rhosts, but it allows host-based authentication without permitting login with rlogin/rsh. glow-up move honestly ✨
  • ~/.k5login
  • ~/.k5users β€” these files enforce GSSAPI/Kerberos authentication access control. further details live in ksu(1). heads up: the location of the k5login file depends on the configuration option k5login_directory in krb5.conf(5). it's giving "look it up in three other manpages" πŸ’€
  • ~/.ssh/ β€” the default location for all user-specific configuration and authentication info. there's no general requirement to keep the entire contents of this directory secret, but the recommended permissions are read/write/execute for the user, and not accessible by others. keep your lil folder cozy but private πŸŽ€
  • ~/.ssh/authorized_keys β€” lists the public keys (ECDSA, Ed25519, RSA) that can be used for logging in as this user. format is described above. the content of the file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others.
⚠️ if this file, the ~/.ssh directory, or the user's home directory are writable by other users, then the file could be modified or replaced by unauthorized users. in that case, sshd will not allow it to be used unless the StrictModes option has been set to β€œno”. so like… don't do that πŸ™
  • ~/.ssh/environment β€” read into the environment at login (if it exists). it can only contain empty lines, comment lines (that start with β€˜#’), and assignment lines of the form name=value. the file should be writable only by the user; it need not be readable by anyone else. environment processing is disabled by default and is controlled via the PermitUserEnvironment option. default-off, bestie, don't @ me πŸ¦‹
  • ~/.ssh/known_hosts β€” contains a list of host keys for all hosts the user has logged into that are not already in the systemwide list of known host keys. format described above. this file should be writable only by root/the owner and can, but need not be, world-readable.
  • ~/.ssh/rc β€” contains initialization routines to be run before the user's home directory becomes accessible. should be writable only by the user, and need not be readable by anyone else.
  • /etc/hosts.equiv β€” for host-based authentication (see ssh(1)). it should only be writable by root. only. root. periodt πŸ‘‘
  • /etc/gsissh/moduli β€” contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange" key exchange method. the file format is described in moduli(5). if no usable groups are found in this file then fixed internal groups will be used β€” so there's a fallback, cute 🌸
  • /etc/motd β€” see motd(5). that's it, that's the whole thing πŸ’…
  • /etc/nologin β€” if this file exists, sshd refuses to let anyone except root log in. the contents of the file are displayed to anyone trying to log in, and non-root connections are refused. the file should be world-readable. it's literally the "we're closed" sign on the door πŸ”₯
  • /etc/gsissh/shosts.equiv β€” used in exactly the same way as hosts.equiv, but allows host-based authentication without permitting login with rlogin/rsh.
  • /etc/gsissh/ssh_host_ecdsa_key
  • /etc/gsissh/ssh_host_ed25519_key
  • /etc/gsissh/ssh_host_rsa_key β€” these files contain the private parts of the host keys. they should only be owned by root, readable only by root, and not accessible to others.
🚨 note that sshd does not start if these files are group/world-accessible. she will simply refuse. iconic of her honestly πŸ’€
  • /etc/gsissh/ssh_host_ecdsa_key.pub
  • /etc/gsissh/ssh_host_ed25519_key.pub
  • /etc/gsissh/ssh_host_rsa_key.pub β€” these contain the public parts of the host keys. they should be world-readable but writable only by root. their contents should match the respective private parts. plot twist: these files are not really used for anything β€” they're provided for the convenience of the user so their contents can be copied to known hosts files. these files are created using ssh-keygen(1). decorative but valid ✨
  • /etc/gsissh/ssh_known_hosts β€” systemwide list of known host keys. should be prepared by the system administrator to contain the public host keys of all machines in the organization. format described above. this file should be writable only by root/the owner and should be world-readable.
  • /etc/gsissh/sshd_config β€” contains configuration data for sshd. the file format and configuration options are described in sshd_config(5). the main character of the config world, fr fr πŸ‘‘
  • /etc/gsissh/sshrc β€” similar to ~/.ssh/rc, it can be used to specify machine-specific login-time initializations globally. this file should be writable only by root, and should be world-readable.
  • /usr/share/empty.sshd β€” the chroot(2) directory used by sshd during privilege separation in the pre-authentication phase. the directory should not contain any files and must be owned by root and not group or world-writable. literally keep it empty, bestie, it's a vibe 🫢
  • /var/run/gsisshd.pid β€” contains the process ID of the sshd listening for connections (if there are several daemons running concurrently for different ports, this contains the process ID of the one started last). the content of this file is not sensitive; it can be world-readable. it's giving "last one to the party writes the note" 😭

🌈 IPV6 🌈

okay so IPv6 address can be used everywhere where IPv4 address. that's the dream, no cap πŸ’–

but in all entries, the IPv6 address must be enclosed in square brackets. so like [ ], you know the ones.

⚠️ note: the square brackets are metacharacters for the shell and must be escaped in shell. so if you're typing this straight into a shell, don't forget the backslash or the shell will do its lil thing and ruin your day πŸ’€

πŸ‘€ SEE ALSO πŸ‘€

go read these next, bestie, they're all part of the extended cinematic universe:

scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh-keyscan(1), chroot(2), login.conf(5), moduli(5), sshd_config(5), inetd(8), sftp-server(8)


πŸ‘‘ AUTHORS πŸ‘‘

the lore drop 🫢:

OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support for privilege separation. Chris Rapier, Michael Stevens, Ben Bennet, and Mike Tasota developed the HPN extensions at the Pittsburgh Supercomuting Center with grants from Cisco, the National Library of Medicine, and the National Science Foundation.

shoutout to the whole squad, we literally would not have secure remote login without y'all πŸ’œ


and that's a wrap on the whole SSHD(8) page, bestie!! πŸŽ€ this version is the Debian one, dated October 4, 2025, and it's SSHD(8) β€” you made it all the way to the end, so here's your crown πŸ‘‘ go log in somewhere secure. mwah πŸ’–

πŸ“¦ where this page comes from
  • fedora 44: gsi-openssh-server 10.2p1-1.fc44 Β· BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant
  • fedora 44: gsi-openssh-server 10.2p1-4.fc44 Β· BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND snprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms