웹·서버

Linux Errno 99 Cannot assign requested address 원인별 해결법

Linux 서버에서 프로그램을 실행하다 보면 다음과 같은 오류가 나타날 수 있습니다.

@@IBLE_CODE_BLOCK_0@@

또는

@@IBLE_CODE_BLOCK_1@@

이 오류는 대부분 프로그램이 현재 서버에 존재하지 않는 IP 주소에 bind하려 할 때 발생합니다.

Linux의 EADDRNOTAVAIL 오류에 해당하며, 포트가 이미 사용 중일 때 발생하는 Address already in use와는 원인이 다릅니다.

이 글에서는 서버 IP 확인부터 Secondary IP, 프로그램의 bind 설정 위치, 0.0.0.0, AWS·VPS, Docker, 재부팅 이후 발생하는 경우까지 순서대로 확인해보겠습니다.

아래 명령어는 sudo를 기본적으로 생략했습니다. Permission denied, Operation not permitted 등 권한 오류가 발생하면 해당 명령 앞에 sudo를 붙여 다시 실행하세요.

가장 먼저 서버의 실제 IP를 확인

ip -br addr로 서버 실제 IP와 인터페이스를 확인하는 화면
Errno 99 확인의 첫 단계는 프로그램 설정이 아니라 서버가 실제로 가진 IP를 보는 것입니다.

처음부터 네트워크 설정을 변경하지 말고 현재 서버에 어떤 IP가 실제로 존재하는지 확인합니다.

# 현재 서버의 IP와 네트워크 인터페이스 확인
ip -br addr

예를 들어 다음처럼 나올 수 있습니다.

lo       UNKNOWN    127.0.0.1/8
ens18    UP         192.168.1.10/24

여기서

입니다.

그런데 프로그램의 bind 설정이 다음과 같다면 문제가 될 수 있습니다.

192.168.1.100:8080

현재 서버에는 192.168.1.100이 없기 때문입니다.

더 자세하게 확인하려면 다음 명령을 사용합니다.

# 인터페이스별 상세 IP 정보 확인
ip addr show

예를 들어 다음처럼 표시될 수 있습니다.

2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP>
    inet 192.168.1.10/24 scope global ens18

여기서 실제 인터페이스 이름은 ens18, IPv4 주소는 192.168.1.10입니다.

인터넷 예제에는 흔히 eth0가 나오지만 서버에 따라 다음처럼 이름이 다를 수 있습니다.

eth0
ens3
ens18
ens160
enp0s3

따라서 특정 IP를 추가하거나 설정 파일을 수정할 때는 ip -br addr에 실제로 표시되는 자신의 인터페이스 이름을 사용해야 합니다.

  • ens18 → 네트워크 인터페이스 이름
  • 192.168.1.10/24 → 해당 인터페이스에 설정된 IP와 CIDR

Secondary IP가 사라진 경우

Secondary IP를 사용하고 있다면 해당 IP가 현재 서버에 남아 있는지 확인합니다.

실제로 할당받은 Secondary IP가 192.168.1.100, 인터페이스가 ens18, CIDR이 /24라면 다음처럼 임시로 추가할 수 있습니다.

# Secondary IP를 현재 인터페이스에 임시 추가
ip addr add 192.168.1.100/24 dev ens18

여기서 다음 값은 자신의 서버 환경에 맞게 변경해야 합니다.

192.168.1.100  → 실제 Secondary IP
/24            → 실제 CIDR
ens18          → 실제 인터페이스 이름

특히 /24도 예시일 뿐입니다. 서버 환경에 따라 /16, /24, /32 등 다른 값이 사용될 수 있습니다.

IP를 추가한 뒤 다시 확인합니다.

# Secondary IP가 정상적으로 추가됐는지 확인
ip -br addr

예상 결과는 다음과 비슷합니다.

ens18    UP    192.168.1.10/24 192.168.1.100/24

이제 문제가 발생했던 서비스를 다시 시작합니다.

# 실제 서비스 이름으로 변경
systemctl restart YOUR_SERVICE

서비스 상태도 확인합니다.

# 서비스 실행 상태 확인
systemctl status YOUR_SERVICE --no-pager

IP를 추가한 뒤 서비스가 정상적으로 실행된다면 Secondary IP가 서버에서 사라졌던 것이 원인일 가능성이 높습니다.

재부팅하면 IP가 다시 사라진다면

ip addr add로 추가한 IP는 현재 실행 중인 시스템에 임시로 적용되므로 재부팅하면 사라질 수 있습니다.

Ubuntu에서 Netplan을 사용하는 서버라면 먼저 실제 설정 파일을 확인합니다.

# 현재 서버의 Netplan 설정 파일 확인
ls -l /etc/netplan/

서버에 따라 다음처럼 파일명이 다를 수 있습니다.

00-installer-config.yaml
01-netcfg.yaml
50-cloud-init.yaml

인터넷 예제에 01-netcfg.yaml이 나온다고 그대로 사용하면 안 됩니다.

현재 서버의 /etc/netplan/에 실제로 존재하는 파일을 사용해야 합니다.

설정 파일을 수정하기 전에 백업합니다.

# 예시: 실제 Netplan 설정 파일 백업
cp /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.bak

실제 파일이 01-netcfg.yaml이라면 다음처럼 변경합니다.

cp /etc/netplan/01-netcfg.yaml /etc/netplan/01-netcfg.yaml.bak

설정 파일을 엽니다.

# 실제 Netplan 설정 파일 열기
nano /etc/netplan/50-cloud-init.yaml

예를 들어 DHCP를 사용하면서 ens18 인터페이스에 Secondary IP를 추가하는 구조는 다음과 비슷할 수 있습니다.

network:
  version: 2
  ethernets:
    ens18:
      dhcp4: true
      addresses:
        - 192.168.1.100/24

기존에 고정 IP를 사용 중이라면 기존 IP를 지우지 않고 Secondary IP를 추가합니다.

network:
  version: 2
  ethernets:
    ens18:
      addresses:
        - 192.168.1.10/24
        - 192.168.1.100/24
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 1.1.1.1

위 값 역시 예시입니다.

ens18           → 실제 인터페이스 이름
192.168.1.100   → 실제 Secondary IP
/24             → 실제 CIDR
192.168.1.1     → 실제 Gateway

기존 설정에 Gateway, DNS, 고정 IP 등이 있다면 기존 내용을 통째로 지우고 예제를 붙여 넣으면 안 됩니다.

현재 설정을 유지한 상태에서 필요한 IP만 추가해야 합니다.

Netplan은 YAML 형식이므로 들여쓰기도 정확해야 합니다.

설정을 수정했다면 바로 netplan apply를 실행하기보다 먼저 테스트합니다.

# 변경된 Netplan 설정을 시험 적용
netplan try

정상이라면 다음과 비슷한 메시지가 나옵니다.

Do you want to keep these settings?

Changes will revert in 120 seconds.
Press ENTER before the timeout to confirm the new configuration.

SSH 연결이 정상적으로 유지되고 설정에도 문제가 없다면 변경 사항을 확정합니다.

필요한 경우 다음 명령으로 적용할 수도 있습니다.

# Netplan 설정 적용
netplan apply

적용 후 IP를 확인합니다.

# Netplan 적용 후 IP 확인
ip -br addr

더 자세하게 확인하려면 다음 명령을 사용합니다.

# 특정 인터페이스에 적용된 IP 확인
ip addr show dev ens18

재부팅 후에도 IP가 유지되는지 확인하면 영구 설정이 제대로 되었는지 알 수 있습니다.

실제로 제가 서버 재부팅 이후 Secondary IP가 사라져 같은 오류를 겪었던 과정은 아래 글에서 따로 정리했습니다.

bind: cannot assign requested address 에러 해결법

프로그램의 bind 주소가 어디에 설정되어 있는지 확인

애플리케이션 설정 파일에서 bind 주소를 찾는 개발자 UI
서버 IP가 맞다면 다음은 서비스 설정 파일 안의 bind 주소를 실제 IP와 비교해야 합니다.

서버에 IP가 정상적으로 존재한다면 다음으로 확인할 것은 오류를 발생시키는 프로그램이 실제로 어느 IP에 bind하도록 설정되어 있는지입니다.

예를 들어 프로그램이 다음 주소를 사용하도록 되어 있다면

192.168.1.100:8080

서버에 192.168.1.100이 실제로 존재해야 합니다.

그렇다면 이 주소가 어디에 적혀 있는지 찾아야 합니다.

가장 빠른 순서는 오류를 낸 서비스 이름 확인 → systemd의 ExecStart 확인 → EnvironmentFile 확인 → 애플리케이션 설정 파일 검색입니다.

Nginx나 Apache처럼 웹서버 자체가 오류를 낸다면 listen이나 Listen 설정을 먼저 보고, 직접 만든 앱이라면 .env, 실행 스크립트, 애플리케이션 설정 파일에서 HOST, BIND, ADDRESS 같은 값을 찾으면 됩니다.

Nginx라면 현재 적용된 설정에서 listen 줄을 바로 검색합니다.

# Nginx listen 설정 확인
nginx -T 2>/dev/null | grep -n "listen"

Apache라면 설정 디렉터리에서 Listen 값을 검색합니다. 배포판에 따라 설정 경로가 /etc/apache2 또는 /etc/httpd일 수 있습니다.

# Apache Listen 설정 확인
grep -Rni "^Listen\|Listen " /etc/apache2 /etc/httpd 2>/dev/null

여기서 192.168.1.100:80처럼 특정 IP가 보이면, 그 IP가 ip -br addr 결과에 실제로 있는지 비교하면 됩니다.

아래 순서대로 확인하면 192.168.1.100:8080 같은 bind 주소가 어느 파일에서 나온 것인지 대부분 찾을 수 있습니다.

반면 프로그램의 용도에 따라 다음처럼 설정할 수도 있습니다.

0.0.0.0:8080

또는

127.0.0.1:8080

하지만 오류가 난다고 바로 0.0.0.0으로 바꾸기보다 현재 프로그램의 bind 설정이 어디에 들어 있는지 먼저 찾아야 합니다.

어떤 서비스가 오류를 내는지 먼저 확인

systemd로 실행되는 서비스라면 먼저 현재 상태를 확인합니다.

# 문제가 발생한 서비스 상태 확인
systemctl status YOUR_SERVICE

예를 들어 Nginx라면:

systemctl status nginx

직접 만든 애플리케이션이 myapp.service라면:

systemctl status myapp

서비스 이름을 정확히 모르겠다면 이름을 검색할 수 있습니다.

# 실행 중인 서비스 이름 검색
systemctl list-units --type=service | grep -i '프로그램이름'

서비스 시작에 실패했다면 로그도 확인합니다.

# 현재 부팅 이후 서비스 로그 확인
journalctl -u YOUR_SERVICE -b

로그에서 다음 메시지가 있는지 확인합니다.

Cannot assign requested address

로그를 읽을 권한이 없다면 해당 명령 앞에 sudo를 붙여 다시 실행합니다.

systemd 서비스의 실제 실행 명령 확인

많은 서버 프로그램은 systemd의 ExecStart에 실행 명령과 bind 주소가 들어 있습니다.

# 실제 systemd 서비스 설정 확인
systemctl cat YOUR_SERVICE

예를 들어 다음처럼 나올 수 있습니다.

[Service]
ExecStart=/usr/local/bin/myapp --host 192.168.1.100 --port 8080

이 경우 bind 주소는 다음 부분입니다.

--host 192.168.1.100
       ↑
       프로그램이 bind하려는 IP

ip -br addr 결과에 이 IP가 없다면 해당 설정 때문에 오류가 발생할 수 있습니다.

반대로 ExecStart에서 별도 설정 파일을 지정하는 경우도 있습니다.

ExecStart=/usr/local/bin/myapp -c /etc/myapp/config.conf

이 경우 실제 설정은 /etc/myapp/config.conf 안에 있을 가능성이 높습니다.

# systemd에서 확인한 실제 설정 파일 열기
nano /etc/myapp/config.conf

파일을 수정할 권한이 없다면 sudo를 붙여 다시 실행합니다.

EnvironmentFile도 확인

systemd 설정에 다음과 같은 항목이 있을 수도 있습니다.

EnvironmentFile=/etc/default/myapp

또는

EnvironmentFile=/etc/myapp/myapp.env

이 경우 Host와 Port가 Environment 파일에 들어 있을 수 있습니다.

# Environment 파일 내용 확인
cat /etc/default/myapp

예를 들어:

HOST=192.168.1.100
PORT=8080

처럼 되어 있다면 HOST에 지정된 IP가 현재 서버에 존재하는지 확인합니다.

설정 위치를 모르겠다면 IP 자체를 검색

프로그램이 사용하려는 IP는 알고 있지만 설정 파일 위치를 모른다면 해당 IP를 직접 검색할 수 있습니다.

예를 들어 문제가 되는 IP가 192.168.1.100이라면:

# /etc 아래에서 해당 IP가 들어 있는 설정 검색
grep -Rni "192.168.1.100" /etc 2>/dev/null

결과가 다음처럼 나오면:

/etc/myapp/config.conf:12:bind-address=192.168.1.100

/etc/myapp/config.conf의 12번째 줄에 bind 설정이 있다는 의미입니다.

웹 애플리케이션이라면 /var/www도 검색할 수 있습니다.

# /var/www 아래에서 해당 IP 검색
grep -Rni "192.168.1.100" /var/www 2>/dev/null

/opt 아래에 프로그램이 설치되어 있다면:

# /opt 아래에서 해당 IP 검색
grep -Rni "192.168.1.100" /opt 2>/dev/null

서버 전체 /를 검색하는 것도 가능하지만 파일이 많은 서버에서는 시간이 오래 걸릴 수 있으므로 /etc, /var/www, /opt, 실제 애플리케이션 디렉터리부터 확인하는 것이 좋습니다.

Nginx에서 bind 주소 확인

Nginx라면 listen 설정을 확인합니다.

현재 적용되는 설정에서 listen 항목을 찾습니다.

# Nginx의 현재 listen 설정 확인
nginx -T 2>&1 | grep -n "listen"

일반적으로 다음 경로에 설정이 있습니다.

/etc/nginx/nginx.conf
/etc/nginx/conf.d/
/etc/nginx/sites-enabled/

예를 들어 다음처럼 되어 있다면:

listen 192.168.1.100:80;

Nginx가 192.168.1.100이라는 특정 IP에 직접 bind하려는 것입니다.

그런데 해당 IP가 서버에 없다면 문제가 발생할 수 있습니다.

특정 IP에만 bind할 필요가 없다면 서버 구성에 따라 다음처럼 사용할 수 있습니다.

listen 80;

설정을 변경한 뒤에는 문법부터 검사합니다.

# Nginx 설정 문법 검사
nginx -t

정상이라면 설정을 다시 불러옵니다.

# Nginx 설정 다시 불러오기
systemctl reload nginx

Apache에서 bind 주소 확인

Ubuntu의 Apache에서는 주로 다음 경로를 확인합니다.

/etc/apache2/ports.conf
/etc/apache2/sites-enabled/

현재 Listen 설정을 검색합니다.

# Apache의 Listen 설정 검색
grep -Rni "Listen" /etc/apache2

예를 들어:

Listen 192.168.1.100:80

으로 되어 있는데 서버에 해당 IP가 없다면 문제가 될 수 있습니다.

모든 인터페이스의 80 포트에서 연결을 받으려는 일반적인 구성이라면 다음과 같은 형태를 사용할 수 있습니다.

Listen 80

변경 후에는 설정 문법을 검사합니다.

# Apache 설정 문법 검사
apachectl configtest

정상이라면 설정을 다시 불러옵니다.

systemctl reload apache2

Python·Gunicorn·Uvicorn에서 확인

Python 웹 애플리케이션은 실행 명령에 bind 주소가 직접 들어 있는 경우가 많습니다.

Gunicorn 예:

gunicorn --bind 192.168.1.100:8000 app:app

Uvicorn 예:

uvicorn main:app --host 192.168.1.100 --port 8000

systemd로 실행한다면 다음 명령으로 실제 실행 옵션을 확인합니다.

# Python 애플리케이션의 실제 실행 명령 확인
systemctl cat YOUR_SERVICE

특정 IP를 사용할 필요가 없다면 애플리케이션 구조에 따라 Gunicorn은:

--bind 0.0.0.0:8000

Uvicorn은:

--host 0.0.0.0

처럼 사용할 수 있습니다.

반대로 Nginx를 Reverse Proxy로 사용하고 외부에서 Python 애플리케이션에 직접 접근할 필요가 없다면:

127.0.0.1:8000

처럼 localhost에만 bind하는 방식이 더 적절할 수 있습니다.

Node.js에서 확인

Node.js에서는 코드나 .env 파일에서 Host를 지정하는 경우가 많습니다.

예:

app.listen(3000, '192.168.1.100');

또는 .env 파일:

HOST=192.168.1.100
PORT=3000

현재 프로젝트에서 해당 IP가 어디에 사용되는지 검색합니다.

# 현재 프로젝트에서 문제가 되는 IP 검색
grep -Rni "192.168.1.100" . 2>/dev/null

.env 같은 숨김 파일이 있는지도 확인합니다.

# 숨김 파일을 포함해 현재 디렉터리 확인
ls -la

HOST 값이 있다면 현재 서버에 실제로 존재하는 IP인지 확인합니다.

MySQL·Redis·PostgreSQL이라면

프로그램마다 bind 설정의 이름도 다릅니다.

설정 디렉터리를 알고 있다면 다음처럼 관련 키워드를 검색할 수도 있습니다.

# 특정 프로그램의 설정 디렉터리에서 bind 관련 설정 검색
grep -RniE "bind|bind-address|listen|listen_addresses|host" /etc/프로그램이름 2>/dev/null

/etc/프로그램이름 부분은 실제 설정 디렉터리로 변경해야 합니다.

어떤 주소로 변경해야 할까?

현재 bind 설정을 찾았다면 서비스의 역할에 따라 주소를 결정합니다.

예를 들어 Nginx가 외부 요청을 받고 내부 애플리케이션으로 전달하는 구조라면:

인터넷
  ↓
Nginx :80 / :443
  ↓
127.0.0.1:8000
  ↓
애플리케이션

내부 애플리케이션은 127.0.0.1에만 bind해도 됩니다.

반대로 애플리케이션 자체가 외부 요청을 직접 받아야 한다면 0.0.0.0 또는 실제 서버 IP가 필요할 수 있습니다.

오류가 난다는 이유만으로 무조건 0.0.0.0으로 변경하면 안 됩니다.

0.0.0.0은 모든 IPv4 인터페이스에서 연결을 받을 수 있으므로 기존에 내부에서만 접근 가능했던 서비스가 외부에 노출될 수도 있습니다.

변경 후 실제 Listen 주소 확인

설정을 수정했다면 서비스를 다시 시작하거나 reload합니다.

# 서비스 재시작
systemctl restart YOUR_SERVICE

그다음 현재 어느 주소에서 Listen하고 있는지 확인합니다.

# TCP Listen 주소와 포트 확인
ss -lnt

프로세스 정보까지 함께 확인하려면:

# Listen 포트와 프로세스 확인
ss -lntup

예를 들어:

LISTEN 0 128 127.0.0.1:8000 0.0.0.0:*

이라면 localhost의 8000 포트에서만 Listen하는 상태입니다.

다음처럼 나오면:

LISTEN 0 128 0.0.0.0:8000 0.0.0.0:*

모든 IPv4 인터페이스의 8000 포트에서 Listen 중입니다.

특정 IP라면:

LISTEN 0 128 192.168.1.100:8000 0.0.0.0:*

처럼 표시됩니다.

정리하면 bind 설정은 다음 순서로 확인하면 됩니다.

오류가 발생한 서비스 확인
        ↓
systemctl cat으로 실행 명령 확인
        ↓
ExecStart / EnvironmentFile 확인
        ↓
설정 파일에서 bind·listen·host 확인
        ↓
모르면 IP 자체를 grep으로 검색
        ↓
실제 서버 IP와 비교
        ↓
설정 수정
        ↓
서비스 재시작
        ↓
ss -lnt로 최종 확인
프로그램 주로 확인하는 설정
Nginx listen
Apache Listen
Gunicorn --bind
Uvicorn --host
Node.js HOST, app.listen()
MySQL bind-address
Redis bind
PostgreSQL listen_addresses
Bind 주소 일반적인 의미
192.168.1.100:8080 지정한 특정 IP에서만 연결
0.0.0.0:8080 모든 IPv4 인터페이스에서 연결
127.0.0.1:8080 같은 서버 내부에서만 연결

AWS·VPS에서는 Public IP와 Private IP를 구분

클라우드 서버의 Public IP와 Private IP 차이 다이어그램
클라우드 서버에서는 Public IP가 서버 내부 인터페이스에 직접 붙어 있지 않은 경우가 많습니다.

클라우드 서버에서는 관리 화면에 표시되는 Public IP와 Linux 내부에서 실제로 사용하는 IP가 다를 수 있습니다.

예를 들어 AWS EC2 관리 화면에는 다음과 같은 Public IP가 있을 수 있습니다.

54.xxx.xxx.xxx

하지만 서버 안에서:

# Linux 서버가 실제로 가지고 있는 IP 확인
ip -br addr

를 실행하면:

eth0    UP    10.0.1.25/24

처럼 Private IP만 표시될 수 있습니다.

구조를 단순하게 보면 다음과 같습니다.

인터넷
   ↓
Public IP
54.xxx.xxx.xxx
   ↓
클라우드 NAT
   ↓
Private IP
10.0.1.25
   ↓
Linux 서버

이런 환경에서 프로그램에 Public IP를 직접 지정해:

54.xxx.xxx.xxx:8080

로 bind하려 하면 Linux 입장에서는 해당 IP가 자신의 로컬 인터페이스에 없기 때문에 Cannot assign requested address가 발생할 수 있습니다.

서비스 구조에 따라:

0.0.0.0:8080

또는 실제 Private IP:

10.0.1.25:8080

를 사용해야 할 수 있습니다.

Secondary IP를 사용하는 VPS나 클라우드 서버라면 Linux에서 IP를 추가하기 전에 해당 IP가 실제로 서버 또는 네트워크 인터페이스에 할당된 주소인지 먼저 확인해야 합니다.

Docker에서 발생한다면 Host IP 확인

Docker 컨테이너와 호스트 IP 바인딩 차이 설명 이미지
Docker에서는 컨테이너 내부에 없는 Host IP로 직접 bind하면 같은 오류가 날 수 있습니다.

Docker Compose에서 특정 Host IP를 지정해 놓은 경우에도 Cannot assign requested address가 발생할 수 있습니다.

예를 들어 다음과 같이 설정되어 있다고 가정해보겠습니다.

services:
  web:
    ports:
      - "192.168.1.100:8080:80"

각 값의 의미는 다음과 같습니다.

192.168.1.100 : 8080 : 80
    Host IP     Host   Container
                Port     Port

즉 Docker는 Host 서버의 192.168.1.100 주소에 8080 포트를 열려고 합니다.

먼저 Docker Host에 해당 IP가 실제로 존재하는지 확인합니다.

# Docker Host의 실제 IP 확인
ip -br addr

192.168.1.100이 결과에 없다면 Compose에 지정한 Host IP를 다시 확인해야 합니다.

특정 Host IP에만 bind할 필요가 없다면 다음처럼 Host IP를 생략할 수 있습니다.

ports:
  - "8080:80"

반대로 외부에는 노출하지 않고 Host 내부에서만 접근시키려면:

ports:
  - "127.0.0.1:8080:80"

처럼 localhost에만 bind할 수 있습니다.

Docker에서 이 오류가 발생한다면 Compose 파일의 Host IP와 ip -br addr 결과를 먼저 비교하는 것이 가장 빠릅니다.

재부팅할 때만 오류가 발생한다면

systemd 서비스 시작 순서와 network-online target 타임라인
부팅 직후에만 실패한다면 서비스가 네트워크 준비보다 먼저 시작되는지 봐야 합니다.

설치 직후에는 정상적으로 작동하는데 서버를 재부팅한 뒤에만 오류가 발생한다면 먼저 IP부터 다시 확인합니다.

# 재부팅 후 현재 서버의 IP 확인
ip -br addr

재부팅 전에는 있던 Secondary IP가 사라졌다면 Netplan 등 영구 네트워크 설정을 확인해야 합니다.

반대로 IP는 정상적으로 존재하는데 부팅할 때만 서비스가 실패하고, 나중에 직접 재시작하면 정상 작동하는 경우도 있습니다.

이 경우 서비스가 네트워크보다 먼저 시작되는지 확인해볼 수 있습니다.

먼저 서비스 상태를 확인합니다.

# 서비스 상태 확인
systemctl status YOUR_SERVICE

현재 부팅 이후 로그도 확인합니다.

# 현재 부팅 이후 해당 서비스 로그 확인
journalctl -u YOUR_SERVICE -b

로그에서 다음 오류가 발생한 시점을 확인합니다.

Cannot assign requested address

그런데 부팅이 끝난 뒤 다음 명령으로 서비스를 다시 시작했을 때:

# 부팅 이후 서비스 수동 재시작
systemctl restart YOUR_SERVICE

정상적으로 실행된다면 네트워크 준비 시점과 서비스 시작 순서도 확인해볼 필요가 있습니다.

systemd 서비스에서는 상황에 따라 다음과 같은 설정을 사용할 수 있습니다.

[Unit]
Wants=network-online.target
After=network-online.target

Wants=network-online.target은 네트워크가 온라인 상태가 되는 target을 함께 활성화하도록 요청하고, After=network-online.target은 해당 target 이후에 서비스를 시작하도록 순서를 지정합니다.

하지만 Cannot assign requested address 오류가 발생했다고 무조건 이 설정부터 추가하면 안 됩니다.

다음 순서로 확인하는 것이 좋습니다.

1. 서버에 해당 IP가 실제로 존재하는지 2. 재부팅 이후 Secondary IP가 사라지는지 3. 프로그램의 bind 주소가 올바른지 4. IP는 정상인데 부팅할 때만 실패하는지 5. 직접 restart하면 정상 작동하는지

마지막 두 조건에 해당한다면 서비스 시작 순서를 확인해볼 수 있습니다.

Address already in use와 혼동하지 않기

Cannot assign requested address와 Address already in use 비교표
Cannot assign requested address는 없는 IP 문제이고, Address already in use는 포트 충돌 문제입니다.

Cannot assign requested addressAddress already in use는 둘 다 프로그램이 socket을 bind하는 과정에서 발생할 수 있지만 원인은 다릅니다.

예를 들어 다음 오류가 나온다면:

Address already in use

현재 글에서 다루는 IP 문제보다는 포트 충돌을 먼저 확인합니다.

# 현재 Listen 중인 포트와 프로세스 확인
ss -lntup

특정 포트만 찾으려면 예를 들어 8080 포트의 경우:

# 8080 포트를 사용하는 프로세스 확인
ss -lntup | grep ':8080'

프로세스 정보가 표시되지 않는다면 이때 sudo를 붙여 다시 확인할 수 있습니다.

반대로:

Permission denied

가 나온다면 IP보다 권한 문제를 먼저 확인해야 합니다.

특히 Linux에서는 일반 사용자 프로세스가 80, 443 등 1024 미만의 privileged port에 직접 bind하려 할 때 권한 문제가 발생할 수 있습니다.

따라서 오류 메시지가 정확히:

Cannot assign requested address

라면 가장 먼저 다음 명령부터 실행합니다.

# 현재 서버가 실제로 가지고 있는 IP 확인
ip -br addr

그리고 프로그램이 bind하려는 IP가 현재 서버에 실제로 존재하는지 확인합니다.

그다음 프로그램의 bind 설정 위치를 찾아 실제 IP와 비교하고, Secondary IP·클라우드 Public IP·Docker Host IP·재부팅 후 서비스 시작 순서를 차례대로 확인하면 대부분 원인을 좁힐 수 있습니다.

결국 Errno 99: Cannot assign requested address에서 가장 중요한 질문은 하나입니다.

프로그램이 사용하려는 IP 주소를 현재 이 서버가 실제로 가지고 있는가?

오류 주요 원인 먼저 확인
Cannot assign requested address 서버에 없는 IP 사용 ip -br addr
Address already in use 주소 또는 포트가 이미 사용 중 ss -lntup
Permission denied 포트 또는 실행 권한 문제 사용자·권한

확인할 점

서버 네트워크 설정은 배포 환경마다 다릅니다. 예시 IP, CIDR, 인터페이스 이름, Gateway를 그대로 복사하지 말고 반드시 현재 서버의 실제 값을 확인한 뒤 적용해야 합니다.

자주 묻는 질문

Errno 99 Cannot assign requested address는 포트 충돌인가요?

대부분 포트 충돌이 아니라 현재 서버에 없는 IP 주소로 bind하려 할 때 발생합니다. 포트 충돌은 보통 Address already in use로 표시됩니다.

가장 먼저 어떤 명령어를 실행해야 하나요?

먼저 ip -br addr 명령으로 현재 서버가 실제로 가지고 있는 IP와 인터페이스 이름을 확인하는 것이 좋습니다.

AWS나 VPS에서는 Public IP로 bind하면 안 되나요?

대부분 클라우드 서버 내부에는 Private IP만 직접 설정되어 있고 Public IP는 외부에서 매핑됩니다. 프로그램은 보통 Private IP나 0.0.0.0에 bind해야 합니다.

Docker 컨테이너 안에서 Host IP로 bind해도 되나요?

컨테이너 내부에 존재하지 않는 Host IP로 직접 bind하면 실패할 수 있습니다. 컨테이너 안에서는 보통 0.0.0.0으로 listen하고 포트 매핑으로 외부에 노출합니다.

재부팅할 때만 오류가 나면 무엇을 봐야 하나요?

IP가 실제로 존재하는데 부팅 직후에만 실패한다면 네트워크 준비보다 서비스가 먼저 시작되는지 확인하고 systemd의 network-online.target 적용 여부를 검토할 수 있습니다.