우분투 서버 초기 설정: 신규 설치 후 Ubuntu 서버에서 시작할 9단계

새 서버를 받으면 서비스를 올리기 전에 우분투 서버 초기 설정을 한 번 거칩니다. 디지털오션에서 만든 Ubuntu 24.04 서버에 root로 접속해 패키지 업데이트부터 sudo 사용자, 키 로그인, 방화벽, 시간대, 자동 보안 업데이트, 스왑까지 차례로 설정하고, 재부팅한 뒤에도 설정이 그대로 남는 것까지 확인했습니다.
아래 결과 상자는 명령을 이 순서대로 실행한 출력입니다. 서버 IP 203.0.113.10은 예시 값이며, 새로 만드는 일반 사용자 이름은 deploy로 정했습니다.
1️⃣ 우분투 패키지 업데이트
새로 만든 서버에도 설치할 업데이트가 쌓여 있습니다. 패키지 목록을 새로 받은 뒤, 실제로 설치하기 전에 무엇이 바뀌는지부터 확인합니다.
🔲 apt-get update
export DEBIAN_FRONTEND=noninteractive아래 apt-get 명령은 이 값을 먼저 둔 뒤 실행했습니다. 이 값을 두면 패키지 설치 중 설정을 묻는 창이 뜨지 않고 기본 답이 적용됩니다.
apt-get updateHit:1 http://mirrors.digitalocean.com/ubuntu noble InRelease
Hit:2 http://mirrors.digitalocean.com/ubuntu noble-updates InRelease
Hit:3 http://mirrors.digitalocean.com/ubuntu noble-backports InRelease
Hit:4 https://repos-droplet.digitalocean.com/apt/droplet-agent main InRelease
Hit:5 http://security.ubuntu.com/ubuntu noble-security InRelease
Reading package lists...🔲 apt-get -s upgrade
apt-get -s upgradeCalculating upgrade...
The following upgrades have been deferred due to phasing:
libsqlite3-0
The following packages will be upgraded:
apt apt-transport-https apt-utils bind9-dnsutils bind9-host bind9-libs
cloud-init distro-info-data gir1.2-glib-2.0 git git-man libapt-pkg6.0t64
libbrotli1 libglib2.0-0t64 libglib2.0-bin libglib2.0-data liblzma5
libmspack0t64 libpcre2-8-0 python3-jwt python3-twisted tmux
ubuntu-pro-client ubuntu-pro-client-l10n xz-utils zlib1g
26 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.-s 옵션은 설치하지 않고 결과만 계산하는 모의 실행입니다. 이 서버에서는 26개가 업그레이드 대상이었고, libsqlite3-0 하나는 [deferred due to phasing]으로 이번 업그레이드에서 빠졌습니다. 대상 개수는 서버를 만든 시점과 이미지에 따라 서버마다 다릅니다.
🔲 apt-get -y upgrade
apt-get -y upgrade26 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
Need to get 15.4 MB of archives.
After this operation, 398 kB of additional disk space will be used.설치가 끝난 뒤에는 다시 시작한 서비스 목록이 이어서 나옵니다.
Running kernel seems to be up-to-date.
Restarting services...
/etc/needrestart/restart.d/systemd-manager
systemctl restart cron.service fwupd.service multipathd.service packagekit.service polkit.service ssh.service systemd-journald.service systemd-networkd.service systemd-resolved.service systemd-timesyncd.service systemd-udevd.service udisks2.service
Service restarts being deferred:
systemctl restart ModemManager.service
/etc/needrestart/restart.d/dbus.service
systemctl restart systemd-logind.service
systemctl restart unattended-upgrades.service재부팅이 필요한 업데이트가 들어왔을 때는 /var/run/reboot-required 파일이 생깁니다. 이번에는 [Running kernel seems to be up-to-date.]가 나오고 그 파일도 생기지 않아 재부팅 없이 다음 단계로 넘어갔습니다.
2️⃣ 우분투 사용자 추가와 sudo 권한
평소 작업은 일반 사용자로 하고, 관리 명령만 sudo로 실행합니다. sudo는 root 비밀번호 대신 자기 비밀번호로 권한을 올리므로 누가 어떤 명령을 실행했는지 남습니다.
🔲 adduser deploy
adduser deployinfo: Adding user `deploy' ...
info: Selecting UID/GID from range 1000 to 59999 ...
info: Adding new group `deploy' (1000) ...
info: Adding new user `deploy' (1000) with group `deploy (1000)' ...
info: Creating home directory `/home/deploy' ...
info: Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for deploy
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
info: Adding new user `deploy' to supplemental / extra groups `users' ...
info: Adding user `deploy' to group `users' ...adduser는 useradd를 감싼 도구로, 홈 폴더와 그룹을 만든 뒤 비밀번호와 사용자 정보를 차례로 묻습니다. 비밀번호는 입력해도 화면에 나오지 않고, 이름과 전화번호 같은 정보는 Enter로 비워 둡니다.
🔲 usermod -aG sudo deploy
usermod -aG sudo deploygroups deploydeploy : deploy sudo users🔲 su
sudo 그룹에 들어간 사용자는 sudo로 관리 명령을 실행할 수 있습니다. su로 deploy 계정으로 전환해 권한을 확인합니다.
su - deployTo run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.whoamideploysudo whoami[sudo] password for deploy:
rootexitsudo를 붙이면 deploy의 비밀번호를 묻고, 맞으면 명령이 root 권한으로 실행됩니다.
3️⃣ 새 사용자 SSH 키 등록
처음에는 root에만 SSH 키가 등록되어 있어 deploy로는 키 로그인이 되지 않습니다. root의 authorized_keys를 deploy의 홈 폴더로 복사합니다.
🔲 install -o deploy -g deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.sshinstall -m 600 -o deploy -g deploy /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keysls -la /home/deploy/.sshtotal 12
drwx------ 2 deploy deploy 4096 Nov 5 11:48 .
drwxr-x--- 3 deploy deploy 4096 Nov 5 11:48 ..
-rw------- 1 deploy deploy 100 Nov 5 11:48 authorized_keysinstall은 폴더 만들기와 복사, 소유자와 권한 지정을 한 번에 처리합니다. sshd는 로그인을 받기 전에 사용자 파일의 권한과 소유자를 검사하므로(StrictModes), .ssh 폴더는 700, authorized_keys는 600으로 둡니다.
🔲 ssh deploy@203.0.113.10
지금 열린 root 창은 닫지 않고, 새 터미널 창에서 deploy로 접속되는지 먼저 확인합니다.
ssh deploy@203.0.113.10whoamideploy4️⃣ SSH root 로그인 차단
Ubuntu 24.04의 sshd_config는 맨 위 Include 줄에서 /etc/ssh/sshd_config.d/ 폴더의 파일을 먼저 불러오고, 같은 항목은 먼저 읽은 값이 적용됩니다. 그래서 설정을 바꾸기 전에 지금 적용된 값과 그 값이 들어 있는 파일부터 확인합니다.
/etc/ssh└─ sshd_config 맨 위 Include /etc/ssh/sshd_config.d/*.conf ├─ ① sshd_config.d/50-cloud-init.conf PasswordAuthentication no ├─ ② sshd_config.d/60-cloudimg-settings.conf PasswordAuthentication no └─ ③ sshd_config 42행 PermitRootLogin yes → no
🔲 sshd -T
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication) 'permitrootlogin yes
passwordauthentication nosudo grep -rn 'PasswordAuthentication' /etc/ssh/sshd_config.d//etc/ssh/sshd_config.d/60-cloudimg-settings.conf:1:PasswordAuthentication no
/etc/ssh/sshd_config.d/50-cloud-init.conf:1:PasswordAuthentication no비밀번호 로그인은 sshd_config.d 안 두 파일에서 이미 꺼져 있고, 바꿀 것은 본 파일의 root 로그인 한 줄입니다.
🔲 sed -i PermitRootLogin
sudo grep -n '^PermitRootLogin' /etc/ssh/sshd_config42:PermitRootLogin yessudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_configsudo grep -n '^PermitRootLogin' /etc/ssh/sshd_config42:PermitRootLogin no🔲 systemctl reload ssh
sudo sshd -tsudo systemctl reload sshsudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication) 'permitrootlogin no
passwordauthentication nosshd -t는 설정 문법을 검사하며 아무것도 나오지 않으면 오류가 없는 것입니다. 다시 읽은 뒤 새 창에서 deploy 접속이 그대로 되는 것을 확인하고, root로 접속해 거절되는지 봅니다.
ssh root@203.0.113.10root@203.0.113.10: Permission denied (publickey).키가 맞아도 root로는 들어갈 수 없고, 관리 작업은 deploy로 접속해 sudo로 합니다.
5️⃣ 우분투 방화벽 ufw
ufw는 Ubuntu의 기본 방화벽 도구이지만 처음에는 꺼져 있습니다. 켜는 순간 허용하지 않은 접속이 막히므로, SSH 허용 규칙을 먼저 넣고 마지막에 켭니다.
sudo ufw status verboseStatus: inactive🔲 ufw allow OpenSSH
sudo ufw app listAvailable applications:
OpenSSHsudo ufw allow OpenSSHRules updated
Rules updated (v6)sudo ufw allow 80/tcpRules updated
Rules updated (v6)sudo ufw allow 443/tcpRules updated
Rules updated (v6)sudo ufw show addedAdded user rules (see 'ufw status' for running firewall):
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcpOpenSSH는 22번 포트를 여는 프로필이고, 80과 443은 웹 서버에 사용하는 포트입니다. 규칙은 IPv4와 IPv6에 함께 들어갑니다.
🔲 ufw enable
sudo ufw enableCommand may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startupsudo ufw status verboseStatus: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6) 들어오는 접속은 기본으로 막히고, 허용한 세 포트만 열린 상태로 부팅 때도 켜집니다. 켠 뒤 새 창에서 deploy로 다시 접속해 규칙 번호를 확인합니다.
sudo ufw status numberedStatus: active
To Action From
-- ------ ----
[ 1] OpenSSH ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] OpenSSH (v6) ALLOW IN Anywhere (v6)
[ 5] 80/tcp (v6) ALLOW IN Anywhere (v6)
[ 6] 443/tcp (v6) ALLOW IN Anywhere (v6) 6️⃣ 우분투 시간대 설정
처음 시간대는 Etc/UTC입니다. 로그와 예약 작업의 시각을 서버 지역에 맞추기 위해, 싱가포르 지역에 만든 이 서버는 Asia/Singapore로 설정했습니다.
timedatectl Local time: Thu 2026-11-05 12:00:31 UTC
Universal time: Thu 2026-11-05 12:00:31 UTC
RTC time: Thu 2026-11-05 12:00:31
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no🔲 timedatectl list-timezones
timedatectl list-timezones | grep SingaporeAsia/Singapore🔲 timedatectl set-timezone
sudo timedatectl set-timezone Asia/Singaporetimedatectl Local time: Thu 2026-11-05 20:00:32 +08
Universal time: Thu 2026-11-05 12:00:32 UTC
RTC time: Thu 2026-11-05 12:00:32
Time zone: Asia/Singapore (+08, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no바뀌는 것은 Local time과 Time zone 두 줄이며, 시계 동기화(NTP)와 UTC 시각은 그대로입니다.
7️⃣ unattended upgrades 자동 보안 업데이트
Ubuntu는 보안 업데이트를 unattended-upgrades 패키지로 자동 설치하며, 이 패키지는 처음부터 설치되어 켜져 있습니다. 그래서 이 단계에서는 켜져 있는지와 무엇을 자동으로 설치하는지를 확인합니다.
🔲 dpkg-query -W
dpkg-query -W unattended-upgradesunattended-upgrades 2.9.1+nmu4ubuntu1systemctl is-enabled unattended-upgrades apt-daily.timer apt-daily-upgrade.timerenabled
enabled
enabled🔲 cat 20auto-upgrades
cat /etc/apt/apt.conf.d/20auto-upgradesAPT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";두 값의 1은 하루에 한 번이라는 뜻이며, 0으로 바꾸면 자동 업데이트가 꺼집니다. 무엇을 설치할지는 50unattended-upgrades 파일이 정합니다.
grep -vE '^[[:space:]]*(//|$)' /etc/apt/apt.conf.d/50unattended-upgradesUnattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::Package-Blacklist {
};
Unattended-Upgrade::DevRelease "auto";허용된 출처에 -security는 있고 -updates는 없어, 일반 업데이트는 자동으로 설치되지 않고 보안 업데이트만 설치됩니다. 일반 업데이트까지 자동으로 받으려면 이 파일에서 -updates 줄의 주석을 풉니다.
🔲 unattended-upgrade
sudo unattended-upgrade --dry-run --debugStarting unattended upgrades script
Allowed origins are: o=Ubuntu,a=noble, o=Ubuntu,a=noble-security, o=UbuntuESMApps,a=noble-apps-security, o=UbuntuESM,a=noble-infra-security같은 실행의 마지막 두 줄입니다.
No packages found that can be upgraded unattended and no pending auto-removals
The list of kept packages can't be calculated in dry-run mode.--dry-run은 설치하지 않고 자동 업데이트가 할 일만 계산합니다. 패키지 업데이트를 마친 뒤라 자동으로 설치할 패키지가 없다고 나왔습니다. 실제 실행 기록은 /var/log/unattended-upgrades/ 폴더에 남습니다.
sudo ls -l /var/log/unattended-upgrades/total 32
-rw-r--r-- 1 root root 0 Nov 5 20:00 unattended-upgrades-dpkg.log
-rw-r--r-- 1 root root 0 Nov 5 17:34 unattended-upgrades-shutdown.log
-rw-r--r-- 1 root root 29093 Nov 5 20:04 unattended-upgrades.log8️⃣ 우분투 스왑 메모리 설정
이 서버는 메모리가 1GB이고 처음에 스왑이 0입니다. 앱을 올리기 전에 2GB 스왑 파일을 만들고, 재부팅 뒤에도 켜지도록 /etc/fstab에 등록합니다.
free -h total used free shared buff/cache available
Mem: 961Mi 328Mi 161Mi 4.0Mi 631Mi 633Mi
Swap: 0B 0B 0Bdf -h /Filesystem Size Used Avail Use% Mounted on
/dev/vda1 24G 2.0G 22G 9% /🔲 fallocate -l 2G /swapfile
sudo fallocate -l 2G /swapfilesudo chmod 600 /swapfilels -lh /swapfile-rw------- 1 root root 2.0G Nov 5 20:04 /swapfile🔲 mkswap /swapfile
sudo mkswap /swapfileSetting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=0b43ccd8-5b4a-4048-9b84-eee12667b387🔲 swapon /swapfile
sudo swapon /swapfileswapon --showNAME TYPE SIZE USED PRIO
/swapfile file 2G 0B -2free -h total used free shared buff/cache available
Mem: 961Mi 328Mi 160Mi 4.0Mi 632Mi 632Mi
Swap: 2.0Gi 0B 2.0Gi🔲 tee -a /etc/fstab
swapon은 지금 켜는 것까지이며, 재부팅 뒤에도 켜지게 하려면 fstab에 한 줄을 더합니다.
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab/swapfile none swap sw 0 09️⃣ 우분투 서버 초기 설정 확인
설정이 재부팅 뒤에도 남는지 확인하면 우분투 초기 설정을 마칩니다.
🔲 systemctl reboot
sudo systemctl reboot🔲 uptime -p
재부팅 뒤 deploy로 다시 접속합니다.
uptime -pup 2 minutesswapon --showNAME TYPE SIZE USED PRIO
/swapfile file 2G 0B -2sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication) 'permitrootlogin no
passwordauthentication nosudo ufw status verboseStatus: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6) timedatectl | head -n 4 Local time: Thu 2026-11-05 20:06:35 +08
Universal time: Thu 2026-11-05 12:06:35 UTC
RTC time: Thu 2026-11-05 12:06:35
Time zone: Asia/Singapore (+08, +0800)systemctl is-active unattended-upgrades ssh.socketactive
active스왑, SSH 설정, 방화벽, 시간대, 자동 업데이트가 모두 재부팅 전과 같습니다. 이 서버에는 다음으로 Node.js 앱을 PM2와 Nginx로 올립니다.
🔢 FAQ & 추천 콘텐츠
ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.