[카테고리:] 취미

  • Cloudflare Tunnel 홈서버 외부접속 Rocky Linux 9 설정법

    Cloudflare Tunnel 홈서버 외부접속 Rocky Linux 9 설정법

    집 안에 둔 서버를 밖에서 접속하려고 하면 늘 한 지점에서 걸렸습니다. 공유기 포트포워딩은 설정 자체는 어렵지 않지만, 한 번 열어두면 계속 신경이 쓰입니다. DDNS도 공인 IP 여부나 ISP의 CGNAT 환경에 따라 생각보다 깔끔하게 끝나지 않을 때가 있었습니다.

    홈서버 네트워크 구성 참고 이미지

    포트포워딩을 열지 않기로 한 이유

    이번 구성은 Rocky Linux 9 서버에서 Cloudflare Tunnel로 외부 접속을 붙이는 방식입니다. 서버가 Cloudflare 쪽으로 먼저 아웃바운드 연결을 만들고, 외부 요청은 그 터널을 통해 내부 서비스로 전달됩니다.

    이 구조에서는 공유기에서 80, 443 같은 인바운드 포트를 열 필요가 없습니다. firewalld에도 웹 서비스 포트를 추가하지 않았습니다. SSH는 기존처럼 관리용으로만 제한해두는 쪽이 낫다고 봤고, 이 방향은 예전에 정리한 Rocky Linux 9 앵커글이나 SSH 하드닝글의 흐름과도 잘 맞았습니다.

    Cloudflare 공식 문서에서도 Tunnel은 서버에서 실행되는 cloudflared가 Cloudflare와 연결을 맺는 방식으로 설명합니다. 설치와 로컬 관리형 터널 흐름은 공식 문서를 기준으로 확인했습니다.

    • Cloudflare Tunnel 로컬 관리형 터널 문서: https://developers.cloudflare.com/tunnel/advanced/local-management/create-local-tunnel/
    • cloudflared 다운로드 문서: https://developers.cloudflare.com/tunnel/downloads/
    • Cloudflare 패키지 저장소: https://pkg.cloudflare.com/

    비슷한 선택지를 나누면 아래처럼 정리됩니다.

    방식 장점 주의할 점
    Cloudflare Tunnel 포트포워딩 없이 HTTP 서비스를 외부에 공개하기 쉽고 Access 정책을 붙일 수 있음 Cloudflare 프록시 제한을 받으며, 대용량 업로드에는 주의가 필요함
    공유기 포트포워딩 + DDNS 구조가 단순하고 직접 제어하기 쉬움 공인 IP, ISP CGNAT, 포트 노출 문제를 직접 관리해야 함
    VPN/WARP/Tailscale 계열 내부망처럼 접근할 수 있어 관리용으로 안정적 일반 웹 서비스처럼 도메인만 알려주는 공개 접근에는 별도 설계가 필요함

    cloudflared 설치는 dnf repo 방식으로

    Rocky Linux 9에서는 curl | bash 방식 대신 Cloudflare RPM 저장소를 추가한 뒤 dnf install로 설치했습니다. 홈서버처럼 오래 운영할 서버라면 패키지로 관리하는 편이 업데이트와 제거 면에서 깔끔합니다.

    서버 터미널 작업 분위기
    bash

    sudo dnf install -y dnf-plugins-core
    sudo curl -fsSL https://pkg.cloudflare.com/cloudflared.repo -o /etc/yum.repos.d/cloudflared.repo
    sudo dnf install -y cloudflared
    cloudflared --version
    

    설치 후에는 SELinux 상태부터 확인했습니다. 저는 SELinux enforcing 유지를 전제로 작업했습니다.

    bash

    getenforce
    
    text

    Enforcing
    

    firewalld도 확인했습니다. 이번 구성의 핵심은 외부에서 들어오는 HTTP/HTTPS 포트를 열지 않는 것이므로 http, https 서비스를 추가하지 않았습니다.

    bash

    sudo firewall-cmd --list-all
    
    text

    public (active)
      target: default
      services: cockpit dhcpv6-client ssh
      ports:
      protocols:
      forward: yes
      masquerade: no
    

    중요한 점은 터널용으로 firewalld 인바운드 포트를 열지 않았다는 것입니다. 서버가 밖으로 나가는 연결을 만들기 때문에 공유기 포트포워딩도 건드리지 않았습니다.

    터널 생성과 config.yml 작성

    Cloudflare 계정에 도메인이 연결되어 있다는 전제에서 진행했습니다. 먼저 브라우저 인증을 한 번 거칩니다.

    bash

    cloudflared tunnel login
    

    제 환경에서는 아래처럼 인증 URL이 출력됐고, 브라우저에서 도메인을 선택한 뒤 인증 파일이 생성됐습니다.

    text

    Please open the following URL and log in with your Cloudflare account:
    
    https://dash.cloudflare.com/argotunnel?callback=https%3A%2F%2Flogin.cloudflareaccess.org%2F...
    
    You have successfully logged in.
    If you wish to copy your credentials to a server, they have been saved to:
    /home/rocky/.cloudflared/cert.pem
    

    이어서 터널을 만들었습니다. 이름은 나중에 알아보기 쉽도록 homelab-rocky9로 잡았습니다.

    bash

    cloudflared tunnel create homelab-rocky9
    
    text

    Tunnel credentials written to /home/rocky/.cloudflared/2f7b3b7c-9a66-4c91-8b52-111111111111.json.
    Created tunnel homelab-rocky9 with id 2f7b3b7c-9a66-4c91-8b52-111111111111
    

    설정 파일은 /etc/cloudflared/config.yml에 두고 systemd에서 안정적으로 읽도록 했습니다. 아래 예시는 Immich를 http://localhost:2283으로 연결하는 형태입니다. 실제 도메인은 본인 도메인에 맞게 바꾸면 됩니다.

    bash

    sudo mkdir -p /etc/cloudflared
    sudo cp ~/.cloudflared/2f7b3b7c-9a66-4c91-8b52-111111111111.json /etc/cloudflared/
    sudo vi /etc/cloudflared/config.yml
    
    yaml

    tunnel: 2f7b3b7c-9a66-4c91-8b52-111111111111
    credentials-file: /etc/cloudflared/2f7b3b7c-9a66-4c91-8b52-111111111111.json
    
    ingress:
      - hostname: immich.example.com
        service: http://localhost:2283
      - hostname: admin.example.com
        service: http://localhost:8080
      - service: http_status:404
    

    Cloudflare 문서에서는 마지막에 catch-all 규칙을 두는 흐름을 안내합니다. 그래서 맨 아래에 http_status:404를 넣어 정의하지 않은 호스트는 막히게 했습니다.

    DNS 라우팅은 아래처럼 잡았습니다.

    bash

    cloudflared tunnel route dns homelab-rocky9 immich.example.com
    cloudflared tunnel route dns homelab-rocky9 admin.example.com
    
    text

    2026-07-17T03:41:12Z INF Added CNAME immich.example.com which will route to this tunnel tunnelID=2f7b3b7c-9a66-4c91-8b52-111111111111
    2026-07-17T03:41:18Z INF Added CNAME admin.example.com which will route to this tunnel tunnelID=2f7b3b7c-9a66-4c91-8b52-111111111111
    
    네트워크 연결 흐름 참고 이미지

    설정 검증도 한 번 해두는 편이 좋습니다.

    bash

    cloudflared tunnel ingress validate --config /etc/cloudflared/config.yml
    
    text

    Validating rules from /etc/cloudflared/config.yml
    OK
    

    systemd 등록과 재부팅 복구 확인

    수동 실행으로만 두면 서버 재부팅 때 터널이 내려갈 수 있습니다. 그래서 바로 systemd 서비스로 등록했습니다.

    bash

    sudo cloudflared service install
    sudo systemctl enable --now cloudflared
    sudo systemctl status cloudflared --no-pager
    

    정상이라면 대략 이런 로그가 보입니다.

    text

    ● cloudflared.service - cloudflared
         Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; preset: disabled)
         Active: active (running) since Fri 2026-07-17 03:48:31 UTC; 12s ago
       Main PID: 1842 (cloudflared)
          Tasks: 9
         Memory: 18.7M
            CPU: 230ms
    
    Jul 17 03:48:32 rocky9 cloudflared[1842]: INF Starting tunnel tunnelID=2f7b3b7c-9a66-4c91-8b52-111111111111
    Jul 17 03:48:33 rocky9 cloudflared[1842]: INF Registered tunnel connection connIndex=0
    Jul 17 03:48:34 rocky9 cloudflared[1842]: INF Registered tunnel connection connIndex=1
    

    재부팅 후 자동으로 복구되는지도 확인했습니다.

    bash

    sudo reboot
    

    다시 접속한 뒤 아래 명령을 실행했습니다.

    bash

    systemctl is-enabled cloudflared
    systemctl is-active cloudflared
    journalctl -u cloudflared -b --no-pager | tail -n 20
    
    text

    enabled
    active
    Jul 17 04:02:11 rocky9 cloudflared[912]: INF Starting tunnel tunnelID=2f7b3b7c-9a66-4c91-8b52-111111111111
    Jul 17 04:02:12 rocky9 cloudflared[912]: INF Registered tunnel connection connIndex=0
    Jul 17 04:02:13 rocky9 cloudflared[912]: INF Registered tunnel connection connIndex=1
    Jul 17 04:02:14 rocky9 cloudflared[912]: INF Registered tunnel connection connIndex=2
    Jul 17 04:02:15 rocky9 cloudflared[912]: INF Registered tunnel connection connIndex=3
    

    여기까지 확인해야 홈서버 운영용으로 믿고 쓸 수 있습니다. 단순히 접속이 되는지보다 서버 재부팅 후에도 터널이 자동으로 살아나는지가 더 중요했습니다.

    Immich 백업에서 만난 100MB 제한

    Cloudflare Tunnel을 붙인 뒤 가장 먼저 확인한 서비스는 Immich였습니다. 사진 백업은 잘 됐지만, 모바일에서 찍은 영상 하나가 계속 실패했습니다. 처음에는 Immich 설정이나 nginx 업로드 제한을 의심했는데, 로그를 보니 원인은 다른 쪽에 가까웠습니다.

    모바일 백업과 홈서버 연결 참고 이미지

    Immich 모바일 백업 중 대용량 영상에서 남은 로그입니다.

    text

    | immich_server | [Nest] 91  - 07/17/2026, 4:18:27 AM   ERROR [Api:AssetController] Upload failed: PayloadTooLargeException: request entity too large |
    | --- | --- |
    | immich_proxy | 172.18.0.1 - - [17/Jul/2026:04:18:27 +0000] "POST /api/assets HTTP/1.1" 413 176 "-" "Immich/1.132.3 build.197" |
    | cloudflared | 2026-07-17T04:18:27Z ERR Request failed error="HTTP status 413 Request Entity Too Large" cfRay=95ab111111111111-ICN ingressRule=0 originService=http://localhost:2283 |
    

    Cloudflare의 Request body size limit 기준으로 Free와 Pro 플랜은 요청 본문 최대 100MB입니다. 이 제한을 넘는 업로드는 413 Request Entity Too Large로 막힐 수 있습니다.

    • Cloudflare 요청 크기 제한 문서: https://developers.cloudflare.com/workers/platform/limits/

    그래서 Immich를 Cloudflare Tunnel 하나로만 쓰는 건 제 기준에서는 애매했습니다. 사진 위주라면 문제가 적지만, 요즘 휴대폰 영상은 100MB를 넘는 경우가 흔합니다.

    운영 방식 장점 주의할 점
    Immich 외부 접속을 Cloudflare Tunnel로만 사용 도메인 접속이 쉽고 포트포워딩이 필요 없음 100MB 초과 영상 업로드에서 413 오류가 날 수 있음
    집 안에서는 LAN 주소로 직접 백업 대용량 영상 업로드가 안정적이고 빠름 외부에서는 별도 접속 경로가 필요함
    외부 백업은 WARP 또는 VPN 경로로 분리 내부망 접근처럼 사용할 수 있어 대용량 업로드에 유리함 클라이언트 설정이 추가로 필요함

    현재는 집 안에서는 Immich 앱이 로컬 주소를 보도록 두고, 밖에서는 조회나 가벼운 업로드만 Tunnel을 타게 나눴습니다. 외부에서 대용량 백업까지 해야 한다면 WARP나 VPN 계열을 함께 설계하는 쪽이 현실적입니다. 이 부분은 별도 Immich글에서 모바일 백업 기준으로 더 자세히 다룰 만했습니다.

    Zero Trust Access로 관리 화면 보호하기

    Tunnel을 열었다고 해서 모든 경로를 그대로 공개하고 싶지는 않았습니다. 특히 Immich admin, 서버 관리용 대시보드, 내부 도구처럼 자체 로그인이 있더라도 앞단에 한 겹 더 두는 편이 낫습니다.

    Cloudflare Zero Trust의 Access 정책을 쓰면 특정 이메일이나 이메일 도메인 기준으로 인증 게이트를 붙일 수 있습니다. 공식 문서에서도 Access는 self-hosted application 앞에서 요청을 검사하고, 정책에 맞는 사용자만 통과시키는 방식으로 설명합니다.

    • Cloudflare Access 애플리케이션 문서: https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/
    • Cloudflare Access 정책 문서: https://developers.cloudflare.com/cloudflare-one/access-controls/policies/

    예를 들어 admin.example.com은 Access Application으로 만들고, 정책에는 제 이메일만 허용했습니다.

    보호 방식 장점 주의할 점
    Access 이메일 인증 관리 페이지 앞단에 인증 게이트를 둘 수 있음 이메일 OTP나 IdP 흐름이 한 번 추가됨
    앱 자체 로그인만 사용 구성이 단순함 앱 취약점이나 로그인 페이지 노출을 그대로 감수해야 함
    IP 제한 특정 위치에서는 깔끔함 모바일망, 외부 작업 환경에서는 관리가 번거로움

    설정 방향은 단순합니다. Zero Trust 대시보드에서 Access Application을 만들고, 도메인을 admin.example.com으로 지정한 뒤 Allow 정책에 사용할 이메일을 넣었습니다.

    text

    Application domain: admin.example.com
    Policy action: Allow
    Include selector: Emails
    Value: [email protected]
    Login method: One-time PIN
    

    주의할 점은 OTP를 아무 이메일에나 열어두지 않는 것입니다. 홈서버 관리 화면은 특히 Everyone 허용으로 두지 않는 것이 중요합니다.

    보안 접근 제어 참고 이미지

    정리

    Cloudflare Tunnel은 홈서버 외부 접속을 만들 때 꽤 실용적이었습니다. 특히 공유기 포트포워딩 없이 도메인 기반 HTTPS 접속을 붙일 수 있다는 점이 가장 컸습니다. Rocky Linux 9에서도 RPM 저장소를 추가해 dnf install cloudflared로 관리하면 설치 흐름이 깔끔했고, systemd 등록 후 재부팅 복구까지 확인하니 운영 부담도 적었습니다.

    다만 Immich처럼 대용량 업로드가 많은 서비스는 100MB 제한을 먼저 생각해야 합니다. 저는 외부 조회와 가벼운 접근은 Tunnel, 집 안 백업은 LAN 직접 연결, 관리 화면은 Zero Trust Access로 보호하는 식으로 역할을 나눴습니다.

    홈랩에서는 한 가지 도구로 전부 해결하려 하기보다 노출을 줄이고 필요한 경로만 열어두는 구성이 오래 운영하기에 편했습니다.

  • Immich 구글포토 대체 Rocky Linux 사진 백업 서버 구축

    Immich 구글포토 대체 Rocky Linux 사진 백업 서버 구축

    구글포토를 계속 쓰면서도 마음 한쪽이 불편했던 이유는 비용만은 아니었습니다. 가족 사진, 영수증, 여행 기록이 한곳에 오래 쌓이다 보니 사진 백업은 편해야 하지만, 저장 위치와 백업 방식은 직접 통제하고 싶다는 생각이 커졌습니다.

    개인 사진 백업 이미지

    구성 환경

    이번 구성은 Rocky Linux 9 + Docker Compose v2 기준입니다. Rocky Linux 기본 설정은 Rocky Linux 9 기본 설정 글을 먼저 보면 흐름이 편하고, Docker가 아직 없다면 Docker 설치글을 먼저 끝내는 편이 좋습니다.

    항목
    OS Rocky Linux 9.x
    실행 방식 Docker + Compose v2
    Immich 포트 2283/tcp
    RAM 최소 4GB, 얼굴 인식까지 고려하면 8GB 이상 권장
    사진 저장 경로 /srv/immich/library
    DB 저장 경로 /srv/immich/postgres
    공식 문서 Immich Docker Compose 안내

    Immich는 공식 문서 기준으로 docker compose 설치 흐름이 잘 정리되어 있습니다. 예전 자료에서는 pgvecto-rs DB 이미지를 쓰는 경우도 많았지만, 현재 공식 Compose 예시는 ghcr.io/immich-app/postgres 계열 이미지로 정리되어 있습니다. 이미 운영 중인 서버라면 새 Compose 파일을 그대로 덮기보다, 공식 업그레이드 문서를 먼저 확인하는 쪽이 안전합니다.

    docker-compose.yml 구성

    Immich는 기능이 많아 보여도 기본 구성은 비교적 단순합니다. 사진 업로드와 웹 화면을 담당하는 immich-server, 검색과 얼굴 인식에 쓰이는 machine-learning, 캐시용 redis, 데이터베이스가 함께 떠야 정상적으로 동작합니다.

    yaml

    name: immich
    
    services:
      immich-server:
        container_name: immich_server
        image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
        volumes:
          - ${UPLOAD_LOCATION}:/data:z
          - /etc/localtime:/etc/localtime:ro
        env_file:
          - .env
        ports:
          - "2283:2283"
        depends_on:
          - redis
          - database
        restart: always
        healthcheck:
          disable: false
    
      immich-machine-learning:
        container_name: immich_machine_learning
        image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
        volumes:
          - model-cache:/cache:z
        env_file:
          - .env
        restart: always
        healthcheck:
          disable: false
    
      redis:
        container_name: immich_redis
        image: docker.io/valkey/valkey:9
        healthcheck:
    test: redis-cli ping || exit 1
        restart: always
    
      database:
        container_name: immich_postgres
        image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
        environment:
          POSTGRES_PASSWORD: ${DB_PASSWORD}
          POSTGRES_USER: ${DB_USERNAME}
          POSTGRES_DB: ${DB_DATABASE_NAME}
          POSTGRES_INITDB_ARGS: "--data-checksums"
        volumes:
          - ${DB_DATA_LOCATION}:/var/lib/postgresql/data:z
        shm_size: 128mb
        restart: always
        healthcheck:
          disable: false
    
    volumes:
      model-cache:
    

    환경값은 .env로 분리해두는 편이 관리하기 쉽습니다. 비밀번호는 복잡하게 만들수록 좋지만, Docker 파싱 문제를 줄이려면 공식 안내처럼 영문과 숫자 조합으로 두는 쪽이 덜 번거로웠습니다.

    env

    UPLOAD_LOCATION=/srv/immich/library
    DB_DATA_LOCATION=/srv/immich/postgres
    TZ=Asia/Seoul
    IMMICH_VERSION=v3
    
    DB_PASSWORD=ChangeThisPassword1234
    DB_USERNAME=postgres
    DB_DATABASE_NAME=immich
    
    서버와 사진 백업 흐름

    SELinux와 방화벽 설정

    Rocky Linux 9에서 Immich를 올릴 때 가장 자주 막히는 부분은 SELinux입니다. Docker 볼륨에 :z 라벨을 붙이지 않거나 컨텍스트가 맞지 않으면 컨테이너는 떠도 내부에서 파일을 쓰지 못합니다.

    실제로는 이런 로그를 만나기 쉽습니다.

    bash

    Error: EACCES: permission denied, mkdir '/data/upload'
    

    DB 쪽에서는 아래처럼 보일 수 있습니다.

    bash

    initdb: error: could not access directory "/var/lib/postgresql/data": Permission denied
    

    이때 setenforce 0으로 넘기는 방식은 피하는 게 좋습니다. 계속 켜둘 홈서버라면 SELinux를 끄는 대신 컨텍스트를 맞춰서 해결하는 방식이 맞습니다.

    bash

    sudo dnf install -y policycoreutils-python-utils
    
    sudo mkdir -p /srv/immich/library /srv/immich/postgres
    
    sudo semanage fcontext -a -t container_file_t "/srv/immich(/.*)?"
    sudo restorecon -Rv /srv/immich
    

    firewalld도 Rocky Linux 기본 흐름에 맞춰 열어줍니다.

    bash

    sudo firewall-cmd --permanent --add-port=2283/tcp
    sudo firewall-cmd --reload
    sudo firewall-cmd --list-ports
    

    컨테이너 실행은 Immich Compose 파일이 있는 디렉터리에서 진행합니다.

    bash

    docker compose up -d
    docker compose ps
    

    얼굴 인식과 메모리 사용

    Immich의 장점은 사진을 단순히 저장하는 데서 끝나지 않는다는 점입니다. 업로드한 사진을 기준으로 검색, 미리보기, 얼굴 인식이 돌아가면 구글포토를 쓰던 감각과 꽤 가까워집니다.

    머신러닝과 사진 분류 작업

    다만 immich-machine-learning 컨테이너는 생각보다 메모리를 사용합니다. 사진 수가 많고 CPU만으로 인덱싱을 돌리면 초반 며칠은 서버가 계속 바쁠 수 있습니다. N100 미니PC나 ARM 서버처럼 저전력 장비에서는 업로드 직후 결과를 기대하기보다, 밤새 천천히 처리하게 두는 편이 현실적입니다.

    메모리와 CPU 사용량은 아래 명령으로 확인할 수 있습니다.

    bash

    docker stats immich_machine_learning immich_server immich_postgres
    

    CPU 인덱싱 속도는 사진 해상도와 장비에 따라 차이가 큽니다. GPU 가속을 붙이면 빨라질 수 있지만, 홈서버에서는 전력과 발열도 함께 봐야 하므로 무조건 정답이라고 보기는 어렵습니다.

    모바일 앱 백업 설정

    서버가 올라오면 브라우저에서 아래 주소로 접속합니다.

    text

    http://서버IP:2283
    

    외부에서 쓰려면 리버스 프록시와 HTTPS까지 붙이는 편이 좋습니다. 다만 집 안에서 먼저 테스트할 때는 2283 포트만으로도 충분합니다. 모바일 앱에서는 서버 URL을 넣고 로그인한 뒤 백그라운드 자동 백업을 켜면 됩니다.

    처음부터 모든 앨범을 올리기보다는 카메라 앨범부터 시작하는 편이 좋습니다. 스크린샷이나 다운로드 폴더는 나중에 필요할 때 추가해야 정리가 덜 흐트러집니다.

    스토리지 설계

    사진 백업은 처음에는 100GB도 커 보이지만, 가족 단위로 몇 년 치를 모으면 금방 단위가 바뀝니다. 휴대폰 사진에 동영상까지 섞이면 1TB는 시작점에 가깝고, 장기 보관은 4TB 이상부터 여유가 생깁니다.

    제품 장점 단점
    구글 포토 앱 완성도와 검색이 좋고 관리 부담이 거의 없습니다 용량이 늘수록 비용이 계속 붙고 데이터 위치를 직접 통제하기 어렵습니다
    Immich 셀프호스팅 원본 사진을 내 서버에 보관하고 백업 정책을 직접 정할 수 있습니다 서버 운영, 업데이트, 백업을 직접 챙겨야 합니다
    Synology NAS 저장소 관리와 디스크 교체가 편하고 가족용 공유에 강합니다 초기 비용이 있고 Docker 성능은 모델에 따라 차이가 납니다
    N100/N150 미니PC 전력 대비 성능이 좋아 Immich 서버용으로 무난합니다 디스크 베이를 따로 구성해야 해서 저장소 설계가 필요합니다
    NAS HDD 대용량을 비교적 안정적으로 운용하기 좋습니다 SSD보다 느리며 DB 저장 위치로는 적합하지 않을 수 있습니다
    홈서버 저장장치 구성

    개인적으로는 사진 원본은 NAS HDD에 두고, DB는 SSD에 두는 구성이 가장 무난해 보였습니다. Immich 공식 안내에서도 DB를 네트워크 공유에 두는 방식은 권장하지 않으니, 처음 설계할 때 저장 위치를 나눠두는 편이 좋습니다.

    마지막으로 백업은 Immich 하나로 끝내지 않는 게 안전합니다. 서버에 원본이 있고, NAS나 외장하드에 한 벌 더 있으며, 정말 중요한 사진은 외부 저장소까지 두는 3-2-1 규칙을 기준으로 잡으면 복구 선택지가 남습니다. Immich는 단순히 구글포토 화면을 대신하는 도구라기보다, 내 사진 보관 방식을 다시 정리하게 만드는 홈서버 서비스에 가깝습니다.

  • Rocky Linux 9 로컬 LLM 구축 Ollama Open WebUI Docker 설정

    Rocky Linux 9 로컬 LLM 구축 Ollama Open WebUI Docker 설정

    로컬 LLM을 집 서버에 올리는 이유

    로컬 AI를 한 번 구성해두면 생각보다 자주 쓰게 됩니다. 외부 API 키를 넣지 않아도 되고, 테스트하다가 토큰 비용이 쌓일 걱정도 없습니다. 홈서버에 붙여두기 좋은 서비스였습니다.

    로컬 서버 구축 분위기

    제가 로컬 LLM에 관심을 둔 가장 큰 이유는 프라이버시와 API 비용이었습니다.

    ChatGPT나 Claude 같은 서비스를 쓰면 편하지만, 개인 메모나 내부 문서 내용을 넣을 때는 한 번 더 생각하게 됩니다. 반대로 Ollama는 모델을 서버 안에 내려받아 실행하는 방식이라, 기본적인 질의응답은 외부 API 없이 처리할 수 있습니다.

    물론 성능은 하드웨어를 많이 탑니다. 그래도 간단한 요약, 코드 초안, 개인용 질의응답 정도라면 Rocky Linux 9 + Docker + Ollama + Open WebUI 조합이 꽤 깔끔합니다.

    공식 문서는 아래를 기준으로 확인하면 됩니다.

    구분 링크 확인할 내용
    Rocky Linux Rocky Linux 공식 사이트 Rocky Linux 9 ISO, 릴리즈 정보
    Docker Docker Engine 설치 문서 Docker 및 Compose v2 설치
    Ollama Ollama Linux 설치 Linux 설치 명령과 모델 실행
    Open WebUI Open WebUI Quick Start Docker 실행, Compose 예시

    사전 준비는 Rocky 9와 Docker부터

    이 글은 Rocky Linux 9.x에 Docker와 Compose v2가 설치된 상태를 기준으로 정리했습니다. Docker Compose는 예전의 docker-compose가 아니라 docker compose처럼 띄어 쓰는 v2 방식으로 진행합니다.

    먼저 서버에서 Docker가 정상 동작하는지 확인합니다.

    bash

    docker --version
    docker compose version
    systemctl status docker
    

    방화벽을 사용 중이라면 나중에 Open WebUI 접속용으로 3000번 포트를 열어야 합니다. Ollama의 기본 포트는 11434인데, 외부에 직접 열기보다는 Docker 네트워크 내부에서만 쓰는 편이 낫습니다.

    서버 작업 환경

    Ollama 설치와 모델 Pull

    Ollama는 호스트에 직접 설치할 수도 있고, Docker 컨테이너로 띄울 수도 있습니다. 홈서버에서 관리하기에는 Docker Compose로 함께 묶는 방식이 편했습니다.

    먼저 감을 보고 싶다면 호스트에 설치한 뒤 모델을 받아 테스트해도 됩니다.

    bash

    curl -fsSL https://ollama.com/install.sh | sh
    ollama pull llama3.2
    ollama run llama3.2
    

    모델 이름은 시점에 따라 바뀔 수 있으니, 실제 사용 전에는 Ollama 공식 라이브러리에서 한 번 확인하는 편이 좋습니다. 입문용으로는 llama3.2, 가벼운 서버라면 더 작은 모델부터 시작하는 것이 부담이 적습니다.

    모델 목록은 이렇게 확인합니다.

    bash

    ollama list
    

    Open WebUI Docker Compose 작성

    Open WebUI는 브라우저에서 ChatGPT처럼 사용할 수 있게 해주는 웹 UI입니다. 공식 문서에서도 Docker 방식을 안내하고 있고, 데이터는 볼륨에 남기는 구조가 기본입니다.

    저는 Ollama와 Open WebUI를 같은 compose 파일에 두는 구성이 가장 단순했습니다.

    yaml

    services:
      ollama:
        image: ollama/ollama:latest
        container_name: ollama
        restart: unless-stopped
        volumes:
          - ollama:/root/.ollama
        ports:
          - "127.0.0.1:11434:11434"
    
      open-webui:
        image: ghcr.io/open-webui/open-webui:main
        container_name: open-webui
        restart: unless-stopped
        depends_on:
          - ollama
        ports:
          - "3000:8080"
        environment:
          - OLLAMA_BASE_URL=http://ollama:11434
          - WEBUI_SECRET_KEY=change-this-to-a-long-random-string
        volumes:
          - open-webui:/app/backend/data
    
    volumes:
      ollama:
      open-webui:
    

    여기서 중요한 부분은 OLLAMA_BASE_URL=http://ollama:11434 입니다. 컨테이너 안에서 localhost:11434를 바라보면 Open WebUI 자기 자신을 가리키게 되어 연결이 되지 않습니다.

    실행은 compose 파일이 있는 디렉터리에서 합니다.

    bash

    docker compose up -d
    docker ps
    docker logs -f open-webui
    
    도커 컨테이너 운영 이미지

    firewalld와 SELinux에서 막히는 지점

    Rocky Linux 9에서 Ubuntu 기준 글과 차이가 나는 부분은 이 지점이었습니다. 컨테이너는 떠 있는데 브라우저 접속이 안 되거나, 볼륨을 바인드 마운트했을 때 권한 에러가 나는 경우가 있습니다.

    외부 브라우저에서 접속할 예정이라면 firewalld에 3000번 포트를 열어줍니다.

    bash

    sudo firewall-cmd --add-port=3000/tcp --permanent
    sudo firewall-cmd --reload
    sudo firewall-cmd --list-ports
    

    SELinux는 named volume을 쓰면 대체로 조용합니다. 하지만 아래처럼 호스트 디렉터리를 직접 붙이면 에러가 날 수 있습니다.

    yaml

    volumes:
      - ./open-webui-data:/app/backend/data
    

    이때 로그에는 이런 식으로 남는 경우가 있습니다.

    bash

    PermissionError: [Errno 13] Permission denied: '/app/backend/data'
    

    또는 audit 로그에서 AVC deny가 확인됩니다.

    bash

    sudo ausearch -m avc -ts recent
    

    바인드 마운트를 꼭 써야 한다면 :Z 옵션을 붙여 SELinux 컨텍스트를 컨테이너에 맞춰줍니다.

    yaml

    volumes:
      - ./open-webui-data:/app/backend/data:Z
    

    이미 만들어둔 디렉터리라면 권한도 같이 확인합니다.

    bash

    mkdir -p ./open-webui-data
    sudo chown -R 1000:1000 ./open-webui-data
    

    Rocky 계열에서는 이 부분을 빼먹으면 원인 찾는 데 시간이 꽤 걸립니다. 방화벽은 접속 문제, SELinux는 파일 접근 문제로 나눠서 보면 훨씬 빨리 좁힐 수 있습니다.

    접속 테스트와 첫 모델 확인

    브라우저에서 아래 주소로 접속합니다.

    text

    http://서버IP:3000
    

    처음 접속하면 계정을 만들고, 관리자 화면에서 Ollama 연결 상태를 확인합니다. compose에서 OLLAMA_BASE_URL을 제대로 넣었다면 별도 설정 없이 모델 목록이 잡히는 편입니다.

    웹 UI 접속 확인 화면 분위기

    모델이 보이지 않으면 먼저 Ollama 컨테이너 안에서 pull을 실행합니다.

    bash

    docker exec -it ollama ollama pull llama3.2
    docker exec -it ollama ollama list
    

    Open WebUI 로그에서 연결 실패가 보이면 URL 설정을 다시 확인합니다.

    bash

    docker logs open-webui --tail=100
    

    자주 만나는 메시지는 대략 이런 형태입니다.

    bash

    httpx.ConnectError: [Errno 111] Connection refused
    

    이 경우 대부분 Open WebUI가 Ollama를 localhost로 찾고 있거나, 두 컨테이너가 같은 Docker 네트워크에 있지 않은 상황이었습니다.

    사양별 체감 속도와 선택 기준

    로컬 LLM은 설치보다 사양 선택에서 기대치를 맞추는 일이 더 중요합니다. 특히 CPU만 있는 서버와 GPU가 있는 서버는 체감 차이가 큽니다.

    제품명 가격대 주요 특징 추천 대상
    Oracle Cloud ARM Free Tier 무료 가능 비용 부담은 거의 없지만 LLM 추론은 느린 편 테스트용, 가벼운 모델 실험
    Intel N100 미니 PC 10만~20만원대 전력 소모가 낮고 24시간 운영 부담이 적음 홈서버 입문, 문서 요약 위주
    Ryzen 5급 미니 PC 30만~50만원대 CPU 추론 기준으로 N100보다 여유 있음 개인용 AI 서버, 여러 서비스 병행
    RTX 3060 12GB 데스크톱 중고가 변동 VRAM 12GB로 7B급 모델 운용이 수월함 응답 속도 중시, 로컬 AI 주사용
    RTX 4060 Ti 16GB 데스크톱 가격 변동 큼 VRAM 여유가 있어 모델 선택 폭이 넓음 장기적으로 로컬 LLM을 자주 쓸 사람

    제휴 링크를 넣는다면 표의 제품명이나 가격대 옆에 붙이는 방식이 자연스럽습니다. 다만 서버 부품은 가격 변동이 심하므로, 글을 발행할 때 실제 판매가와 재고를 한 번 더 확인하는 편이 좋습니다.

    홈서버 하드웨어 선택 분위기

    마무리 운영 포인트

    Rocky Linux 9에서 Ollama와 Open WebUI를 Docker로 묶으면 관리 자체는 단순합니다. 핵심은 Ollama 주소를 컨테이너 네트워크 기준으로 잡는 것, 그리고 firewalld와 SELinux를 Rocky 방식대로 처리하는 것입니다.

    처음부터 큰 모델을 올리기보다 llama3.2 같은 모델로 접속과 응답 흐름을 먼저 확인하고, 그다음 하드웨어에 맞춰 모델을 바꾸는 순서가 덜 피곤했습니다. 로컬 AI는 한 번에 완성하는 서비스라기보다, 홈서버에 하나 얹어두고 천천히 손에 맞게 조정하는 쪽에 가깝습니다.

  • 홈서버 자동화 작업 추천 기사 요약 텔레그램 알림 구성

    홈서버 자동화 작업 추천 기사 요약 텔레그램 알림 구성

    관심 기사 요약 자동화가 홈서버와 잘 맞는 이유

    관심 있는 기사만 골라 텔레그램으로 받아보는 자동화는 홈서버에서 돌리기 좋은 작업입니다. 매번 뉴스 앱을 열고, 키워드를 검색하고, 저장해두는 과정이 생각보다 번거롭기 때문입니다. RSS, 요약, 텔레그램 봇을 묶으면 매일 반복하는 확인 작업을 꽤 줄일 수 있습니다.

    자동화 작업 참고 이미지

    자동화 흐름은 단순할수록 오래 갑니다

    홈서버 자동화는 처음부터 크게 만들면 관리가 피곤해집니다. 직접 구성해보는 입장에서는 기사 수집 → 필터링 → 요약 → 텔레그램 전송 정도로 나누는 방식이 가장 무난합니다.

    예를 들어 관심 키워드를 미리 정해두고, RSS 피드에서 해당 키워드가 들어간 기사만 추려냅니다. 이후 원문 전체를 가져오기보다 제목, 발행처, 링크, 짧은 요약 정도만 정리해서 보내는 편이 깔끔합니다.

    특히 저작권이 있는 기사 본문을 통째로 저장하거나 재전송하는 방식은 피해야 합니다. 개인용 자동화라도 원문 링크 중심으로 확인하는 구조를 잡아두면 나중에 범위가 커졌을 때도 부담이 덜합니다.

    홈서버에 올리기 좋은 자동화 도구

    자동화 도구는 성향에 따라 선택이 갈립니다. 코드로 직접 짜는 방식이 편한 분도 있고, 화면에서 흐름을 연결하는 방식이 관리하기 쉬운 분도 있습니다.

    개인 홈서버 기준으로는 아래 세 가지가 후보에 오릅니다.

    제품 장점 단점
    n8n 시각적으로 흐름을 확인하기 좋아 RSS, HTTP 요청, 텔레그램 연동을 빠르게 구성할 수 있습니다 워크플로가 많아지면 백업과 버전 관리에 신경 써야 합니다
    Node-RED 가볍고 홈서버 자동화에 익숙한 사용자가 많아 센서·알림 연동까지 확장하기 좋습니다 뉴스 요약처럼 텍스트 처리 로직이 많아지면 흐름이 복잡해질 수 있습니다
    Python 스크립트 원하는 방식으로 세밀하게 제어할 수 있고 Docker 크론 작업으로 돌리기 좋습니다 예외 처리, 로그, 재시도 로직을 직접 챙겨야 합니다

    처음 구성한다면 n8n으로 흐름을 잡고, 나중에 로직이 복잡해지는 부분만 Python 스크립트로 분리하는 방식이 현실적입니다. 처음부터 완성형으로 만들기보다, 며칠 받아보면서 필터를 조정하는 쪽이 실제 사용에는 더 잘 맞습니다.

    홈서버 자동화 참고 이미지

    텔레그램 봇은 알림 채널로 쓰기 편합니다

    텔레그램은 봇을 만들고 채팅 ID만 확인하면 메시지를 보낼 수 있어 자동화 입문용으로도 부담이 적습니다. 홈서버에서 외부로 알림을 보내야 할 때 이메일보다 즉시성이 좋고, 메시지 형식도 비교적 다루기 쉽습니다.

    구성은 단순하게 잡을 수 있습니다.

    text

    RSS 피드 확인
    → 관심 키워드 필터링
    → 제목과 링크 추출
    → 짧은 요약 생성
    → 텔레그램 봇으로 전송
    

    여기서 중요한 건 요약 범위입니다. 기사 본문을 길게 복사해 보내기보다, 직접 읽을지 판단할 수 있을 정도의 짧은 메모만 남기는 편이 좋습니다. 예를 들면 “AI 반도체 수요 관련 기사, 기업 실적 전망 중심”처럼 요약은 짧게, 원문은 링크로 두는 방식입니다.

    저작권은 자동화할수록 더 조심해야 합니다

    뉴스 자동화에서 가장 애매해지는 부분이 저작권입니다. 사람이 직접 읽고 메모하는 것과 달리, 시스템이 정기적으로 본문을 수집하고 저장하면 성격이 달라질 수 있습니다.

    그래서 기준을 보수적으로 잡는 편이 좋습니다.

    항목 권장 방식
    기사 본문 전체 저장하지 않기
    텔레그램 전송 내용 제목, 출처, 링크, 짧은 요약 위주
    보관 기간 필요한 경우에만 짧게 유지
    공유 범위 개인 채팅방 또는 비공개 채널 중심
    원문 확인 공식 기사 링크로 이동

    이렇게 해두면 자동화의 편의는 가져가면서도, 불필요하게 원문을 복제하는 구조는 피할 수 있습니다. 여러 사람이 보는 채널에 보내는 경우라면 더 보수적으로 운영하는 것이 맞습니다.

    뉴스 요약 자동화 참고 이미지

    로그와 실패 처리는 꼭 챙겨야 합니다

    처음에는 메시지만 잘 오면 끝난 것처럼 보입니다. 하지만 며칠 돌려보면 RSS 피드가 일시적으로 막히거나, 특정 언론사 링크 형식이 바뀌거나, 요약 API 응답이 늦어지는 일이 생깁니다.

    그래서 최소한 실패 로그, 중복 전송 방지, 재시도 횟수는 넣어두는 것이 좋습니다. 같은 기사가 하루에 여러 번 오면 금방 피로해지고, 실패했는데 조용히 넘어가면 자동화의 신뢰도가 떨어집니다.

    Docker Compose로 올린다면 컨테이너 로그를 확인하기 쉽게 두고, 중요한 오류만 별도 텔레그램 알림으로 보내는 방식도 괜찮습니다. 홈서버 자동화는 화려한 기능보다 이런 기본기가 더 오래 갑니다.

    관심 키워드는 좁게 시작하는 편이 좋습니다

    처음부터 “IT 뉴스 전체”처럼 넓게 잡으면 알림이 너무 많아집니다. 차라리 홈서버, NAS, Docker, 보안 업데이트, AI 인프라처럼 직접 챙겨볼 주제를 좁게 정하는 편이 실사용에 맞습니다.

    며칠 받아본 뒤 필요 없는 키워드는 빼고, 자주 놓치는 주제는 추가하면 됩니다. 자동화는 한 번에 완성하는 작업이라기보다 알림의 밀도를 계속 맞춰가는 과정에 가깝습니다.

    텔레그램 알림 자동화 참고 이미지

    정리하면 정보 확인이 가벼워집니다

    기사 요약 자동화는 거창한 시스템이라기보다, 매일 반복하던 확인 작업을 줄이는 도구에 가깝습니다. 홈서버에 n8n이나 간단한 Python 스크립트를 올려두고 원문 링크 중심의 짧은 요약만 텔레그램으로 받아도 충분히 실용적입니다.

    다만 편하다는 이유로 기사 본문을 그대로 모으거나 공유하는 구조로 만들면 문제가 될 수 있습니다. 처음부터 “기사를 대신 읽어주는 도구”가 아니라 읽을 기사를 고르는 도구로 기준을 잡아두는 편이 좋습니다.

  • 홈서버 자동화 작업 추천 백업 알림 모니터링 구성

    홈서버 자동화 작업 추천 백업 알림 모니터링 구성

    자동화는 작은 반복 작업부터 시작합니다

    홈서버를 켜두고 나면 처음에는 파일 저장이나 개인 웹서비스 정도만 떠올리기 쉽습니다. 그런데 운영 시간이 쌓이면 매일 확인해야 하는 작업이 생각보다 많아집니다. 이때 자동화를 잘 잡아두면 서버를 들여다보는 시간이 줄고, 운영 부담도 꽤 가벼워집니다.

    홈서버 자동화 작업 구상

    처음부터 거창한 시스템을 만들 필요는 없습니다. 직접 구성해보면 백업, 알림, 정리, 모니터링처럼 반복 주기가 분명한 작업부터 자동화하는 쪽이 체감이 큽니다.

    예를 들어 매일 새벽 특정 폴더를 백업하고, 실패하면 텔레그램이나 디스코드로 알림을 받는 정도만 해도 충분히 실용적입니다. Oracle Cloud Free Tier 같은 ARM 서버, Synology NAS, Docker Compose 기반 홈랩에서도 이런 수준의 자동화는 비교적 부담 없이 시작할 수 있습니다.

    먼저 해볼 만한 자동화 작업

    자동화 후보는 많지만, 처음에는 실패해도 복구가 쉽고 성공하면 바로 편해지는 작업을 고르는 편이 좋습니다. 홈서버에서 자주 구성하는 흐름을 기준으로 정리하면 다음과 같습니다.

    작업명 주요 역할 추천 도구 추천 대상
    파일 백업 자동화 지정 폴더를 NAS, MinIO, 외장 스토리지로 주기 백업 rclone, restic, borg 사진·문서 보관이 많은 경우
    컨테이너 업데이트 확인 Docker 이미지 새 버전 확인 및 알림 Watchtower, Diun 여러 서비스를 Docker로 돌리는 경우
    서버 상태 알림 CPU, RAM, 디스크, 네트워크 상태 감시 Uptime Kuma, Netdata, Grafana 장애를 빨리 알고 싶은 경우
    로그 정리 오래된 로그 압축·삭제 logrotate, cron 디스크 용량이 자주 줄어드는 경우
    SSL 인증서 갱신 HTTPS 인증서 자동 갱신 Caddy, Traefik, Nginx Proxy Manager 외부 접속 서비스를 운영하는 경우
    미디어 파일 정리 다운로드 파일명 정리, 폴더 이동 FileBot, Sonarr, Radarr 개인 미디어 서버를 쓰는 경우
    사진 자동 분류 업로드 사진을 날짜별로 정리 Immich, PhotoPrism, Synology Photos 스마트폰 사진 백업이 많은 경우
    정기 리포트 발송 서버 상태나 백업 결과를 메일로 전달 cron, shell script, Gotify 점검 기록을 남기고 싶은 경우

    이 중 하나만 먼저 고른다면 백업 자동화가 가장 무난합니다. 홈서버는 결국 데이터를 오래 보관하는 장비에 가깝기 때문에, 서비스 편의 기능보다 백업 체계가 먼저 안정돼야 합니다.

    서버 자동화와 작업 흐름

    백업은 성공 여부 확인까지 포함해야 합니다

    백업 스크립트를 만들어두는 것만으로는 부족합니다. 중요한 건 백업이 실제로 성공했는지 확인하는 과정까지 자동화하는 것입니다.

    예를 들어 rclone으로 MinIO나 NAS에 백업을 보낸다면, 단순 복사 명령만 cron에 넣기보다 실행 결과를 로그로 남기고 실패 시 알림을 보내는 방식이 좋습니다. restic이나 borg를 쓰면 스냅샷 기반으로 보관할 수 있어, 실수로 지운 파일을 되돌리기에도 편합니다.

    기본 흐름은 아래처럼 잡을 수 있습니다.

    bash

    0 3 * * * /usr/local/bin/backup-home.sh >> /var/log/home-backup.log 2>&1
    

    이 설정은 매일 새벽 3시에 백업 스크립트를 실행하고 로그를 남기는 형태입니다. 여기에 스크립트 내부에서 실패 여부를 확인하고 알림까지 보내면 운영 부담이 확 줄어듭니다. 다만 실제 경로, 인증 정보, 저장소 주소는 환경마다 다르므로 그대로 복사하기보다 본인 서버 구조에 맞춰 조정해야 합니다.

    컨테이너 업데이트는 자동 적용보다 알림이 먼저입니다

    Docker Compose로 서비스를 여러 개 올려두면 업데이트 관리도 일이 됩니다. 그렇다고 모든 이미지를 자동으로 최신 버전으로 올리는 방식은 조심해야 합니다. 특히 데이터베이스, 인증, 리버스 프록시가 얽힌 서비스는 버전 변경만으로 설정이 깨질 수 있습니다.

    그래서 처음에는 자동 업데이트보다 업데이트 알림 자동화를 먼저 두는 편이 낫습니다. Diun 같은 도구로 새 이미지가 나왔는지만 알려받고, 실제 반영은 주말이나 점검 가능한 시간에 직접 하는 방식입니다.

    Watchtower도 편하지만, 개인 서비스가 여러 개 묶여 있다면 처음에는 모니터링 용도로만 써보는 것이 부담이 적습니다. 자동화의 목적은 손을 덜 대는 것이지, 문제가 생겼을 때 원인을 더 찾기 어렵게 만드는 것이 아닙니다.

    홈서버 모니터링과 자동화 구성

    알림 채널은 한곳으로 모으는 편이 좋습니다

    홈서버 자동화가 늘어나면 알림도 함께 늘어납니다. 백업 성공, 백업 실패, 디스크 용량 부족, 서비스 다운, 인증서 갱신 결과가 각각 다른 곳으로 오면 알림을 확인하는 일 자체가 피곤해집니다.

    이럴 때는 Gotify, Telegram Bot, Discord Webhook 중 하나를 정해 서버 알림을 한곳으로 모아두는 편이 관리하기 쉽습니다. 폐쇄적으로 쓰려면 Gotify가 깔끔하고, 외부에서도 바로 확인하려면 텔레그램이나 디스코드가 접근성이 좋습니다.

    알림 기준도 너무 촘촘하게 잡을 필요는 없습니다. 성공 알림은 하루 1회 요약으로 묶고, 실패나 용량 부족처럼 바로 확인해야 하는 항목만 즉시 알림으로 보내는 정도가 적당합니다.

    우선순위는 데이터 보호부터 잡습니다

    처음 홈서버 자동화를 구성한다면 순서를 정해두는 것이 좋습니다. 제 기준에서는 데이터 보호 → 장애 확인 → 유지보수 절감 → 편의 기능 순서가 안정적입니다.

    1. 백업 자동화와 복구 테스트
    2. 디스크 용량, 서비스 다운 알림
    3. 로그 정리와 인증서 갱신
    4. 컨테이너 업데이트 확인
    5. 사진, 미디어, 다운로드 파일 정리
    6. 정기 리포트와 대시보드 구성

    이 순서로 진행하면 서버 운영이 조금씩 손에 익습니다. 특히 복구 테스트는 한 번쯤 꼭 해보는 게 좋습니다. 백업 파일이 있어도 실제로 되돌려본 적이 없다면, 장애 상황에서 그 백업을 믿기 어렵습니다.

    정리해두면 운영이 가벼워집니다

    홈서버 자동화는 화려한 기능보다 반복 작업을 조용히 줄여주는 구성이 오래 갑니다. 백업, 알림, 모니터링, 정리 작업만 차근차근 묶어도 매번 서버에 접속해 확인하던 시간이 줄어듭니다.

    처음부터 모든 것을 자동화하려고 하기보다, 지금 가장 자주 확인하는 작업 하나를 골라 cron이나 Docker Compose 기반으로 작게 붙여보면 됩니다. 그렇게 하나씩 쌓아두면 홈서버는 단순한 장비를 넘어, 생활 속에서 꾸준히 일해주는 개인 인프라에 가까워집니다.

  • 로컬 LLM 모델 비교 Qwen Gemma 홈서버 선택 기준

    로컬 LLM 모델 비교 Qwen Gemma 홈서버 선택 기준

    로컬 LLM에서 먼저 보는 기준

    로컬 LLM을 홈서버에 올려보려면 모델 이름보다 먼저 확인할 것이 있습니다. 내 장비에서 계속 켜둘 수 있는지, 그리고 한국어 질문에 대한 답변 품질이 크게 무너지지 않는지입니다.

    로컬 LLM 홈서버 구성 참고 이미지

    Qwen과 Gemma는 로컬 실행 후보로 자주 언급되는 모델입니다. 다만 성격은 조금 다릅니다. Qwen은 코딩, 추론, 다국어 대응 쪽으로 폭넓게 확장하는 느낌이 강하고, Gemma는 구글 생태계 안에서 문서와 배포 흐름이 비교적 정돈된 편입니다.

    홈서버 기준에서는 최고 성능보다 GGUF, Ollama, LM Studio, llama.cpp 같은 실행 환경에서 얼마나 쉽게 굴러가는지가 더 중요할 때가 많습니다. GPU 여유가 크지 않다면 4bit 양자화 모델부터 확인하는 쪽이 현실적입니다.

    Qwen 쪽 인상

    Qwen은 공식 블로그 기준으로 Qwen3에서 0.6B, 1.7B, 4B, 8B, 14B, 32B 같은 dense 모델과 MoE 모델을 공개했습니다. 공식 안내에서도 Ollama, LM Studio, MLX, llama.cpp 등을 로컬 사용 도구로 언급하고 있어 홈랩 환경과 잘 맞는 편입니다.

    참고: Qwen3 공식 블로그

    한국어 사용감은 모델 크기와 양자화 상태에 따라 차이가 납니다. 작은 모델은 빠르지만 긴 문맥을 이어가는 글쓰기나 복잡한 질문에서는 답변이 짧아지는 편입니다. 개인 서버에서도 어느 정도 활용성을 기대하려면 8B 이상부터 체감이 좋아지는 편입니다.

    로컬 서버와 모델 비교 참고 이미지

    Gemma 쪽 인상

    Gemma는 Google AI 문서 기준으로 Gemma 4가 E2B, E4B, 12B, 26B A4B, 31B 구성을 갖고 있습니다. 문서상으로는 텍스트뿐 아니라 이미지, 비디오, 일부 모델의 오디오 입력까지 확장되어 있고, 로컬 실행용 GGUF와 QAT 체크포인트도 안내되어 있습니다.

    참고: Gemma 공식 문서

    Gemma의 장점은 문서 흐름이 깔끔하다는 점입니다. 어떤 크기를 고르면 되는지, 양자화 모델을 어디서 받아야 하는지 찾기 편합니다. 다만 이전 Gemma 계열은 라이선스나 사용 조건 확인이 필요했기 때문에, 실제 배포 전에는 현재 모델 카드와 라이선스 문서를 다시 보는 것이 좋습니다.

    Qwen과 Gemma 비교

    모델 가격 주요 특징 추천 대상
    Qwen 무료 공개 가중치 모델 중심 코딩, 추론, 다국어, 로컬 실행 도구 지원 폭이 넓음 홈서버에서 챗봇, 코딩 보조, RAG 실험을 함께 해보고 싶은 사람
    Gemma 무료 공개 가중치 모델 중심 공식 문서, QAT, GGUF, 구글 생태계 연동이 잘 정리됨 안정적인 문서와 배포 경로를 따라 차근차근 구성하려는 사람

    홈서버에서는 어떤 쪽이 편할까

    직접 홈서버에 올린다고 생각하면, 처음부터 큰 모델을 고르기보다 작은 모델부터 확인하는 쪽이 덜 피곤합니다. CPU나 저전력 서버라면 Qwen 4B급, Gemma E2B/E4B급 양자화 모델부터 테스트하고, GPU 여유가 있으면 8B 이상으로 넘어가는 방식이 현실적입니다.

    Oracle Cloud Free Tier ARM 같은 환경에서는 대형 모델 자체보다 API 서버, 벡터DB, 웹 UI를 함께 올릴 수 있는 균형이 더 중요합니다. Synology나 미니 PC도 마찬가지입니다. 모델 하나가 잘 돌아가더라도 메모리 여유가 부족하면 RAG나 웹 UI에서 금방 답답해질 수 있습니다.

    홈서버 로컬 AI 구성 참고 이미지

    정리

    코딩 보조와 실험 폭을 넓게 가져가고 싶다면 Qwen, 문서와 배포 흐름을 따라 안정적으로 시작하고 싶다면 Gemma가 편합니다.

    둘 다 로컬 LLM 입문용으로 충분히 의미가 있습니다. 다만 홈서버에서는 모델 이름만 보고 고르기보다 메모리, 양자화 포맷, 실행 도구 호환성을 먼저 맞춰보는 것이 시행착오를 줄이는 데 도움이 됩니다.

  • 리눅스 데스크톱 홈서버 입문자를 위한 GUI 관리 방법

    리눅스 데스크톱 홈서버 입문자를 위한 GUI 관리 방법

    터미널이 부담스러운 사람에게 맞는 출발점

    리눅스를 처음 데스크톱으로 쓰려는 분들이 가장 많이 부딪히는 지점은 성능보다 관리 방식입니다. 서버처럼 검은 터미널만 붙잡고 운영해야 한다고 생각하면 시작 전부터 부담이 커집니다. 하지만 요즘 리눅스 데스크톱은 생각보다 훨씬 친절합니다.

    리눅스 데스크톱 참고 이미지

    홈서버를 직접 굴리다 보면 SSH 접속, 패키지 업데이트, 로그 확인 같은 작업을 피하기 어렵습니다. 다만 처음부터 모든 작업을 명령어로 처리할 필요는 없습니다. 리눅스 데스크톱 환경을 올려두면 파일 관리, 네트워크 설정, 디스크 확인 같은 기본 작업을 화면에서 직접 확인하며 처리할 수 있습니다.

    GNOME, KDE Plasma, Xfce 같은 데스크톱 환경은 윈도우를 써본 사람이라면 비교적 빠르게 익숙해질 수 있는 구조입니다. 설정 앱에서 와이파이, 사용자 계정, 디스플레이, 업데이트를 확인할 수 있고, 파일 탐색기에서 공유 폴더나 외장 디스크에 접근하기도 쉽습니다.

    서버를 공부하려고 리눅스를 설치했는데 터미널 때문에 막히는 경우가 많습니다. 이럴 때 데스크톱 환경은 좋은 완충 장치가 됩니다. 명령어를 몰라도 시스템 상태를 눈으로 확인할 수 있다는 점이 초반 진입장벽을 낮춰줍니다.

    홈서버 입문자에게 맞는 선택

    홈서버 구축 관점에서 보면 리눅스 데스크톱은 “서버답지 않은 선택”이라기보다 관리 방식을 넓혀주는 선택에 가깝습니다. 예를 들어 Rocky Linux 9.x나 Ubuntu LTS 계열에 데스크톱 환경을 얹고, Docker Compose v2로 서비스를 관리하면 GUI와 터미널을 함께 사용할 수 있습니다.

    리눅스 데스크톱 작업 환경 참고 이미지

    NAS나 미니PC를 24시간 켜두는 환경이라면 화면을 항상 연결해둘 필요는 없습니다. 처음 설정할 때만 데스크톱으로 잡아두고, 어느 정도 익숙해진 뒤에는 SSH 접속 위주로 넘어가도 됩니다. 핵심은 처음부터 CLI만 고집하지 않아도 된다는 점입니다.

    제품 장점 단점
    Ubuntu Desktop LTS 자료가 많고 드라이버 지원이 좋아 입문자에게 부담이 적음 서버 용도로는 기본 설치 구성이 다소 무겁게 느껴질 수 있음
    Linux Mint 윈도우와 비슷한 사용감이라 적응이 빠름 서버 운영 자료는 Ubuntu Server 기준보다 상대적으로 적음
    Fedora Workstation 최신 커널과 패키지를 빠르게 경험할 수 있음 장기 운영보다는 업데이트 흐름을 꾸준히 따라가야 함
    Rocky Linux 9.x + GUI RHEL 계열 서버 환경과 가까워 운영 연습에 좋음 데스크톱 편의성은 Ubuntu 계열보다 덜 친절하게 느껴질 수 있음

    그래픽 환경이 항상 낭비는 아닙니다

    서버 운영을 조금 해본 분들은 데스크톱 환경을 올리면 리소스를 낭비한다고 말하기도 합니다. 틀린 말은 아닙니다. RAM이 1GB나 2GB 수준인 작은 VPS라면 GUI는 부담이 됩니다.

    하지만 집에서 쓰는 미니PC, 남는 노트북, Synology 외 별도 테스트 장비처럼 자원이 어느 정도 있는 환경이라면 이야기가 달라집니다. 배우는 속도와 관리 편의성도 운영 비용의 일부로 봐야 합니다.

    디스크 마운트가 꼬였을 때, 네트워크 연결을 확인할 때, Docker 볼륨 위치를 정리할 때 화면이 있으면 실수를 줄이기 쉽습니다. 터미널에서 lsblk, ip addr, journalctl을 하나씩 치는 방식도 중요하지만, 처음에는 GUI로 구조를 이해하고 필요한 순간에 명령어를 붙이는 흐름이 더 자연스럽습니다.

    리눅스 시스템 관리 참고 이미지

    어디까지 데스크톱으로 관리할까

    리눅스 데스크톱을 쓴다고 해서 모든 관리를 마우스로 끝낼 수 있는 건 아닙니다. Docker 컨테이너 재시작, 방화벽 설정, 서비스 로그 확인처럼 결국 터미널이 필요한 순간은 옵니다. 다만 그 시점이 꼭 설치 첫날일 필요는 없습니다.

    처음에는 업데이트, 파일 복사, 원격 접속 설정, 브라우저에서 관리자 페이지 접속 정도를 데스크톱으로 처리해도 충분합니다. 이후 Portainer, CasaOS, Cockpit 같은 웹 기반 관리 도구를 붙이면 터미널 의존도는 더 줄어듭니다. 터미널을 완전히 피하기보다 천천히 익숙해지는 구조가 현실적입니다.

    리눅스 데스크톱은 홈서버를 처음 만지는 사람에게 좋은 출발점이 될 수 있습니다. 서버 운영의 본질을 흐리는 선택이라기보다, 시스템을 눈으로 이해하고 실수를 줄이기 위한 발판에 가깝습니다. 어느 정도 익숙해진 뒤에는 필요한 서비스만 남기고 가볍게 운영하는 방향으로 바꿔도 늦지 않습니다.

  • 홈서버 로컬 LLM 구축 Ollama Docker로 소형 모델 올리기

    홈서버 로컬 LLM 구축 Ollama Docker로 소형 모델 올리기

    홈서버에서 로컬 LLM을 돌려보는 이유

    책상 위에 놓인 작은 서버가 문서 요약이나 간단한 질의응답까지 해주면 생각보다 쓸모가 많습니다. 거창한 GPU 서버가 아니어도 1B~3B급 소형 LLM부터 올려보면, 홈서버에서 어디까지 가능한지 감을 잡을 수 있습니다.

    이번 구성은 Rocky Linux 9.x / Docker Engine 28.x / Docker Compose v2.x / Ollama Docker 이미지 조합을 기준으로 정리했습니다. Oracle Cloud Free Tier ARM 같은 저전력 서버나 시놀로지에서 Docker를 쓰는 환경도 큰 흐름은 비슷합니다.

    홈서버 로컬 LLM 구성 참고 이미지

    Ollama를 Docker로 올리기

    Ollama는 리눅스 설치 스크립트도 제공하지만, 홈서버에서는 나중에 지우거나 옮기기 쉬운 Docker 방식이 관리하기 편했습니다. 공식 Docker Hub 기준으로 Ollama 컨테이너는 11434 포트를 사용합니다.

    mkdir -p ~/services/ollama
    cd ~/services/ollama
    
    services:
      ollama:
        image: ollama/ollama:latest
        container_name: ollama
        restart: unless-stopped
        ports:
          - "127.0.0.1:11434:11434"
        volumes:
          - ollama:/root/.ollama
    
    volumes:
      ollama:
    
    docker compose up -d
    docker exec -it ollama ollama --version
    

    포트를 127.0.0.1로 묶은 이유는 단순합니다. LLM API를 인터넷에 바로 노출하지 않기 위해서입니다. 내부망 밖에서 접근해야 한다면 VPN, Tailscale, 리버스 프록시 인증 같은 보호 장치를 먼저 붙이는 편이 낫습니다.

    작은 모델부터 테스트하기

    처음부터 7B, 14B 모델을 받으면 다운로드도 오래 걸리고 메모리도 금방 부족해집니다. 홈서버에서는 1B~3B 모델로 시작하는 편이 현실적입니다.

    docker exec -it ollama ollama pull llama3.2:1b
    docker exec -it ollama ollama run llama3.2:1b
    

    간단한 호출은 curl로 바로 확인할 수 있습니다.

    curl http://127.0.0.1:11434/api/chat \
      -d '{
        "model": "llama3.2:1b",
        "messages": [
          {
            "role": "user",
            "content": "홈서버에서 로컬 LLM을 돌릴 때 장점 3가지만 짧게 정리해줘."
          }
        ],
        "stream": false
      }'
    

    응답이 느리더라도 일단 동작하면 기본 구성은 된 셈입니다. CPU만 쓰는 서버라면 속도보다 상시 실행 가능 여부와 메모리 여유를 먼저 확인하는 게 좋습니다.

    로컬 서버와 인공지능 구성을 떠올리게 하는 이미지

    홈서버용 소형 LLM 후보

    Ollama 라이브러리 기준으로 llama3.2는 1B와 3B 모델을 제공하고, qwen2.5는 0.5B부터 3B까지 작은 선택지가 넓습니다. gemma3도 270M, 1B처럼 가벼운 모델이 있어 테스트용으로 부담이 적습니다.

    순위 제품명 핵심 강점 총평 평점
    1 llama3.2:1b 가볍고 시작이 빠름 CPU 홈서버에서 첫 테스트용으로 무난합니다 4.5
    2 qwen2.5:1.5b 크기와 답변 품질의 균형 한국어 질문도 간단한 용도라면 꽤 버팁니다 4.3
    3 qwen2.5:3b 조금 더 나은 답변 품질 메모리 여유가 있으면 1B급보다 만족도가 올라갑니다 4.2
    4 gemma3:1b 작은 용량과 빠른 테스트 가벼운 질의응답, 요약 실험에 맞습니다 4.0

    이 점수는 절대 성능표가 아니라 홈서버에서 굴려볼 때의 체감 기준에 가깝습니다. 특히 CPU 서버라면 3B 모델부터 답변 대기 시간이 꽤 느껴질 수 있습니다.

    모델 파일과 저장공간 관리

    모델 파일은 생각보다 빨리 쌓입니다. 내려받은 모델은 ollama list로 확인하고, 잘 쓰지 않는 모델은 정리하는 편이 좋습니다.

    docker exec -it ollama ollama list
    docker exec -it ollama ollama rm qwen2.5:3b
    

    시놀로지나 미니PC처럼 저장공간이 넉넉하지 않은 장비라면 모델을 여러 개 받아두기보다 하나씩 비교하고 지우는 방식이 낫습니다. 백업 대상에도 모델 볼륨을 꼭 포함할 필요는 없습니다. 다시 받을 수 있는 파일이라면 설정만 따로 관리해도 충분합니다.

    로컬 LLM과 홈서버 운영을 연상시키는 이미지

    어디까지 기대할 수 있을까

    소형 LLM은 대형 모델처럼 긴 추론이나 복잡한 코딩을 매끄럽게 처리하진 못합니다. 대신 개인 메모 요약, 짧은 문장 다듬기, 로그 설명, 내부 문서 초안 정리 같은 작업에는 꽤 현실적인 재미가 있습니다.

    나중에 Open WebUI 같은 웹 인터페이스를 붙이면 개인 장비나 가족용 브라우저에서도 접근하기 편합니다. 다만 이때도 인증 없이 외부에 열어두는 구성은 피해야 합니다.

    공식 안내는 아래 링크에서 확인했습니다. 모델 크기와 태그는 바뀔 수 있으니 실제 설치 전에는 한 번 더 확인하는 편이 안전합니다.

    • Ollama Linux 설치: https://ollama.com/download/linux
    • Ollama Docker 이미지: https://hub.docker.com/r/ollama/ollama
    • Ollama 모델 라이브러리: https://ollama.com/library
  • 홈서버 소프트웨어 라이선스 오픈소스와 상용 제품 차이

    홈서버 소프트웨어 라이선스 오픈소스와 상용 제품 차이

    홈서버에서 라이선스를 먼저 봐야 하는 이유

    홈서버를 구성하다 보면 하드웨어보다 먼저 막히는 지점이 의외로 소프트웨어 라이선스입니다. 설치 자체는 금방 끝나지만, 개인 사용만 가능한지, 외부 접속을 열어도 되는지, 가족이나 팀원과 함께 써도 되는지는 따로 확인해야 합니다.

    Rocky Linux 9.x, Docker Compose v2, MinIO 같은 S3 호환 스토리지, 리버스 프록시, 모니터링 도구를 엮어 쓰는 구성이라면 더 그렇습니다. 홈서버라고 해도 여러 소프트웨어가 함께 돌아가는 운영 환경이기 때문에, 라이선스 범위를 대충 넘기기는 어렵습니다.

    홈서버와 소프트웨어 구성을 떠올리게 하는 서버 이미지

    오픈소스라고 전부 자유로운 것은 아닙니다

    오픈소스는 소스코드가 공개되어 있고, 정해진 조건 안에서 사용·수정·배포할 수 있는 소프트웨어입니다. 여기서 중요한 기준은 무료 여부가 아니라 사용 조건입니다.

    MIT, Apache 2.0 같은 라이선스는 개인 홈서버에서 쓰기 비교적 부담이 적은 편입니다. Docker로 서비스를 올리고 내부망이나 개인 도메인으로 접속하는 정도라면 대체로 큰 문제가 생기지 않습니다.

    다만 GPL 계열은 조금 더 신경 써야 합니다. 직접 수정한 프로그램을 외부에 배포하거나 공개 서비스에 붙일 때는 소스 공개 의무가 따라올 수 있습니다. 집에서 설치해 혼자 쓰는 수준이라면 부담이 크지 않지만, 수정본을 나눠주거나 상업 서비스에 연결하면 해석이 달라질 수 있습니다.

    라이선스 제품은 기능보다 사용 범위가 먼저입니다

    라이선스 제품은 구매하거나 구독해서 쓰는 상용 소프트웨어를 말합니다. 홈서버에서는 NAS 운영체제, 백업 솔루션, 가상화 관리 도구, 보안 제품에서 자주 마주칩니다.

    이런 제품은 기능표만 보면 매력적으로 보이지만, 실제로는 개인용·비상업용·상업용·사용자 수·장치 수 같은 조건이 더 중요합니다. 무료 플랜이라고 해도 서버 설치가 제한되어 있거나, 기업망 사용이 금지되는 경우가 있습니다.

    특히 홈서버를 가족용에서 소규모 팀, 동호회, 외부 사용자용으로 넓히면 개인 사용 범위를 벗어날 수 있습니다. 이때는 “돈을 받지 않으니 괜찮다”보다 약관에 적힌 사용 범위를 확인하는 쪽이 안전합니다.

    네트워크와 서버 운영을 연상시키는 기술 이미지

    홈서버에서 자주 만나는 선택지

    홈서버에서 자주 비교하게 되는 소프트웨어 유형을 정리하면 다음과 같습니다.

    구분 장점 주의할 점
    오픈소스 소프트웨어 비용 부담이 낮고 수정·자동화·Docker 배포가 자유로운 편입니다 라이선스별 의무가 다르며, 문제 발생 시 직접 해결해야 하는 경우가 많습니다
    무료 상용 제품 설치가 쉽고 UI가 정리되어 있어 입문자가 접근하기 좋습니다 개인용 제한, 기능 제한, 사용자 수 제한이 붙을 수 있습니다
    유료 라이선스 제품 공식 지원, 업데이트, 관리 기능이 안정적인 편입니다 장치 수나 사용자 수에 따라 비용이 늘고, 홈랩 규모에서는 과할 수 있습니다

    설치 전에 확인할 핵심 항목

    개인적으로는 설치 전에 라이선스 전문을 처음부터 끝까지 읽기보다, 먼저 세 가지를 확인합니다. 개인 사용 허용 여부, 외부 공개 가능 여부, 수정·배포 조건입니다.

    MinIO 같은 S3 호환 스토리지를 올리고, 리버스 프록시로 여러 서비스를 묶고, 대시보드까지 붙이면 외부 접속 구조가 자연스럽게 생깁니다. 이때 단순 내부 테스트인지, 실제 사용자에게 열어두는 서비스인지에 따라 라이선스 해석이 달라질 수 있습니다.

    Docker 이미지도 따로 봐야 합니다. 컨테이너로 배포된다고 해서 라이선스 조건이 사라지는 것은 아닙니다. 이미지 안에 포함된 애플리케이션, 플러그인, 폰트, 데이터베이스에도 각각 다른 조건이 있을 수 있습니다.

    흔히 헷갈리는 부분

    오픈소스와 무료 소프트웨어를 같은 의미로 쓰는 경우가 많지만, 실제로는 다릅니다. 무료지만 소스가 닫힌 제품도 있고, 오픈소스지만 특정 조건을 지켜야 하는 제품도 있습니다.

    홈서버에서는 “혼자 쓰니까 괜찮겠지” 하고 넘어가기 쉽습니다. 개인 메모, 사진 백업, 미디어 서버 정도라면 대체로 부담이 적지만, 외부 계정을 만들어주거나 커뮤니티용 서비스로 확장하면 확인할 항목이 늘어납니다.

    상업용 여부도 단순히 매출 발생만 뜻하지는 않습니다. 회사 업무 자료를 올리거나, 사무실 장비에서 운영하거나, 업무용 계정으로 접속하게 하면 개인 홈랩과 다르게 볼 여지가 있습니다.

    서버 운영과 개발 환경을 떠올리게 하는 작업 이미지

    오래 운영하려면 기록이 필요합니다

    홈서버 구축 초반에는 기능이 먼저 눈에 들어오지만, 오래 운영하려면 라이선스 메모를 남겨두는 편이 좋습니다. 서비스 이름, 버전, 라이선스 종류, 공식 링크 정도만 정리해도 나중에 교체하거나 공개 범위를 바꿀 때 판단이 빨라집니다.

    특히 백업, 스토리지, 인증, 모니터링처럼 서버 핵심에 붙는 소프트웨어는 업데이트 정책과 라이선스 변경 가능성도 함께 봐두는 것이 좋습니다. 예전에는 자유롭게 쓰던 기능이 어느 순간 유료 플랜으로 이동하는 경우도 있습니다.

    정리하면, 홈서버에서 오픈소스는 자유도가 큰 대신 조건을 직접 확인해야 하고, 라이선스 제품은 편의성이 있는 대신 사용 범위가 더 명확하게 제한됩니다. 처음부터 모든 항목을 완벽하게 따질 필요는 없지만, 외부 공개나 공동 사용으로 넘어가는 시점에는 한 번 멈춰서 라이선스를 확인하는 습관이 필요합니다.

  • Rocky Linux 9 SSH 포트 변경과 SELinux 접속 오류 해결

    Rocky Linux 9 SSH 포트 변경과 SELinux 접속 오류 해결

    서버를 처음 열어둘 때 가장 긴장되는 순간은 설치보다 SSH 설정을 바꾼 직후입니다. Rocky Linux 9에서 sshd_config의 포트만 바꾸고 재시작했다가 접속이 막히면 복구가 번거로워집니다. SSH 포트 변경은 단순히 숫자 하나를 바꾸는 작업이 아니라 sshd 설정, SELinux, firewalld 세 군데를 함께 맞추는 작업입니다.

    홈서버 SSH 설정 참고 이미지

    먼저 끊지 말아야 할 것

    Rocky Linux 9.x에서 작업할 때 가장 먼저 지켜야 할 것은 명령어 순서보다 현재 SSH 세션을 유지하는 것입니다. 설정을 바꾼 뒤 기존 터미널을 바로 닫으면, 새 포트 접속이 실패했을 때 되돌아갈 통로가 사라질 수 있습니다.

    오라클 클라우드 같은 VPS 환경에서는 서버 내부의 firewalld만 열어서는 부족합니다. 콘솔의 Security List 인바운드 규칙에서도 새 SSH 포트를 허용해야 합니다. 집에서 운영하는 홈서버라면 공유기 포트포워딩도 함께 확인해야 합니다.

    확인 항목 해야 할 일
    기존 SSH 세션 닫지 않고 유지
    새 터미널 변경 포트로 접속 테스트
    클라우드 방화벽 Security List 인바운드 허용
    홈서버 공유기 포트포워딩 확인
    비상 접속 콘솔, IPMI, 시리얼 콘솔 확보

    1단계, sshd_config에서 포트 지정

    예시는 2222 포트로 진행하겠습니다. 기본 설정 파일을 직접 수정해도 되고, Rocky Linux 9에서는 /etc/ssh/sshd_config.d/ 아래에 별도 설정 파일을 두는 방식도 사용할 수 있습니다.

    기본 파일을 수정한다면 아래처럼 엽니다.

    sudo vi /etc/ssh/sshd_config
    

    그리고 Port 값을 지정합니다.

    Port 2222
    

    drop-in 방식으로 관리하고 싶다면 별도 파일을 만들어도 됩니다.

    sudo vi /etc/ssh/sshd_config.d/10-custom-port.conf
    
    Port 2222
    

    여기까지만 하고 sshd를 재시작하면 접속이 막힐 수 있습니다. Rocky Linux 계열에서는 SELinux가 해당 포트를 SSH용 포트로 허용하는지를 따로 확인해야 합니다.

    2단계, SELinux 포트 컨텍스트 추가

    이 글에서 가장 중요한 부분입니다. SELinux를 enforcing 상태로 유지하면서 새 포트를 SSH용으로 등록해야 합니다. setenforce 0으로 넘기는 방식은 당장은 편해 보여도, 서버 운영 기준으로는 권장하기 어렵습니다.

    먼저 semanage 명령이 없다면 패키지를 설치합니다.

    sudo dnf install policycoreutils-python-utils
    

    새 SSH 포트를 등록합니다.

    sudo semanage port -a -t ssh_port_t -p tcp 2222
    

    이미 같은 포트가 등록되어 있거나 기존 항목을 수정해야 한다면 -a 대신 -m을 사용합니다.

    sudo semanage port -m -t ssh_port_t -p tcp 2222
    

    등록 여부는 아래 명령으로 확인합니다.

    sudo semanage port -l | grep ssh
    

    정상이라면 ssh_port_t 항목에 2222가 포함되어 있어야 합니다. Rocky Linux 9에서 SSH 포트 변경 후 접속이 안 되는 문제는 이 SELinux 포트 컨텍스트에서 걸리는 경우가 많습니다.

    3단계, firewalld에서 포트 열기

    SELinux까지 맞췄다면 이제 OS 방화벽을 열 차례입니다. Rocky Linux 9 기준으로는 firewalld를 사용합니다.

    sudo firewall-cmd --permanent --add-port=2222/tcp
    sudo firewall-cmd --reload
    

    기존 22번 포트를 닫을지는 바로 결정하지 않는 편이 안전합니다. 새 포트 접속이 확실히 되는 것을 확인한 뒤 닫아도 늦지 않습니다.

    sudo firewall-cmd --permanent --remove-service=ssh
    sudo firewall-cmd --reload
    

    이 명령은 선택 사항입니다. 운영 중인 서버라면 새 포트 접속 성공 확인 후 기존 SSH 서비스 제거 순서로 진행하는 것이 안전합니다.

    4단계, 적용하고 새 터미널에서 검증

    설정이 끝났다면 sshd를 재시작합니다.

    sudo systemctl restart sshd
    

    기존 터미널은 그대로 둔 상태에서 새 터미널을 열고 변경한 포트로 접속합니다.

    ssh -p 2222 user@host
    

    접속이 안 된다면 설정을 다시 감으로 고치기보다, 어디서 막혔는지 나눠서 확인하는 편이 빠릅니다.

    sudo ss -tlnp | grep 2222
    sudo journalctl -u sshd -n 50 --no-pager
    sudo firewall-cmd --list-ports
    sudo semanage port -l | grep ssh
    

    ss에서 2222 포트가 보이지 않으면 sshd 설정을 먼저 봐야 합니다. journalctl에서 SELinux 관련 거부 흔적이 보이면 포트 컨텍스트를 다시 확인해야 합니다. 클라우드 서버라면 이 단계에서 클라우드 보안 목록 인바운드 규칙도 함께 확인해야 합니다.

    정리해두면 덜 당황합니다

    SSH 포트 변경은 간단한 보안 설정처럼 보이지만, Rocky Linux 9에서는 sshd_config, SELinux, firewalld가 함께 맞아야 정상적으로 동작합니다. 특히 SELinux를 끄지 않고 포트 컨텍스트를 등록하는 것이 핵심입니다.

    포트 변경만으로 보안이 끝나는 것은 아닙니다. 이후에는 SSH 키 인증, 비밀번호 로그인 차단, fail2ban 같은 설정까지 이어가면 홈서버 운영을 더 안정적으로 가져갈 수 있습니다.