들어가며: SSH, 원격 서버 관리의 핵심

SSH(Secure Shell)는 네트워크를 통해 안전하게 원격 서버에 접속하고 관리하는 프로토콜입니다. 암호화된 통신으로 데이터를 보호하며, 현대 서버 운영에서 가장 중요한 도구 중 하나입니다. 이번 편에서는 SSH의 기초부터 고급 활용법까지 다룹니다.

1. SSH 기초

1.1 SSH 접속 기본

# 기본 접속
ssh username@hostname

# 특정 포트로 접속
ssh -p 2222 username@hostname

# IP 주소로 접속
ssh user@192.168.1.100

# 상세 디버그 모드
ssh -v username@hostname
ssh -vvv username@hostname  # 더 자세한 정보

1.2 SSH 서버 설치 및 상태 확인

# Ubuntu/Debian
sudo apt update
sudo apt install openssh-server

# RHEL/CentOS
sudo dnf install openssh-server

# SSH 서버 상태 확인
sudo systemctl status sshd

# 서비스 시작/중지/재시작
sudo systemctl start sshd
sudo systemctl stop sshd
sudo systemctl restart sshd

# 부팅 시 자동 시작
sudo systemctl enable sshd

1.3 SSH 접속 끊기

# 일반 종료
exit
logout
Ctrl + D

# 세션이 멈췄을 때 강제 종료
~.    # Enter 후 ~. 입력

2. SSH 키 기반 인증

2.1 키 쌍 생성

# RSA 키 생성 (기본)
ssh-keygen -t rsa -b 4096

# Ed25519 키 생성 (권장, 더 안전하고 빠름)
ssh-keygen -t ed25519

# 특정 파일명으로 생성
ssh-keygen -t ed25519 -f ~/.ssh/myserver_key

# 코멘트 추가
ssh-keygen -t ed25519 -C "admin@company.com"

# 생성된 파일 확인
ls -la ~/.ssh/
# id_ed25519      - 개인키 (절대 공유하지 않음)
# id_ed25519.pub  - 공개키 (서버에 등록)

2.2 공개키 서버에 등록

# ssh-copy-id 사용 (가장 쉬운 방법)
ssh-copy-id username@hostname
ssh-copy-id -i ~/.ssh/myserver_key.pub username@hostname

# 수동 등록
cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# 또는 직접 서버에서
# ~/.ssh/authorized_keys 파일에 공개키 내용 추가

# 권한 설정 (중요!)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

2.3 키 기반 접속

# 기본 키로 접속
ssh username@hostname

# 특정 키 지정
ssh -i ~/.ssh/myserver_key username@hostname

# 패스프레이즈 입력 피하기 (ssh-agent)
eval $(ssh-agent)
ssh-add ~/.ssh/id_ed25519
ssh-add -l  # 등록된 키 확인

3. SSH 설정 파일

3.1 클라이언트 설정 (~/.ssh/config)

# ~/.ssh/config 예시
# 웹서버
Host webserver
    HostName 192.168.1.10
    User admin
    Port 22
    IdentityFile ~/.ssh/webserver_key

# 개발서버 (별칭 사용)
Host dev
    HostName dev.company.com
    User developer
    Port 2222

# DB서버 (점프호스트 경유)
Host dbserver
    HostName 10.0.0.50
    User dbadmin
    ProxyJump webserver

# 모든 호스트 공통 설정
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes

# 이제 간단히 접속 가능
# ssh webserver
# ssh dev

3.2 서버 설정 (/etc/ssh/sshd_config)

# 주요 보안 설정
# 포트 변경
Port 2222

# root 로그인 비활성화
PermitRootLogin no

# 비밀번호 인증 비활성화 (키 인증만 허용)
PasswordAuthentication no

# 빈 비밀번호 금지
PermitEmptyPasswords no

# 특정 사용자만 허용
AllowUsers admin deploy

# 특정 그룹만 허용
AllowGroups sshusers

# 로그인 시도 제한
MaxAuthTries 3

# 최대 세션 수
MaxSessions 5

# X11 포워딩 비활성화
X11Forwarding no

# 설정 적용
sudo sshd -t  # 문법 검사
sudo systemctl restart sshd

4. 파일 전송: SCP와 SFTP

4.1 SCP (Secure Copy)

# 로컬 → 원격 (파일)
scp file.txt user@host:/path/to/destination/

# 로컬 → 원격 (디렉토리)
scp -r mydir/ user@host:/path/to/destination/

# 원격 → 로컬
scp user@host:/path/to/file.txt ./local/

# 다른 포트 사용
scp -P 2222 file.txt user@host:/path/

# 특정 키 사용
scp -i ~/.ssh/mykey file.txt user@host:/path/

# 압축 전송 (대용량 파일에 유용)
scp -C largefile.zip user@host:/path/

# 대역폭 제한 (KB/s)
scp -l 1000 file.txt user@host:/path/

# 서버 간 전송
scp user1@host1:/file.txt user2@host2:/path/

4.2 SFTP (SSH File Transfer Protocol)

# SFTP 접속
sftp user@host
sftp -P 2222 user@host

# SFTP 명령어
sftp> pwd           # 원격 현재 디렉토리
sftp> lpwd          # 로컬 현재 디렉토리
sftp> ls            # 원격 파일 목록
sftp> lls           # 로컬 파일 목록
sftp> cd /path      # 원격 디렉토리 이동
sftp> lcd /path     # 로컬 디렉토리 이동
sftp> get file.txt  # 다운로드
sftp> get -r dir/   # 디렉토리 다운로드
sftp> put file.txt  # 업로드
sftp> put -r dir/   # 디렉토리 업로드
sftp> rm file.txt   # 삭제
sftp> mkdir newdir  # 디렉토리 생성
sftp> exit          # 종료

4.3 rsync over SSH

# 기본 동기화
rsync -avz source/ user@host:/destination/

# 삭제된 파일도 동기화
rsync -avz --delete source/ user@host:/destination/

# 다른 포트 사용
rsync -avz -e "ssh -p 2222" source/ user@host:/dest/

# 진행률 표시
rsync -avz --progress source/ user@host:/dest/

# 테스트 (dry-run)
rsync -avzn source/ user@host:/dest/

5. SSH 터널링 (포트 포워딩)

5.1 로컬 포트 포워딩

로컬 머신의 포트를 원격 서버를 통해 다른 서버로 연결합니다.

# 구문: ssh -L [로컬포트]:[대상호스트]:[대상포트] [SSH서버]

# 예: 로컬 3306으로 접속하면 원격 DB 서버에 연결
ssh -L 3306:localhost:3306 user@sshserver

# 예: 원격 서버 뒤의 다른 서버 접근
ssh -L 8080:internal-web.lan:80 user@sshserver

# 백그라운드 실행
ssh -fNL 3306:localhost:3306 user@sshserver

# 이제 localhost:3306으로 DB 접속 가능
mysql -h localhost -P 3306 -u dbuser -p

5.2 원격 포트 포워딩

원격 서버의 포트를 로컬 머신으로 연결합니다.

# 구문: ssh -R [원격포트]:[로컬호스트]:[로컬포트] [SSH서버]

# 예: 원격 서버의 8080을 로컬의 80으로 연결
ssh -R 8080:localhost:80 user@sshserver

# 외부에서 원격 서버의 8080 접근 시 로컬 80으로 전달

# 백그라운드 실행
ssh -fNR 8080:localhost:80 user@sshserver

5.3 동적 포트 포워딩 (SOCKS 프록시)

# SOCKS 프록시 생성
ssh -D 1080 user@sshserver

# 백그라운드 실행
ssh -fND 1080 user@sshserver

# 브라우저나 애플리케이션에서 SOCKS5 프록시 설정
# 프록시: localhost:1080

5.4 점프 호스트 (프록시 점프)

# -J 옵션 사용 (OpenSSH 7.3+)
ssh -J jumphost user@targetserver

# 여러 점프 호스트
ssh -J jump1,jump2 user@target

# 구형 방식 (-o ProxyCommand)
ssh -o ProxyCommand="ssh -W %h:%p jumphost" user@target

# ~/.ssh/config에 설정
Host internal
    HostName 10.0.0.50
    User admin
    ProxyJump jumphost

6. SSH 보안 강화

6.1 sshd_config 보안 설정

# /etc/ssh/sshd_config

# 비밀번호 인증 비활성화 (키만 허용)
PasswordAuthentication no
ChallengeResponseAuthentication no

# root 로그인 금지
PermitRootLogin no

# 빈 비밀번호 금지
PermitEmptyPasswords no

# 키보드 인터랙티브 인증 비활성화
KbdInteractiveAuthentication no

# 프로토콜 버전 2만 허용 (기본값)
Protocol 2

# 로그인 시도 제한
MaxAuthTries 3
LoginGraceTime 30

# 특정 IP에서만 접속 허용 (sshd_config 또는 방화벽)
# AllowUsers admin@192.168.1.0/24

# TCP 포워딩 제한
AllowTcpForwarding no
AllowAgentForwarding no

# 강력한 암호화 알고리즘만 허용
Ciphers aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# 설정 적용 전 문법 검사
sudo sshd -t
sudo systemctl restart sshd

6.2 Fail2Ban 설치

# Ubuntu/Debian
sudo apt install fail2ban

# RHEL/CentOS
sudo dnf install fail2ban

# 설정 파일 생성
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# /etc/fail2ban/jail.local 수정
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log   # Debian/Ubuntu
# logpath = /var/log/secure   # RHEL/CentOS
maxretry = 3
bantime = 3600
findtime = 600

# 서비스 시작
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# 상태 확인
sudo fail2ban-client status sshd

6.3 2단계 인증 (2FA)

# Google Authenticator 설치
sudo apt install libpam-google-authenticator

# 설정 초기화
google-authenticator

# PAM 설정 (/etc/pam.d/sshd)
auth required pam_google_authenticator.so

# sshd_config 설정
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

# 서비스 재시작
sudo systemctl restart sshd

7. SSH 에이전트와 키 관리

7.1 SSH 에이전트 사용

# 에이전트 시작
eval $(ssh-agent)

# 키 추가
ssh-add                      # 기본 키
ssh-add ~/.ssh/mykey        # 특정 키
ssh-add -t 3600 ~/.ssh/key  # 1시간 후 자동 삭제

# 등록된 키 확인
ssh-add -l

# 키 삭제
ssh-add -d ~/.ssh/mykey     # 특정 키
ssh-add -D                  # 모든 키

# 에이전트 종료
ssh-agent -k

7.2 SSH 에이전트 포워딩

# -A 옵션으로 에이전트 포워딩
ssh -A user@server1

# 이제 server1에서 로컬 키로 다른 서버 접속 가능
ssh user@server2

# ~/.ssh/config에 설정
Host server1
    ForwardAgent yes

# 주의: 신뢰할 수 있는 서버에서만 사용

7.3 키 관리 모범 사례

# 키별 용도 분리
ssh-keygen -t ed25519 -f ~/.ssh/work_key -C "work"
ssh-keygen -t ed25519 -f ~/.ssh/personal_key -C "personal"

# 강력한 패스프레이즈 설정
ssh-keygen -t ed25519 -f ~/.ssh/mykey
# (대화형으로 패스프레이즈 입력)

# 키 권한 확인
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/*.pub
chmod 700 ~/.ssh

# 오래된 키 교체
# 1. 새 키 생성
# 2. 새 키를 서버에 등록
# 3. 테스트
# 4. 구 키 삭제

8. 원격 서버 관리 팁

8.1 세션 유지 (keepalive)

# 클라이언트 설정 (~/.ssh/config)
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

# 서버 설정 (/etc/ssh/sshd_config)
ClientAliveInterval 60
ClientAliveCountMax 3

8.2 tmux/screen과 함께 사용

# tmux 세션 생성
tmux new -s mysession

# 세션 분리 (Ctrl+B, D)
# SSH 연결이 끊어져도 작업 유지

# 다시 접속 후 세션 복귀
tmux attach -t mysession

# 세션 목록
tmux ls

8.3 여러 서버 동시 관리

# 여러 서버에 동일 명령 실행
for server in server1 server2 server3; do
    ssh $server "uptime"
done

# parallel-ssh 사용
pssh -h hosts.txt -l user "uptime"

# Ansible 사용 (권장)
ansible all -m ping
ansible all -a "uptime"

8.4 SSH 연결 재사용

# ~/.ssh/config
Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

# 소켓 디렉토리 생성
mkdir -p ~/.ssh/sockets

# 첫 연결 후 추가 연결이 빠름

9. 문제 해결

9.1 일반적인 오류

# Permission denied (publickey)
# → 키 권한 확인
chmod 600 ~/.ssh/id_*
chmod 700 ~/.ssh

# Host key verification failed
# → known_hosts에서 해당 호스트 제거
ssh-keygen -R hostname

# Connection refused
# → SSH 서버 실행 확인
sudo systemctl status sshd

# Connection timed out
# → 방화벽 확인
sudo ufw status
sudo firewall-cmd --list-all

9.2 디버그 모드

# 클라이언트 디버그
ssh -v user@host    # 기본
ssh -vv user@host   # 상세
ssh -vvv user@host  # 매우 상세

# 서버 디버그 (포그라운드 실행)
sudo /usr/sbin/sshd -d -p 2222

10. 실습: SSH 보안 설정 체크리스트

# 1. 키 기반 인증 설정
ssh-keygen -t ed25519
ssh-copy-id user@server

# 2. 비밀번호 인증 비활성화
# /etc/ssh/sshd_config
PasswordAuthentication no

# 3. root 로그인 금지
PermitRootLogin no

# 4. 포트 변경 (선택)
Port 2222

# 5. 방화벽 설정
sudo ufw allow 2222/tcp
sudo ufw enable

# 6. Fail2Ban 설치
sudo apt install fail2ban

# 7. 설정 적용
sudo sshd -t && sudo systemctl restart sshd

# 8. 테스트
ssh -p 2222 user@server

마무리

SSH는 원격 서버 관리의 핵심 도구입니다. 키 기반 인증을 사용하고, 적절한 보안 설정을 적용하며, 터널링 기능을 활용하면 안전하고 효율적인 서버 관리가 가능합니다. 다음 편에서는 쉘 스크립트 기초를 통해 서버 관리 자동화의 첫 걸음을 시작합니다.