How to Capture SSHd Logs in Docker Containers When Using -D Flag


5 views

Many developers encounter this frustrating scenario: you've set up SSHD in a Docker container with the -D flag, but docker logs shows nothing. This behavior occurs because:

  • SSHD with -D runs in foreground but doesn't write to stdout/stderr by default
  • Docker captures container logs from these standard streams
  • The logging backend (journald/json-file) makes no difference for this particular issue

The correct approach requires adding the -e flag to make SSHD output logs to stderr:

FROM alpine:latest
RUN apk add --no-cache openssh-server \
    && mkdir /var/run/sshd \
    && ssh-keygen -A
CMD ["/usr/sbin/sshd", "-D", "-e"]

For more advanced logging requirements, consider these approaches:

1. Direct Log File Access

# In Dockerfile
RUN mkdir -p /var/log && touch /var/log/sshd.log
CMD ["sh", "-c", "/usr/sbin/sshd -D -E /var/log/sshd.log"]

# To view logs:
docker exec -it container-name tail -f /var/log/sshd.log

2. Syslog Forwarding

# Install syslog daemon
RUN apk add --no-cache rsyslog

# Configure SSHD to use syslog
CMD ["sh", "-c", "rsyslogd & /usr/sbin/sshd -D -e"]

If logs still don't appear:

  • Verify the container is actually running: docker ps
  • Check for immediate exits: docker inspect --format='{{.State.ExitCode}}' container-name
  • Test with simpler commands first: CMD ["sh", "-c", "echo 'test' && /usr/sbin/sshd -D -e"]

For production environments:

# Use a proper init system to manage processes
RUN apk add --no-cache openrc
CMD ["/sbin/init", "sshd -D -e"]

Remember that running SSHD in containers has security implications. Consider alternatives like docker exec for most use cases.


When running SSHd in a Docker container with Alpine Linux, a common frustration is that logs don't appear through docker logs command. This happens because by default, SSHd logs to syslog rather than stdout/stderr.

# Typical Dockerfile that won't show logs
FROM alpine:latest
RUN apk add --no-cache openssh-server \
    && mkdir /var/run/sshd \
    && ssh-keygen -A
CMD ["/usr/sbin/sshd", "-D"]

The solution lies in SSHd's -e flag, which forces logging to stderr:

# Working Dockerfile with visible logs
FROM alpine:latest
RUN apk add --no-cache openssh-server \
    && mkdir /var/run/sshd \
    && ssh-keygen -A
CMD ["/usr/sbin/sshd", "-D", "-e"]

While -D keeps SSHd in foreground mode (necessary for Docker), -e ensures logs go to stderr. Testing shows:

docker run -d --name sshd-container sshd-image
docker logs sshd-container
# Now shows:
# Server listening on 0.0.0.0 port 22.
# Server listening on :: port 22.

For more complex logging needs, consider these options:

# 1. Redirect syslog to stdout
CMD ["sh", "-c", "/usr/sbin/sshd -D | logger -t sshd"]

# 2. Use custom logging configuration
RUN echo "SyslogFacility DAEMON" >> /etc/ssh/sshd_config

When using journald driver, verify logs with:

journalctl -u docker CONTAINER_NAME=sshd-container

Remember that journald may add its own timestamp and metadata fields to log entries.

For production environments, consider:

  • Adding log rotation (logrotate inside container)
  • Using centralized logging (Fluentd, ELK stack)
  • Implementing log level control via sshd_config
# Example for log level control
RUN echo "LogLevel VERBOSE" >> /etc/ssh/sshd_config