Nginx 가상 호스트: 하나의 서버에서 여러 웹사이트 호스팅하기

Nginx 가상 호스트(서버 블록)의 강력한 기능을 활용하여 단일 서버에서 여러 웹사이트나 서브도메인을 효율적으로 호스팅하는 방법을 알아보세요. 이 가이드는 디렉토리 설정, 설정 파일 생성, 서버 블록 활성화, Nginx 테스트를 포함한 포괄적인 단계별 튜토리얼을 제공합니다. 서브도메인, 기본 서버 블록, HTTPS 통합, 전용 로깅에 대한 모범 사례를 배울 수 있습니다. 실용적인 예제와 필수 문제 해결 팁을 통해 멀티 사이트 Nginx 호스팅을 마스터하고 리소스 사용을 최적화하며 웹 서버 관리를 간소화하세요.

Nginx 가상 호스트: 하나의 서버에서 여러 웹사이트 호스팅하기

하나의 서버에서 여러 개의 소규모 사이트를 운영하는 것은 Nginx의 일반적인 작업입니다. 회사 사이트, 문서 사이트, 스테이징 앱, 고객 포털이 모두 동일한 머신에서 호스팅될 수 있습니다. Nginx는 server 블록을 사용하여 이를 분리합니다. Apache 사용자들은 종종 이와 동일한 개념을 가상 호스트라고 부르므로, 튜토리얼이나 호스팅 패널에서 두 용어를 모두 볼 수 있습니다.

중요한 부분은 간단합니다. Nginx는 포트, IP 주소 및 Host 헤더를 확인한 후 일치하는 server 블록을 선택합니다. 잘못된 사이트가 로드된다면, 문제는 대개 신비롭지 않습니다. 일반적으로 누락된 DNS 레코드, server_name의 오타, 요청을 가로채는 기본 서버, 또는 동일한 이름을 주장하는 두 개의 파일 때문입니다.

Nginx 서버 블록(가상 호스트) 이해하기

핵심적으로, Nginx 서버 블록은 Nginx 설정 파일(nginx.conf 또는 포함된 파일) 내에 정의된 설정 지시문입니다. 각 server 블록은 특정 가상 호스트에 대한 설정을 정의하며, 특정 도메인 또는 도메인 집합에 대한 요청에 Nginx가 어떻게 응답해야 하는지를 지정합니다. Nginx는 listen 지시문을 사용하여 수신할 IP 주소와 포트를 지정하고, server_name 지시문을 사용하여 이 서버 블록이 응답해야 하는 도메인 이름 또는 호스트 이름을 식별합니다.

요청이 들어오면 Nginx는 HTTP 요청의 Host 헤더를 검사하여 설정된 서버 블록의 server_name 지시문과 비교합니다. 그런 다음 일치하는 서버 블록에 정의된 콘텐츠를 제공합니다. 일치하는 server_name이 없으면 Nginx는 일반적으로 기본 서버 블록(첫 번째 server 블록 또는 명시적으로 default_server로 표시된 블록)으로 대체됩니다.

사전 요구 사항

시작하기 전에 다음 사항이 준비되었는지 확인하세요.

  1. Nginx 설치됨: Nginx가 서버에 설치되어 실행 중이어야 합니다. 설치되지 않은 경우 일반적으로 시스템의 패키지 관리자를 통해 설치할 수 있습니다(예: Ubuntu/Debian의 경우 sudo apt update && sudo apt install nginx, CentOS/RHEL의 경우 sudo yum install nginx).
  2. 도메인 이름: 호스팅하려는 최소 두 개의 도메인 이름(예: example1.comexample2.com) 또는 서브도메인(예: blog.example.comapp.example.com)이 필요합니다. 이러한 도메인의 DNS A/AAAA 레코드는 서버의 공인 IP 주소를 가리켜야 합니다.
  3. 기본 디렉토리 구조: 웹사이트 파일이 위치할 계획이 있어야 합니다. 일반적인 관행은 /var/www/yourdomain.com/html입니다.
  4. Sudo 권한: Nginx 설정 파일을 수정하려면 sudo 액세스 권한이 필요합니다.

단계별 설정 가이드

두 개의 가상 호스트를 설정해 보겠습니다: example1.comexample2.com.

1단계: 웹사이트 디렉토리 구조 생성

먼저 각 웹사이트의 루트 디렉토리를 생성합니다. 여기에 HTML, CSS, JavaScript 및 기타 정적 파일이 저장됩니다. 일반적인 위치는 /var/www/입니다.

sudo mkdir -p /var/www/example1.com/html
sudo mkdir -p /var/www/example2.com/html

# 소유권을 사용자로 설정(USER를 사용자 이름으로 대체)하여 편집 가능하게 함
sudo chown -R $USER:$USER /var/www/example1.com/html
sudo chown -R $USER:$USER /var/www/example2.com/html

# 웹 서버에 읽기 권한 설정
sudo chmod -R 755 /var/www

다음으로, 각 디렉토리에 간단한 index.html 파일을 생성하여 설정을 테스트합니다:

/var/www/example1.com/html/index.html의 경우:

<!-- /var/www/example1.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Example1.com에 오신 것을 환영합니다!</title>
</head>
<body>
    <h1>성공! 이것은 Example1.com입니다.</h1>
    <p>이 가상 호스트가 올바르게 작동하고 있습니다.</p>
</body>
</html>

/var/www/example2.com/html/index.html의 경우:

<!-- /var/www/example2.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Example2.com에 오신 것을 환영합니다!</title>
</head>
<body>
    <h1>성공! 이것은 Example2.com입니다.</h1>
    <p>이 가상 호스트도 작동하고 있습니다!</p>
</body>
</html>

2단계: Nginx 서버 블록 설정 파일 생성

Nginx는 일반적으로 /etc/nginx/sites-enabled/ 디렉토리의 파일에서 서버 블록 설정을 로드합니다. 이러한 파일은 일반적으로 /etc/nginx/sites-available/에 저장된 설정에 대한 심볼릭 링크입니다. 이 분리를 통해 아직 활성화되지 않은 설정을 저장하거나 사이트를 쉽게 활성화/비활성화할 수 있습니다.

example1.com에 대한 새 설정 파일을 생성합니다:

sudo nano /etc/nginx/sites-available/example1.com.conf

다음 내용을 추가합니다:

# /etc/nginx/sites-available/example1.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/example1.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example1.com www.example1.com;

    location / {
        try_files $uri $uri/ =404;
    }

    access_log /var/log/nginx/example1.com_access.log;
    error_log /var/log/nginx/example1.com_error.log;
}

지시문 설명:

  • listen 80;: Nginx가 포트 80(표준 HTTP)에서 수신합니다. listen [::]:80;은 IPv6용입니다.
  • root /var/www/example1.com/html;: 이 서버 블록의 문서 루트를 지정합니다. Nginx는 이 디렉토리 내에서 파일을 찾습니다.
  • index index.html ...;: 디렉토리가 요청될 때(예: 누군가 example1.com/을 방문할 때) Nginx가 제공해야 하는 기본 파일을 정의합니다.
  • server_name example1.com www.example1.com;: 이것은 중요합니다. Nginx에게 example1.com 또는 www.example1.com에 대한 요청에 이 서버 블록의 설정을 사용하여 응답하도록 지시합니다.
  • location / { ... }: 특정 URI에 대한 요청을 처리하는 방법을 정의하는 블록입니다. try_files는 파일을 직접 제공하려고 시도하고($uri), 그 다음 디렉토리($uri/), 마지막으로 404 Not Found 오류를 반환합니다.
  • access_logerror_log: 이 특정 사이트에 대한 별도의 로그 파일을 지정합니다. 이는 더 쉬운 디버깅 및 분석을 위한 좋은 방법입니다.

이제 example2.com에 대한 유사한 설정 파일을 생성합니다:

sudo nano /etc/nginx/sites-available/example2.com.conf

다음 내용을 추가합니다:

# /etc/nginx/sites-available/example2.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/example2.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example2.com www.example2.com;

    location / {
        try_files $uri $uri/ =404;
    }

    access_log /var/log/nginx/example2.com_access.log;
    error_log /var/log/nginx/example2.com_error.log;
}

3단계: 서버 블록 활성화

이러한 설정을 활성화하려면 sites-available 디렉토리에서 sites-enabled 디렉토리로 심볼릭 링크를 생성합니다. 이는 Nginx가 시작될 때 이러한 파일을 포함하도록 지시합니다.

sudo ln -s /etc/nginx/sites-available/example1.com.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example2.com.conf /etc/nginx/sites-enabled/

4단계: Nginx 설정 테스트

리로드하기 전에 Nginx 설정에 구문 오류가 있는지 테스트하는 것이 중요합니다. 이렇게 하면 오타로 인해 Nginx가 다시 시작되지 않는 것을 방지할 수 있습니다.

sudo nginx -t

성공을 나타내는 다음과 유사한 출력이 표시되어야 합니다:

ginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

오류가 표시되면 해당 설정 파일에서 수정하고 sudo nginx -t를 다시 실행하여 통과할 때까지 반복합니다.

5단계: Nginx 다시 시작

Nginx를 다시 시작하거나 리로드하여 새 설정을 적용합니다. reload는 일반적으로 활성 연결을 끊지 않고 새 설정을 로드할 수 있으므로 선호됩니다.

sudo systemctl reload nginx
# 또는 리로드가 작동하지 않거나 새 설치의 경우:
sudo systemctl restart nginx

6단계: DNS 레코드 업데이트

example1.com, www.example1.com, example2.comwww.example2.com에 대한 DNS A 레코드가 모두 Nginx 서버의 IP 주소를 가리키는지 확인하세요. 올바른 DNS 항목이 없으면 브라우저가 웹사이트를 찾을 수 없습니다.

DNS 전파가 완료되면(몇 분에서 몇 시간까지 걸릴 수 있음) 웹 브라우저에서 http://example1.comhttp://example2.com을 방문하여 각각의 index.html 페이지를 볼 수 있어야 합니다.

고급 시나리오 및 모범 사례

서브도메인 호스팅

서브도메인(예: blog.example.com, shop.example.com) 호스팅은 별도의 도메인 호스팅과 정확히 동일하게 작동합니다. 서브도메인을 server_name으로 사용하여 새 서버 블록을 정의하기만 하면 됩니다.

blog.example.com의 예:

# /etc/nginx/sites-available/blog.example.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/blog.example.com/html;
    index index.html;

    server_name blog.example.com;

    location / {
        try_files $uri $uri/ =404;
    }
}

디렉토리(/var/www/blog.example.com/html)를 생성하고, index.html을 생성하고, 심볼릭 링크를 생성하고, Nginx를 리로드하는 것을 잊지 마세요.

기본 서버 블록

서버의 다른 server_name 지시문과 일치하지 않는 도메인 이름에 대한 요청을 처리하는 기본 서버 블록을 두는 것이 좋습니다. 이렇게 하면 알 수 없는 요청이 Nginx가 찾은 "첫 번째" 가상 호스트에 의해 제공되는 것을 방지하거나 일반적인 "사이트를 찾을 수 없음" 페이지를 제공할 수 있습니다.

일반적으로 nginx.conf 또는 sites-enabled의 첫 번째 server 블록이 암시적으로 기본값입니다. default_server를 사용하여 명시적으로 설정할 수 있습니다:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name _;
    # 밑줄 `_`은 실제 요청과 일치하지 않는 존재하지 않는 도메인 이름입니다.
    # localhost를 사용할 수도 있습니다.

    root /var/www/default_site/html;
    index index.html;

    location / {
        return 444; # 알 수 없는 호스트에 대해 Nginx 특정 444 오류(응답 없음) 반환
        # 또는 일반 랜딩 페이지 제공:
        # try_files $uri $uri/ =404;
    }
}

경고: default_server 블록을 정의하는 경우 지정된 listen 포트에서 하나의 server 블록만 default_server 플래그를 가지고 있는지 확인하십시오. 그렇지 않으면 Nginx가 경고를 기록합니다.

HTTPS(SSL/TLS)로 가상 호스트 보호

프로덕션 웹사이트의 경우 HTTPS를 활성화하는 것이 필수적입니다. 여기에는 SSL/TLS 인증서(예: Certbot을 사용한 Let's Encrypt)를 획득하고 Nginx가 인증서와 함께 포트 443에서 수신하도록 구성하는 것이 포함됩니다.

일반적인 HTTPS 서버 블록은 다음과 같습니다(인증서 획득 후):

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example1.com www.example1.com;

    root /var/www/example1.com/html;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/example1.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example1.com/privkey.pem;

    # 기타 SSL 설정 포함(암호, 프로토콜 등)
    include /etc/nginx/snippets/ssl-params.conf;

    location / {
        try_files $uri $uri/ =404;
    }
}

# 선택 사항: 이 도메인에 대한 HTTP에서 HTTPS로 리디렉션
server {
    listen 80;
    listen [::]:80;
    server_name example1.com www.example1.com;
    return 301 https://$host$request_uri;
}

모든 트래픽을 HTTPS로 리디렉션하는 전용 HTTP 서버 블록을 두는 것이 일반적입니다.

Certbot을 사용하는 경우 이러한 블록을 자동으로 생성하거나 편집할 수 있습니다. 편리하지만 결과 파일을 여전히 읽어야 합니다. 자동화된 인증서 도구는 때때로 사용자가 직접 선택하지 않았을 위치에 리디렉션 로직을 추가하며, 중복 리디렉션은 문제 해결을 더 어렵게 만들 수 있습니다.

각 사이트에 대한 로깅

예제에서 보여준 것처럼 각 가상 호스트에 대해 별도의 access_logerror_log 파일을 사용하는 것이 모범 사례입니다. 이렇게 하면 결합된 로그를 뒤지지 않고 개별 웹사이트의 문제를 디버깅하고 트래픽을 분석하는 것이 훨씬 쉬워집니다.

설정 파일 구조

대규모 배포의 경우 Nginx 설정 파일을 다음과 같이 구성하는 것을 고려하십시오:

  • nginx.conf: 기본 설정, conf.d/*.confsites-enabled/*를 포함합니다.
  • conf.d/: 일반적인 서버 전체 설정(예: Gzip, 캐싱).
  • snippets/: 재사용 가능한 Nginx 설정 스니펫(예: SSL 매개변수, 공통 location 블록).
  • sites-available/: 각 웹사이트에 대한 개별 server 블록.
  • sites-enabled/: sites-available/의 활성 설정에 대한 심볼릭 링크.

일반적인 문제 해결

  • 403 Forbidden 오류: 이는 일반적으로 Nginx가 웹사이트 파일이나 디렉토리에 대한 읽기 권한이 없음을 의미합니다. 파일 및 디렉토리 권한을 다시 확인하고(예: sudo chmod -R 755 /var/www/yourdomain.com/html), Nginx 사용자(일반적으로 www-data 또는 nginx)가 읽을 수 있는지 확인하십시오.
  • 404 Not Found 오류: 서버 블록의 root 지시문이 올바른 디렉토리를 가리키고 index.html 파일이 해당 위치에 있는지 확인하십시오. 또한 try_files가 올바르게 구성되었는지 확인하십시오.
  • 잘못된 사이트 로드: 이는 종종 server_name 지시문에 문제가 있음을 나타냅니다. server_name이 액세스하려는 도메인 이름( www. 또는 서브도메인 포함)과 정확히 일치하는지 확인하십시오. 또한 DNS 레코드를 확인하십시오.
  • Nginx 시작/리로드 실패: Nginx를 리로드하거나 다시 시작하기 전에 항상 sudo nginx -t를 사용하여 설정을 테스트하십시오. 오류 메시지는 구문 오류가 발생한 줄과 파일을 정확히 알려줍니다.
  • DNS 문제: IP 주소로는 사이트에 액세스할 수 있지만 도메인 이름으로는 액세스할 수 없는 경우 거의 확실히 DNS 문제입니다. dig 또는 nslookup을 사용하여 도메인의 A 레코드가 올바른 서버 IP를 가리키는지 확인하십시오.

DNS가 준비되기 전에 테스트

공개 DNS가 준비될 때까지 기다리지 않고 Nginx 측을 테스트할 수 있습니다. 사용자 정의 Host 헤더로 요청을 보낼 수 있습니다:

curl -H "Host: example1.com" http://203.0.113.10/
curl -H "Host: example2.com" http://203.0.113.10/

203.0.113.10을 서버 IP로 바꾸십시오. 각 명령이 올바른 테스트 페이지를 반환하면 서버 블록 일치가 작동하는 것입니다. 두 명령이 동일한 페이지를 반환하면 두 파일이 모두 활성화되어 있는지, server_name이 올바른지, 기본 블록이 요청을 가로채고 있는지 확인하십시오.

HTTPS의 경우 TLS가 HTTP Host 헤더가 처리되기 전에 SNI를 사용하기 때문에 테스트가 약간 다릅니다:

curl --resolve example1.com:443:203.0.113.10 https://example1.com/

이 명령은 curl에게 서버 IP에 연결하도록 지시하면서 TLS 및 HTTP에 example1.com을 계속 사용하도록 합니다. DNS를 변경하기 전에 새 HTTPS 가상 호스트를 테스트하는 가장 빠른 방법 중 하나입니다.

유지 관리 가능한 멀티 사이트 패턴

소수의 정적 사이트의 경우 위의 예제로 충분합니다. 여러 애플리케이션을 호스팅하는 경우 반복을 줄이고 진정으로 공유되는 부분만 중앙 집중화하십시오. 예를 들어, 공통 보안 헤더, 압축 및 SSL 매개변수를 스니펫에 넣되 각 사이트의 root, server_name, 업스트림 및 로그는 자체 파일에 표시되도록 유지하십시오.

각 줄을 읽지 않고 한 도메인에서 다른 도메인으로 대규모 프로덕션 블록을 복사하지 마십시오. 이것이 server_name 실수, 잘못된 인증서 경로 및 공유 로그 파일이 발생하는 방법입니다. 실용적인 검토 체크리스트는 간단합니다:

  • server_name에 사용자가 입력할 모든 호스트 이름이 포함되어 있습니까?
  • root 또는 proxy_pass가 이전 사이트가 아닌 이 사이트를 가리킵니까?
  • 액세스 및 오류 로그가 이 사이트를 단독으로 디버깅할 수 있을 정도로 분리되어 있습니까?
  • 리로드 전에 nginx -t가 통과합니까?
  • curl -H "Host: ..." 또는 curl --resolve가 예상된 사이트를 반환합니까?

마지막 참고 사항

Nginx 가상 호스트는 각 사이트에 명확한 서버 블록, 올바른 server_name 및 예측 가능한 기본 대체가 있을 때 안정적입니다. 파일을 지루하게 유지하십시오. 리로드하기 전에 모든 변경 사항을 테스트하십시오. 사이트가 중요할 때 전용 로그를 사용하십시오. 대부분의 멀티 사이트 Nginx 문제는 DNS, TLS/SNI 또는 서버 블록 일치 중 어떤 부분이 실패했는지 증명할 수 있으면 쉽게 해결할 수 있습니다.