<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ubuntu 보관 - 하우인포-IT·테크</title>
	<atom:link href="https://howinfo.kr/tag/ubuntu/feed/" rel="self" type="application/rss+xml" />
	<link>https://howinfo.kr/tag/ubuntu/</link>
	<description>IT·AI 자동화 &#38; 인프라 전문 블로그 (하우인포)</description>
	<lastBuildDate>Thu, 12 Feb 2026 13:12:44 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://howinfo.kr/wp-content/uploads/2026/02/cropped-ChatGPT-Image-2026년-2월-12일-오후-05_39_40-32x32.png</url>
	<title>ubuntu 보관 - 하우인포-IT·테크</title>
	<link>https://howinfo.kr/tag/ubuntu/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Linux 기초 실습 가이드</title>
		<link>https://howinfo.kr/linux-%ea%b8%b0%ec%b4%88-%ec%8b%a4%ec%8a%b5-%ea%b0%80%ec%9d%b4%eb%93%9c/</link>
					<comments>https://howinfo.kr/linux-%ea%b8%b0%ec%b4%88-%ec%8b%a4%ec%8a%b5-%ea%b0%80%ec%9d%b4%eb%93%9c/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Thu, 12 Feb 2026 13:12:20 +0000</pubDate>
				<category><![CDATA[IT기초]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[리눅스]]></category>
		<category><![CDATA[리눅스기초]]></category>
		<category><![CDATA[리눅스명령어]]></category>
		<category><![CDATA[리눅스서버]]></category>
		<category><![CDATA[리눅스실습]]></category>
		<category><![CDATA[리눅스터미널]]></category>
		<category><![CDATA[서버기초]]></category>
		<category><![CDATA[서버운영기초]]></category>
		<category><![CDATA[시스템관리]]></category>
		<category><![CDATA[터미널명령어]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=1611</guid>

					<description><![CDATA[<p>터미널 명령어부터 서버 운영 감각까지 한 번에 익히기 운영체제를 이해했다면, 이제는 직접 만져볼 차례입니다.Linux는 “읽는 것”보다 “직접 입력해보는 것”이 훨씬...</p>
<p>게시물 <a href="https://howinfo.kr/linux-%ea%b8%b0%ec%b4%88-%ec%8b%a4%ec%8a%b5-%ea%b0%80%ec%9d%b4%eb%93%9c/">Linux 기초 실습 가이드</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">터미널 명령어부터 서버 운영 감각까지 한 번에 익히기</h2>



<p>운영체제를 이해했다면, 이제는 직접 만져볼 차례입니다.<br>Linux는 “읽는 것”보다 “직접 입력해보는 것”이 훨씬 중요합니다.</p>



<p>이 글에서는 <strong>실제로 가장 많이 사용하는 명령어 위주</strong>로 실습을 진행해보겠습니다.</p>



<p>👉 실습 환경: Ubuntu / NAS / Orange Pi / 가상머신 모두 가능</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">1️⃣ 현재 시스템 상태 확인하기</h1>



<h2 class="wp-block-heading">📌 현재 위치 확인</h2>



<pre class="wp-block-code"><code>pwd
</code></pre>



<p>현재 내가 있는 디렉토리 경로를 보여줍니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 파일 목록 보기</h2>



<pre class="wp-block-code"><code>ls
ls -al
</code></pre>



<ul class="wp-block-list">
<li><code>-a</code> : 숨김 파일 포함</li>



<li><code>-l</code> : 상세 정보 표시</li>
</ul>



<p>👉 서버 운영에서 가장 기본이 되는 명령어입니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">2️⃣ 디렉토리(폴더) 다루기</h1>



<h2 class="wp-block-heading">📌 디렉토리 이동</h2>



<pre class="wp-block-code"><code>cd /home
cd ..
cd ~
</code></pre>



<ul class="wp-block-list">
<li><code>..</code> → 상위 폴더</li>



<li><code>~</code> → 내 홈 디렉토리</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 디렉토리 생성</h2>



<pre class="wp-block-code"><code>mkdir test_folder
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 디렉토리 삭제</h2>



<pre class="wp-block-code"><code>rm -r test_folder
</code></pre>



<p>⚠ <code>-r</code> 옵션은 하위 폴더까지 삭제<br>⚠ 서버에서 매우 조심해야 합니다</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">3️⃣ 파일 다루기 실습</h1>



<h2 class="wp-block-heading">📌 파일 생성</h2>



<pre class="wp-block-code"><code>touch test.txt
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 파일 내용 확인</h2>



<pre class="wp-block-code"><code>cat test.txt
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 파일 편집 (nano 사용)</h2>



<pre class="wp-block-code"><code>nano test.txt
</code></pre>



<ul class="wp-block-list">
<li>수정 후 → <code>Ctrl + X</code></li>



<li>Y → 저장</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 파일 복사</h2>



<pre class="wp-block-code"><code>cp test.txt copy.txt
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 파일 이동 / 이름 변경</h2>



<pre class="wp-block-code"><code>mv copy.txt newname.txt
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">4️⃣ 권한(Permission) 이해하기</h1>



<p>파일 상세 보기:</p>



<pre class="wp-block-code"><code>ls -l
</code></pre>



<p>출력 예시:</p>



<pre class="wp-block-code"><code>-rwxr-xr--
</code></pre>



<p>구조:</p>



<pre class="wp-block-code"><code>&#91;소유자]&#91;그룹]&#91;기타 사용자]
</code></pre>



<h2 class="wp-block-heading">📌 권한 변경</h2>



<pre class="wp-block-code"><code>chmod 755 test.txt
</code></pre>



<p>755 의미:</p>



<ul class="wp-block-list">
<li>7 → 읽기+쓰기+실행</li>



<li>5 → 읽기+실행</li>



<li>5 → 읽기+실행</li>
</ul>



<p>👉 서버 보안의 기본입니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">5️⃣ 프로세스 확인하기</h1>



<h2 class="wp-block-heading">📌 실행 중인 프로세스 보기</h2>



<pre class="wp-block-code"><code>ps aux
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 실시간 모니터링</h2>



<pre class="wp-block-code"><code>top
</code></pre>



<p>종료: <code>q</code></p>



<p>👉 CPU 사용률, 메모리 확인 가능</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">6️⃣ 서비스 관리 (서버 운영 핵심)</h1>



<p>Linux는 대부분 <strong>systemd</strong> 기반입니다.</p>



<h2 class="wp-block-heading">📌 서비스 상태 확인</h2>



<pre class="wp-block-code"><code>systemctl status nginx
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 서비스 시작</h2>



<pre class="wp-block-code"><code>systemctl start nginx
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 부팅 시 자동 실행 설정</h2>



<pre class="wp-block-code"><code>systemctl enable nginx
</code></pre>



<p>👉 NAS, AI 서버 자동 실행 시 필수 개념</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">7️⃣ 로그 확인하기 (장애 분석 기본)</h1>



<pre class="wp-block-code"><code>tail -f /var/log/syslog
</code></pre>



<p>실시간 로그 확인</p>



<p>👉 장애 발생 시 가장 먼저 보는 영역</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">8️⃣ 패키지 설치 (Ubuntu 기준)</h1>



<pre class="wp-block-code"><code>sudo apt update
sudo apt install htop
</code></pre>



<p>설치 후 실행:</p>



<pre class="wp-block-code"><code>htop
</code></pre>



<p><code>top</code>보다 보기 편한 시스템 모니터링 도구</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">9️⃣ 네트워크 확인</h1>



<h2 class="wp-block-heading">📌 IP 확인</h2>



<pre class="wp-block-code"><code>ip addr
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">📌 포트 확인</h2>



<pre class="wp-block-code"><code>netstat -tulnp
</code></pre>



<p>👉 어떤 서비스가 어떤 포트를 사용하는지 확인 가능</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">🔟 실습 루틴 추천</h1>



<p>매일 10분씩 아래를 반복해보세요:</p>



<ol class="wp-block-list">
<li>폴더 만들기</li>



<li>파일 생성/수정</li>



<li>권한 변경</li>



<li>프로세스 확인</li>



<li>서비스 재시작</li>



<li>로그 확인</li>
</ol>



<p>2주만 해도 서버 감각이 생깁니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">📌 Linux 실습을 하면 생기는 변화</h1>



<p>✔ 서버가 무섭지 않습니다<br>✔ NAS 관리가 쉬워집니다<br>✔ 자동화가 이해됩니다<br>✔ 장애 분석이 가능해집니다<br>✔ Docker 구조가 이해됩니다</p>



<p>Linux는 “암기”가 아니라 “반복 실습”입니다.</p>
<p>게시물 <a href="https://howinfo.kr/linux-%ea%b8%b0%ec%b4%88-%ec%8b%a4%ec%8a%b5-%ea%b0%80%ec%9d%b4%eb%93%9c/">Linux 기초 실습 가이드</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/linux-%ea%b8%b0%ec%b4%88-%ec%8b%a4%ec%8a%b5-%ea%b0%80%ec%9d%b4%eb%93%9c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>파이썬으로 음성 알람 만들기: EdgeTTS 캐시 + 중복방지 + systemd 자동실행</title>
		<link>https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%9c%bc%eb%a1%9c-%ec%9d%8c%ec%84%b1-%ec%95%8c%eb%9e%8c-%eb%a7%8c%eb%93%a4%ea%b8%b0-edgetts-%ec%ba%90%ec%8b%9c-%ec%a4%91%eb%b3%b5%eb%b0%a9%ec%a7%80-systemd-%ec%9e%90/</link>
					<comments>https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%9c%bc%eb%a1%9c-%ec%9d%8c%ec%84%b1-%ec%95%8c%eb%9e%8c-%eb%a7%8c%eb%93%a4%ea%b8%b0-edgetts-%ec%ba%90%ec%8b%9c-%ec%a4%91%eb%b3%b5%eb%b0%a9%ec%a7%80-systemd-%ec%9e%90/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Thu, 12 Feb 2026 02:25:07 +0000</pubDate>
				<category><![CDATA[개발·코딩]]></category>
		<category><![CDATA[EdgeTTS]]></category>
		<category><![CDATA[sysemd]]></category>
		<category><![CDATA[tts]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[스마트홈]]></category>
		<category><![CDATA[알람시계]]></category>
		<category><![CDATA[오렌지파이5]]></category>
		<category><![CDATA[자동화]]></category>
		<category><![CDATA[파이썬]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=1594</guid>

					<description><![CDATA[<p>아침에 알람이 울리긴 하는데…“몇 시인지 말로 알려주면 진짜 바로 일어나겠는데?” 싶을 때가 있죠. 이번 글에서는 오렌지파이5 + Ubuntu 환경에서, 파이썬으로...</p>
<p>게시물 <a href="https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%9c%bc%eb%a1%9c-%ec%9d%8c%ec%84%b1-%ec%95%8c%eb%9e%8c-%eb%a7%8c%eb%93%a4%ea%b8%b0-edgetts-%ec%ba%90%ec%8b%9c-%ec%a4%91%eb%b3%b5%eb%b0%a9%ec%a7%80-systemd-%ec%9e%90/">파이썬으로 음성 알람 만들기: EdgeTTS 캐시 + 중복방지 + systemd 자동실행</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading"></h1>



<p>아침에 알람이 울리긴 하는데…<br>“몇 시인지 말로 알려주면 진짜 바로 일어나겠는데?” 싶을 때가 있죠.</p>



<p>이번 글에서는 <strong>오렌지파이5 + Ubuntu</strong> 환경에서, 파이썬으로 <strong>말하는 음성 알람</strong>을 만드는 방법을 정리했습니다.</p>



<ul class="wp-block-list">
<li>06:00부터 10분 단위로 06:30까지</li>



<li>“주인님 일어나세요. 현재 시간 06시 10분입니다.” 같은 문장을 <strong>TTS로 말해주고</strong></li>



<li>설정파일 1개로 <strong>매일/평일/1회 + 공휴일 제외</strong>까지 제어하고</li>



<li><strong>EdgeTTS 캐시(재생 빠름)</strong> + <strong>중복 재생 방지(안전)</strong> + **systemd 자동 실행(운영 편함)**까지 묶었습니다.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">목표 동작 요약</h2>



<ul class="wp-block-list">
<li>알람 시간: <code>06:00</code>, <code>06:10</code>, <code>06:20</code>, <code>06:30</code></li>



<li>출력: 스피커로 음성 재생(mp3)</li>



<li>스케줄 방식: 설정파일(JSON) 기반</li>



<li>운영 안정성:
<ul class="wp-block-list">
<li>같은 분에 두 번 울리는 것 방지(상태파일 기록)</li>



<li>TTS는 캐시(mp3 재사용)로 속도/안정성 개선</li>



<li>systemd로 부팅 후 자동 실행</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">준비물</h2>



<ul class="wp-block-list">
<li>Orange Pi 5 (또는 Ubuntu 머신)</li>



<li>Ubuntu 22.04/24.04 계열</li>



<li>스피커(3.5mm/USB/블루투스 등)</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">설치(필수 패키지)</h2>



<pre class="wp-block-code"><code>sudo apt update
sudo apt install -y python3-pip mpg123
pip3 install edge-tts holidays
</code></pre>



<ul class="wp-block-list">
<li><code>edge-tts</code> : 텍스트 → 음성(mp3) 생성</li>



<li><code>mpg123</code> : mp3를 바로 재생(가볍고 안정적)</li>



<li><code>holidays</code> : 한국 공휴일 제외(선택처럼 보이지만 “휴일 제외”를 쓰려면 필요)</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1) 설정파일 1개로 알람 규칙 관리하기</h2>



<p>프로젝트 폴더를 만들고, 설정파일을 준비합니다.</p>



<pre class="wp-block-code"><code>mkdir -p ~/edge_alarm
cd ~/edge_alarm
nano alarm_config.json
</code></pre>



<h3 class="wp-block-heading"><code>alarm_config.json</code></h3>



<pre class="wp-block-code"><code>{
  "mode": "weekdays",
  "times": &#91;"06:00", "06:10", "06:20", "06:30"],
  "message_template": "주인님 일어나세요. 현재 시간 {hh}시 {mm}분입니다.",
  "voice": "ko-KR-SunHiNeural",
  "rate": "+0%",
  "volume": 100,
  "exclude_public_holidays": true,
  "country_holidays": "KR",
  "once_date": "2026-02-12"
}
</code></pre>



<h3 class="wp-block-heading">핵심 옵션 설명</h3>



<ul class="wp-block-list">
<li><code>mode</code>
<ul class="wp-block-list">
<li><code>daily</code> : 매일</li>



<li><code>weekdays</code> : 평일만(토/일 제외)</li>



<li><code>once</code> : 특정 날짜 <code>once_date</code>에만 1회 실행</li>
</ul>
</li>



<li><code>times</code> : 울릴 시간을 배열로 관리</li>



<li><code>message_template</code> : <code>{hh}</code>, <code>{mm}</code>가 현재 시각으로 자동 치환</li>



<li><code>exclude_public_holidays</code> : 공휴일 제외 여부</li>



<li><code>country_holidays</code> : 한국은 <code>"KR"</code></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2) 파이썬 실행 코드(alarm_tts.py)</h2>



<p>이 코드는 아래 3가지를 “운영 가능한 수준”으로 묶는 게 포인트입니다.</p>



<ol class="wp-block-list">
<li><strong>EdgeTTS 캐시</strong>: 같은 문장은 mp3를 저장해 재사용</li>



<li><strong>중복방지</strong>: <code>YYYY-MM-DD_HH:MM</code> 키로 “이미 울림” 기록</li>



<li><strong>자동실행</strong>: systemd로 부팅 시 자동 기동</li>
</ol>



<p>아래 파일을 저장하세요.</p>



<pre class="wp-block-code"><code>nano alarm_tts.py
chmod +x alarm_tts.py
</code></pre>



<h3 class="wp-block-heading"><code>alarm_tts.py</code> (한글 상세 주석 포함)</h3>



<pre class="wp-block-code"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
&#91;EdgeTTS 음성 알람 스크립트]
- 설정 파일(alarm_config.json) 하나만 수정해서 운영 가능
- EdgeTTS로 MP3 생성 후 스피커로 재생(mpg123 사용)
- MP3 캐시 저장(같은 문장 재사용) -&gt; 빠르고 안정적
- 상태 파일 기록(같은 분 중복 재생 방지)
- systemd 서비스로 등록하면 부팅 후 자동 실행 가능
"""

import asyncio
import json
import os
import sys
import time
import hashlib
import subprocess
from datetime import datetime, date, timedelta

# EdgeTTS 라이브러리 import
try:
    import edge_tts
except ImportError:
    print("edge-tts가 설치되어 있지 않습니다. `pip3 install edge-tts`를 실행하세요.")
    sys.exit(1)

# 공휴일 제외 기능을 위한 라이브러리(없으면 공휴일 판단 기능이 비활성)
try:
    import holidays as holidays_lib
except ImportError:
    holidays_lib = None

# -----------------------------
# 파일 경로(환경변수로 오버라이드 가능)
# -----------------------------
CONFIG_PATH = os.environ.get("ALARM_CONFIG", "./alarm_config.json")  # 설정 파일
STATE_PATH  = os.environ.get("ALARM_STATE", "./alarm_state.json")    # 중복방지 상태 파일
CACHE_DIR   = os.environ.get("ALARM_CACHE", "./tts_cache")           # TTS mp3 캐시 폴더


def load_json(path: str, default):
    """JSON 파일 로딩. 파일이 없으면 default 반환"""
    if not os.path.exists(path):
        return default
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def save_json(path: str, obj):
    """
    JSON 저장을 안전하게 하기 위한 방식
    - 임시 파일(.tmp)에 먼저 저장한 뒤 os.replace로 교체
    - 저장 중 전원 문제 등으로 파일이 깨질 위험을 줄임
    """
    tmp = path + ".tmp"
    with open(tmp, "w", encoding="utf-8") as f:
        json.dump(obj, f, ensure_ascii=False, indent=2)
    os.replace(tmp, path)


def ensure_dir(p: str):
    """폴더가 없으면 생성"""
    os.makedirs(p, exist_ok=True)


def is_public_holiday(d: date, country_code: str) -&gt; bool:
    """
    특정 국가 공휴일 여부 판단
    - holidays 라이브러리가 없으면 False 처리(공휴일 제외 비활성)
    """
    if holidays_lib is None:
        return False

    try:
        h = holidays_lib.country_holidays(country_code)
        return d in h
    except Exception:
        return False


def should_run_today(cfg: dict, today: date) -&gt; bool:
    """
    오늘 알람을 동작시킬지 판단
    - mode(daily/weekdays/once)
    - 공휴일 제외 옵션
    """
    mode = cfg.get("mode", "daily").lower()

    # once 모드: 특정 날짜에만 동작
    if mode == "once":
        once_date = cfg.get("once_date")
        if not once_date:
            return False
        try:
            od = datetime.strptime(once_date, "%Y-%m-%d").date()
            return today == od
        except ValueError:
            return False

    # weekdays 모드: 토/일이면 동작 안 함
    if mode == "weekdays":
        if today.weekday() &gt;= 5:
            return False

    # 공휴일 제외 옵션
    if cfg.get("exclude_public_holidays", False):
        cc = cfg.get("country_holidays", "KR")
        if is_public_holiday(today, cc):
            return False

    return True


def parse_times(cfg: dict):
    """
    설정 times(&#91;"06:00","06:10"...])를 (hh,mm) 튜플 리스트로 변환
    - 잘못된 값은 무시
    - 중복 제거 + 정렬
    """
    times = cfg.get("times", &#91;])
    parsed = &#91;]
    for t in times:
        try:
            hh, mm = t.split(":")
            parsed.append((int(hh), int(mm)))
        except Exception:
            pass
    return sorted(set(parsed))


def make_message(cfg: dict, now: datetime) -&gt; str:
    """설정 템플릿에서 멘트 생성({hh},{mm} 치환)"""
    tpl = cfg.get("message_template", "주인님 일어나세요. 현재 시간 {hh}시 {mm}분입니다.")
    return tpl.format(hh=now.strftime("%H"), mm=now.strftime("%M"))


def tts_cache_path(text: str, voice: str, rate: str) -&gt; str:
    """
    같은 텍스트/목소리/속도 조합은 mp3를 재사용하기 위해 해시 파일명으로 캐시 저장
    """
    key = f"{voice}|{rate}|{text}".encode("utf-8")
    h = hashlib.sha256(key).hexdigest()&#91;:24]
    return os.path.join(CACHE_DIR, f"{h}.mp3")


async def synthesize_mp3(text: str, voice: str, rate: str, out_path: str):
    """EdgeTTS로 mp3 생성(비동기)"""
    communicate = edge_tts.Communicate(text=text, voice=voice, rate=rate)
    await communicate.save(out_path)


def play_mp3(path: str, volume: int = 100):
    """
    mpg123로 mp3 재생
    - volume(0~100)을 gain으로 완만하게 반영
    """
    gain = max(0, min(32768, int(volume) * 80))
    subprocess.run(&#91;"mpg123", "-q", "-f", str(gain), path], check=False)


def minute_key(d: date, hh: int, mm: int) -&gt; str:
    """중복방지 키: YYYY-MM-DD_HH:MM"""
    return f"{d.isoformat()}_{hh:02d}:{mm:02d}"


def next_trigger_datetime(now: datetime, times):
    """
    현재 시각 기준으로 다음 알람 시각 찾기
    - 오늘~모레까지 탐색(안전장치)
    """
    for day_offset in range(0, 3):
        base = now.date() + timedelta(days=day_offset)
        for hh, mm in times:
            dt = datetime.combine(base, datetime.min.time()).replace(hour=hh, minute=mm)
            if dt &gt; now:
                return dt
    return None


async def main():
    """메인 루프"""
    ensure_dir(CACHE_DIR)

    cfg = load_json(CONFIG_PATH, default={})
    state = load_json(STATE_PATH, default={"fired": {}})

    times = parse_times(cfg)
    if not times:
        print("times 설정이 비어 있거나 형식이 잘못되었습니다.")
        return

    voice = cfg.get("voice", "ko-KR-SunHiNeural")
    rate = cfg.get("rate", "+0%")
    volume = int(cfg.get("volume", 100))

    print(f"&#91;alarm] 시작 mode={cfg.get('mode')} times={cfg.get('times')} voice={voice}")

    while True:
        now = datetime.now()
        today = now.date()

        # 오늘 동작 조건이 아니면 내일 새벽까지 대기
        if not should_run_today(cfg, today):
            tomorrow = datetime.combine(today + timedelta(days=1), datetime.min.time()).replace(minute=1)
            sleep_sec = max(5, int((tomorrow - now).total_seconds()))
            print(f"&#91;alarm] 오늘({today}) 스킵. {sleep_sec}초 후 재확인")
            time.sleep(sleep_sec)
            continue

        # 다음 알람 시각 계산
        nxt = next_trigger_datetime(now, times)
        if not nxt:
            time.sleep(10)
            continue

        # 다음 알람까지 대기(너무 길게 한번에 sleep하지 않도록 최대 60초 단위로 쪼갬)
        sleep_sec = (nxt - now).total_seconds()
        if sleep_sec &gt; 1:
            time.sleep(min(60, sleep_sec))
            continue

        # 중복방지: 같은 분에 이미 울렸으면 스킵
        k = minute_key(nxt.date(), nxt.hour, nxt.minute)
        if state.get("fired", {}).get(k):
            time.sleep(1)
            continue

        # 현재 시간 안내가 정확하도록 "울리는 순간"의 시간을 기준으로 멘트 생성
        speak_time = datetime.now()
        text = make_message(cfg, speak_time)

        # 캐시 mp3가 있으면 재사용, 없으면 새로 생성
        cache_path = tts_cache_path(text, voice, rate)
        if not os.path.exists(cache_path):
            try:
                await synthesize_mp3(text, voice, rate, cache_path)
            except Exception as e:
                print("&#91;alarm] TTS 생성 실패:", e)
                time.sleep(2)
                continue

        print(f"&#91;alarm] 울림 {k} =&gt; {text}")
        play_mp3(cache_path, volume=volume)

        # 상태 기록(이 분에는 이미 울렸음)
        state.setdefault("fired", {})&#91;k] = True
        save_json(STATE_PATH, state)

        # once 모드면 오늘 남은 알람이 없을 때 종료
        if cfg.get("mode", "").lower() == "once":
            remaining = &#91;]
            for hh, mm in times:
                dt = datetime.combine(today, datetime.min.time()).replace(hour=hh, minute=mm)
                if dt &gt; speak_time:
                    remaining.append(dt)
            if not remaining:
                print("&#91;alarm] once 모드 완료. 종료")
                return

        time.sleep(1)


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n&#91;alarm] 사용자에 의해 종료됨")
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3) 실행 방법(수동 테스트)</h2>



<pre class="wp-block-code"><code>cd ~/edge_alarm
python3 alarm_tts.py
</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>당장 테스트하고 싶으면 <code>times</code>를 현재 시간 기준으로 1~2분 뒤로 잠깐 바꿔보면 바로 확인됩니다.</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4) systemd 자동 실행(부팅 시 자동 시작)</h2>



<h3 class="wp-block-heading">1) 서비스 파일 생성</h3>



<pre class="wp-block-code"><code>sudo nano /etc/systemd/system/edge-alarm.service
</code></pre>



<h3 class="wp-block-heading">2) 아래 내용 입력(경로는 본인 계정에 맞게 수정)</h3>



<pre class="wp-block-code"><code>&#91;Unit]
Description=Edge TTS Alarm (EdgeTTS cache + dedup + systemd)
After=network.target sound.target

&#91;Service]
Type=simple
WorkingDirectory=/home/orangepi/edge_alarm
ExecStart=/usr/bin/python3 /home/orangepi/edge_alarm/alarm_tts.py
Restart=always
RestartSec=3

&#91;Install]
WantedBy=multi-user.target
</code></pre>



<h3 class="wp-block-heading">3) 적용 및 실행</h3>



<pre class="wp-block-code"><code>sudo systemctl daemon-reload
sudo systemctl enable --now edge-alarm.service
sudo systemctl status edge-alarm.service
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">운영 팁(실제로 써보면 도움이 되는 부분)</h2>



<ul class="wp-block-list">
<li><strong>네트워크가 잠깐 끊겨도</strong> 이미 만들어둔 mp3 캐시가 있으면 재생은 계속 됩니다.</li>



<li>“같은 시간에 두 번 울림”이 싫다면 <strong>상태파일(alarm_state.json)</strong> 방식이 꽤 든든합니다.</li>



<li>멘트/시간/평일여부는 코드가 아니라 <strong>설정파일 하나로</strong> 운영하면 나중에 유지보수가 편해요.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">FAQ</h2>



<p><strong>Q. 공휴일 제외는 어떻게 동작해요?</strong><br>A. <code>holidays</code> 라이브러리에서 KR 공휴일을 체크해서 해당 날짜면 스킵합니다.</p>



<p><strong>Q. 스피커가 USB/블루투스면 안 나올 때가 있어요.</strong><br>A. 대부분 “기본 출력 장치”가 다르게 잡혀서 생깁니다. 먼저 Ubuntu 사운드 출력 장치를 확인해 주세요.</p>



<p><strong>Q. 멘트를 바꾸려면 코드를 수정해야 하나요?</strong><br>A. 아니요. <code>message_template</code>만 바꾸면 됩니다.</p>



<p></p>
<p>게시물 <a href="https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%9c%bc%eb%a1%9c-%ec%9d%8c%ec%84%b1-%ec%95%8c%eb%9e%8c-%eb%a7%8c%eb%93%a4%ea%b8%b0-edgetts-%ec%ba%90%ec%8b%9c-%ec%a4%91%eb%b3%b5%eb%b0%a9%ec%a7%80-systemd-%ec%9e%90/">파이썬으로 음성 알람 만들기: EdgeTTS 캐시 + 중복방지 + systemd 자동실행</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%9c%bc%eb%a1%9c-%ec%9d%8c%ec%84%b1-%ec%95%8c%eb%9e%8c-%eb%a7%8c%eb%93%a4%ea%b8%b0-edgetts-%ec%ba%90%ec%8b%9c-%ec%a4%91%eb%b3%b5%eb%b0%a9%ec%a7%80-systemd-%ec%9e%90/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>터미널에서 바로 쓰는 한국어 음성 비서 만들기: GPT + Edge TTS (실무용)</title>
		<link>https://howinfo.kr/%ed%84%b0%eb%af%b8%eb%84%90%ec%97%90%ec%84%9c-%eb%b0%94%eb%a1%9c-%ec%93%b0%eb%8a%94-%ed%95%9c%ea%b5%ad%ec%96%b4-%ec%9d%8c%ec%84%b1-%eb%b9%84%ec%84%9c-%eb%a7%8c%eb%93%a4%ea%b8%b0-gpt-edge-tts/</link>
					<comments>https://howinfo.kr/%ed%84%b0%eb%af%b8%eb%84%90%ec%97%90%ec%84%9c-%eb%b0%94%eb%a1%9c-%ec%93%b0%eb%8a%94-%ed%95%9c%ea%b5%ad%ec%96%b4-%ec%9d%8c%ec%84%b1-%eb%b9%84%ec%84%9c-%eb%a7%8c%eb%93%a4%ea%b8%b0-gpt-edge-tts/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Tue, 10 Feb 2026 11:58:53 +0000</pubDate>
				<category><![CDATA[개발·코딩]]></category>
		<category><![CDATA[AI워크플로우]]></category>
		<category><![CDATA[EdgeTTS]]></category>
		<category><![CDATA[GPT]]></category>
		<category><![CDATA[mpg123]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[음성비서]]></category>
		<category><![CDATA[자동화]]></category>
		<category><![CDATA[터미널도구]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=1565</guid>

					<description><![CDATA[<p>회의 준비하다가 갑자기 문득 이런 순간이 있어요. 그래서 저는 아주 단순한 목표로 시작했어요. 터미널에 질문을 치면 GPT가 답하고, 그 답을...</p>
<p>게시물 <a href="https://howinfo.kr/%ed%84%b0%eb%af%b8%eb%84%90%ec%97%90%ec%84%9c-%eb%b0%94%eb%a1%9c-%ec%93%b0%eb%8a%94-%ed%95%9c%ea%b5%ad%ec%96%b4-%ec%9d%8c%ec%84%b1-%eb%b9%84%ec%84%9c-%eb%a7%8c%eb%93%a4%ea%b8%b0-gpt-edge-tts/">터미널에서 바로 쓰는 한국어 음성 비서 만들기: GPT + Edge TTS (실무용)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>회의 준비하다가 갑자기 문득 이런 순간이 있어요.</p>



<ul class="wp-block-list">
<li>“이거 한 줄만 물어보면 되는데… 다시 브라우저 열기 귀찮다”</li>



<li>“답변은 길어질 것 같은데, 화면 보는 대신 그냥 <strong>읽어줬으면</strong> 좋겠다”</li>



<li>“업무 중에 손은 키보드/마우스에 묶여 있는데, 짧게 대화하듯 확인하고 싶다”</li>
</ul>



<p>그래서 저는 아주 단순한 목표로 시작했어요.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>터미널에 질문을 치면 GPT가 답하고, 그 답을 바로 한국어 음성으로 읽어주는 작은 비서</strong></p>
</blockquote>



<p>이번 글에서는 제가 실제 소스를 기준으로, 설치부터 운영 팁까지 한 번에 정리해볼게요.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1) 이 스크립트가 하는 일 (한 줄 요약)</h2>



<p><strong>나&gt; 질문 입력</strong> → <strong>GPT 답변 생성</strong> → <strong>Edge TTS로 mp3 생성</strong> → <strong>mpg123로 즉시 재생</strong></p>



<p>핵심은 “대화가 끊기지 않게” 만드는 거예요.<br>기존 버전에서는 답변이 길어지면 500자에서 <strong>뚝 잘려서</strong> 읽히는 문제가 있었는데, 이 소스에서는 <strong>문장 단위로 나눠서 끝까지 읽는 방식</strong>으로 개선했습니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2) 왜 이소스가 실무에 더 편하냐면</h2>



<p>제가 실제로 써보니, 딱 두 가지가 중요했어요.</p>



<h3 class="wp-block-heading">✅ (1) 답변이 길어져도 끝까지 읽어줌</h3>



<p>업무 질문은 생각보다 길게 답이 나오는 경우가 많아요.<br>“요약 + 근거 + 단계별 명령어” 같은 답변이 나오면 500자 제한으로 끊기는 순간 흐름이 무너집니다.</p>



<p>답변을 <strong>문장 단위로 쪼개서</strong> 자연스럽게 이어 읽어요.</p>



<h3 class="wp-block-heading">✅ (2) asyncio.run() 반복 호출 제거</h3>



<p>환경에 따라(특히 이벤트 루프가 이미 돌아가는 환경) <code>asyncio.run()</code>을 반복하면 충돌이 날 때가 있어요.<br>이 소스에서는 이벤트 루프를 한 번만 만들고 계속 재사용하는 방식이라 안정성이 좋아집니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3) 준비물 (Ubuntu/Orange Pi 기준)</h2>



<ul class="wp-block-list">
<li>Python 3.9+ (대부분 OK)</li>



<li>패키지: <code>openai</code>, <code>edge-tts</code></li>



<li>재생기: <code>mpg123</code></li>



<li>그리고 가장 중요한 <strong>OpenAI API Key</strong></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4) 설치 (실제로 이대로 하면 됩니다)</h2>



<h3 class="wp-block-heading">4-1) mpg123 설치</h3>



<pre class="wp-block-code"><code>sudo apt-get update
sudo apt-get install -y mpg123
</code></pre>



<h3 class="wp-block-heading">4-2) 파이썬 라이브러리 설치</h3>



<pre class="wp-block-code"><code>pip install -U openai edge-tts
</code></pre>



<h3 class="wp-block-heading">4-3) API 키 설정</h3>



<pre class="wp-block-code"><code>export OPENAI_API_KEY="sk-여기에_키_입력"
</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>실무 팁: 매번 export 치기 귀찮으면<br><code>~/.bashrc</code> 또는 <code>~/.profile</code>에 넣어두면 편합니다.</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5) 실행 (가장 기본 세팅)</h2>



<pre class="wp-block-code"><code>python3 text_gpt_edge_tts_v4.py
</code></pre>



<p>실행하면 터미널에 이렇게 뜹니다.</p>



<ul class="wp-block-list">
<li><code>나&gt;</code> 프롬프트가 나오고,</li>



<li>입력하면 <code>GPT&gt;</code> 답변이 출력되고,</li>



<li>이어서 바로 음성으로 재생됩니다.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">6) 자주 쓰는 튜닝 포인트 (환경변수로 조절)</h2>



<p>실무에서 “한 번 만들어두고 계속 쓰는 도구”가 되려면, 튜닝이 쉬워야 해요.<br>이 스크립트는 대부분 환경변수로 바꿀 수 있게 해놨습니다.</p>



<h3 class="wp-block-heading">✅ 모델 바꾸기</h3>



<pre class="wp-block-code"><code>export GPT_MODEL="gpt-4o-mini"
</code></pre>



<h3 class="wp-block-heading">✅ 목소리 바꾸기 (한국어)</h3>



<pre class="wp-block-code"><code>export TTS_VOICE="ko-KR-SunHiNeural"
</code></pre>



<h3 class="wp-block-heading">✅ 말하기 속도/볼륨</h3>



<pre class="wp-block-code"><code>export TTS_RATE="+10%"
export TTS_VOLUME="+0%"
</code></pre>



<h3 class="wp-block-heading">✅ “한 번에 읽는 길이” 조절 (청크 크기)</h3>



<pre class="wp-block-code"><code>export MAX_SPEAK_CHARS="450"
</code></pre>



<ul class="wp-block-list">
<li>너무 자주 끊기면 값을 올리고(500~700)</li>



<li>문장 끝이 어색하게 잘리면 조금 낮추는 게(350~500) 안정적이었습니다.</li>
</ul>



<h3 class="wp-block-heading">✅ TTS 모드 선택</h3>



<pre class="wp-block-code"><code>export TTS_MODE="chunk"   # 기본: 끝까지 읽기
# export TTS_MODE="clamp" # 기존처럼 잘라 읽기
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7) 운영하면서 “진짜 도움이 됐던” 사용 패턴</h2>



<p>제가 실제로 써보면서 효과 있었던 사용 패턴을 몇 개 공유할게요.</p>



<h3 class="wp-block-heading">(1) 짧은 업무 확인</h3>



<ul class="wp-block-list">
<li>“이 로그 메시지 의미가 뭐야?”</li>



<li>“nginx에서 502 나올 때 점검 순서 정리해줘”</li>



<li>“이 에러는 보통 어디서 터지지?”</li>
</ul>



<p>이런 것들은 화면으로 읽기보다 <strong>음성으로 들으면</strong> 손이 자유로워서 편합니다.</p>



<h3 class="wp-block-heading">(2) 문서 초안/메일 초안 만들기</h3>



<ul class="wp-block-list">
<li>“고객에게 보낼 공지 초안 부탁해”</li>



<li>“실무적인 체크리스트 형태로 정리해줘”</li>
</ul>



<p>이럴 때 답이 길어지는데 v4는 중간에 끊기지 않아서 좋았어요.</p>



<h3 class="wp-block-heading">(3) “내가 지금 뭘 해야 하지?” 정리용</h3>



<p>업무가 복잡해질수록, 오히려 이런 질문이 유용합니다.</p>



<ul class="wp-block-list">
<li>“지금 내가 해야 할 일을 5개로 줄여줘”</li>



<li>“우선순위를 정해줘(긴급/중요 기준)”</li>
</ul>



<p>음성으로 들으면 리듬이 생겨서 실행이 빨라져요.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">8) 트러블슈팅 (운영하다 보면 꼭 만나는 것들)</h2>



<h3 class="wp-block-heading">✅ mpg123: command not found</h3>



<p>→ 설치 안 된 상태입니다.</p>



<pre class="wp-block-code"><code>sudo apt-get install -y mpg123
</code></pre>



<h3 class="wp-block-heading">✅ OPENAI_API_KEY 오류 / 401</h3>



<p>→ 키가 없거나 잘못된 값입니다.</p>



<pre class="wp-block-code"><code>echo $OPENAI_API_KEY
</code></pre>



<p>출력이 비어 있으면 export가 적용 안 된 거예요.</p>



<h3 class="wp-block-heading">✅ 음성은 생성되는데 소리가 안 난다</h3>



<p>이건 환경이 다양해서 원인이 여러 개인데, 경험상 체크 순서는 이렇습니다.</p>



<ol class="wp-block-list">
<li>서버/장비에서 실제 오디오 출력 장치가 맞는지</li>



<li><code>mpg123</code>가 소리를 낼 수 있는 상태인지 (권한/장치)</li>



<li>헤드리스 환경이면 기본 오디오 장치가 비정상일 수 있음</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">9) 실무에서 꼭 챙길 보안 포인트</h2>



<p>이런 스크립트는 “내 PC에서만 쓰는 작은 도구”처럼 보여도, 실무에서는 습관이 중요해요.</p>



<ul class="wp-block-list">
<li><strong>API 키를 코드에 하드코딩하지 않기</strong><br>→ 환경변수로 관리하는 게 기본입니다.</li>



<li>가능하면 <code>.bashrc</code>에 넣되, 공유/백업 파일에 키가 올라가지 않도록 주의</li>



<li>회사 자산/업무망 장비에서 돌릴 때는 로그/히스토리 저장 여부도 고려</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">10) 다음 단계 아이디어 (여기서부터가 확장 포인트)</h2>



<p>여기까지는 “키보드 입력 기반 음성 비서”였고, 다음 단계는 이쪽이 재밌습니다.</p>



<ul class="wp-block-list">
<li><strong>마이크 입력(녹음) → Whisper(STT) → GPT → TTS</strong><br>완전한 음성 비서 형태로 확장 가능</li>



<li>답변을 읽는 동안 <strong>중간에 끊기(Stop)</strong> 기능 추가</li>



<li>질문/답변을 파일로 저장해서 <strong>업무 로그처럼 쌓기</strong></li>



<li>(저는 이걸 Note Station 자동 정리 파이프라인과 연결해서 “회의 음성 → STT → 요약 → 노트 자동 삽입”까지도 확장 중입니다)</li>
</ul>



<p>파이썬 소스코드 아래 </p>



<div class="wp-block-file"><a id="wp-block-file--media-cf4ca2c0-7b4a-41dd-aaf5-5f487dff2be3" href="https://howinfo.kr/wp-content/uploads/2026/02/gpt_edge_tts.zip">gpt_edge_tts</a><a href="https://howinfo.kr/wp-content/uploads/2026/02/gpt_edge_tts.zip" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-cf4ca2c0-7b4a-41dd-aaf5-5f487dff2be3">다운로드</a></div>



<p>오렌지파이5에서 돌려봤는데 답변이 조금 늦습니다. 좀더 성능좋은 컴퓨터에서는 대화가 어느정도 되었습니다. </p>



<p>참고하세요. </p>
<p>게시물 <a href="https://howinfo.kr/%ed%84%b0%eb%af%b8%eb%84%90%ec%97%90%ec%84%9c-%eb%b0%94%eb%a1%9c-%ec%93%b0%eb%8a%94-%ed%95%9c%ea%b5%ad%ec%96%b4-%ec%9d%8c%ec%84%b1-%eb%b9%84%ec%84%9c-%eb%a7%8c%eb%93%a4%ea%b8%b0-gpt-edge-tts/">터미널에서 바로 쓰는 한국어 음성 비서 만들기: GPT + Edge TTS (실무용)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%ed%84%b0%eb%af%b8%eb%84%90%ec%97%90%ec%84%9c-%eb%b0%94%eb%a1%9c-%ec%93%b0%eb%8a%94-%ed%95%9c%ea%b5%ad%ec%96%b4-%ec%9d%8c%ec%84%b1-%eb%b9%84%ec%84%9c-%eb%a7%8c%eb%93%a4%ea%b8%b0-gpt-edge-tts/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>🐳 Docker 설치 방법 (Ubuntu 기준) – Docker 개념부터 설치까지 한 번에 정리</title>
		<link>https://howinfo.kr/%f0%9f%90%b3-docker-%ec%84%a4%ec%b9%98-%eb%b0%a9%eb%b2%95-ubuntu-%ea%b8%b0%ec%a4%80-docker-%ea%b0%9c%eb%85%90%eb%b6%80%ed%84%b0-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ed%95%9c-%eb%b2%88/</link>
					<comments>https://howinfo.kr/%f0%9f%90%b3-docker-%ec%84%a4%ec%b9%98-%eb%b0%a9%eb%b2%95-ubuntu-%ea%b8%b0%ec%a4%80-docker-%ea%b0%9c%eb%85%90%eb%b6%80%ed%84%b0-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ed%95%9c-%eb%b2%88/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Mon, 09 Feb 2026 00:53:34 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[DockerCompose]]></category>
		<category><![CDATA[IT기초]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[도커설치]]></category>
		<category><![CDATA[리눅스서버]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=1449</guid>

					<description><![CDATA[<p>Ubuntu 서버나 PC를 사용하다 보면“서비스 하나 설치하려다 환경 꼬였다…” 이런 경험 한 번쯤 있으시죠? 이럴 때 가장 많이 쓰이는 도구가...</p>
<p>게시물 <a href="https://howinfo.kr/%f0%9f%90%b3-docker-%ec%84%a4%ec%b9%98-%eb%b0%a9%eb%b2%95-ubuntu-%ea%b8%b0%ec%a4%80-docker-%ea%b0%9c%eb%85%90%eb%b6%80%ed%84%b0-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ed%95%9c-%eb%b2%88/">🐳 Docker 설치 방법 (Ubuntu 기준) – Docker 개념부터 설치까지 한 번에 정리</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Ubuntu 서버나 PC를 사용하다 보면<br>“서비스 하나 설치하려다 환경 꼬였다…” 이런 경험 한 번쯤 있으시죠?</p>



<p>이럴 때 가장 많이 쓰이는 도구가 바로 <strong>Docker</strong>입니다.<br>이 글에서는 <strong>Docker가 무엇인지</strong>부터<br>👉 <strong>Ubuntu에서 Docker를 설치하고 정상 동작 확인하는 방법</strong>까지<br>초보자 기준으로 차근차근 정리했습니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Docker란 무엇인가?</h2>



<p>Docker는 **애플리케이션을 컨테이너(Container)**라는 단위로 실행할 수 있게 해주는 도구입니다.</p>



<h3 class="wp-block-heading">쉽게 비유하면</h3>



<ul class="wp-block-list">
<li>예전 방식:<br>👉 프로그램마다 직접 설치 (환경 충돌 잦음)</li>



<li>Docker 방식:<br>👉 프로그램 + 실행 환경을 <strong>한 박스에 담아서 실행</strong></li>
</ul>



<p>그래서 이런 장점이 있습니다.</p>



<h3 class="wp-block-heading">Docker의 장점</h3>



<ul class="wp-block-list">
<li>✔ 설치/삭제가 매우 간단</li>



<li>✔ 서버 환경이 달라도 동일하게 실행</li>



<li>✔ 테스트·운영 환경 분리 쉬움</li>



<li>✔ 홈서버, NAS, 클라우드 모두 활용 가능</li>
</ul>



<p>👉 요즘 <strong>홈서버, NAS, AI 서버</strong>에서 Docker는 거의 필수입니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Docker와 가상머신(VM)의 차이</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>구분</th><th>Docker</th><th>가상머신</th></tr></thead><tbody><tr><td>실행 방식</td><td>OS 공유</td><td>OS 전체 포함</td></tr><tr><td>속도</td><td>빠름</td><td>상대적으로 느림</td></tr><tr><td>용량</td><td>작음</td><td>큼</td></tr><tr><td>관리</td><td>간단</td><td>복잡</td></tr></tbody></table></figure>



<p>👉 <strong>가볍고 빠른 서비스 운영</strong>이 목적이라면 Docker가 훨씬 유리합니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Docker 설치 전 확인 사항</h2>



<p>아래 환경을 기준으로 설명합니다.</p>



<ul class="wp-block-list">
<li>✔ Ubuntu 20.04 / 22.04 / 24.04</li>



<li>✔ sudo 권한 사용자</li>



<li>✔ 인터넷 연결</li>
</ul>



<p>버전 확인:</p>



<pre class="wp-block-code"><code>lsb_release -a
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Ubuntu에서 Docker 설치 방법</h2>



<h3 class="wp-block-heading">1️⃣ 기존 패키지 업데이트</h3>



<pre class="wp-block-code"><code>sudo apt update
sudo apt upgrade -y
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">2️⃣ Docker 설치에 필요한 패키지 설치</h3>



<pre class="wp-block-code"><code>sudo apt install -y ca-certificates curl gnupg lsb-release
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">3️⃣ Docker 공식 GPG 키 추가</h3>



<pre class="wp-block-code"><code>sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">4️⃣ Docker 공식 저장소 추가</h3>



<pre class="wp-block-code"><code>echo \
"deb &#91;arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">5️⃣ Docker 엔진 설치</h3>



<pre class="wp-block-code"><code>sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Docker 정상 설치 확인</h2>



<h3 class="wp-block-heading">버전 확인</h3>



<pre class="wp-block-code"><code>docker --version
</code></pre>



<p>정상이라면 아래처럼 출력됩니다.</p>



<pre class="wp-block-code"><code>Docker version XX.X.X, build XXXXX
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">테스트 컨테이너 실행</h3>



<pre class="wp-block-code"><code>sudo docker run hello-world
</code></pre>



<p>✔ 정상 출력되면 Docker 설치 완료입니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">sudo 없이 Docker 사용하기 (중요)</h2>



<p>매번 <code>sudo</code> 붙이기 귀찮다면 사용자 권한을 추가합니다.</p>



<pre class="wp-block-code"><code>sudo usermod -aG docker $USER
</code></pre>



<p>적용을 위해 <strong>로그아웃 후 재로그인</strong> 또는 재부팅하세요.</p>



<p>확인:</p>



<pre class="wp-block-code"><code>docker ps
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Docker Compose란?</h2>



<p>Docker Compose는<br>👉 <strong>여러 개의 컨테이너를 한 번에 관리</strong>하기 위한 도구입니다.</p>



<p>예를 들면:</p>



<ul class="wp-block-list">
<li>웹서버 + DB</li>



<li>AI 서버 + API</li>



<li>홈서버 서비스 묶음</li>
</ul>



<p>지금 설치한 Docker에는 <strong>Compose 플러그인</strong>이 이미 포함되어 있습니다.</p>



<p>확인:</p>



<pre class="wp-block-code"><code>docker compose version
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Docker를 어디에 활용할 수 있을까?</h2>



<p>Docker는 이런 곳에 특히 많이 쓰입니다.</p>



<ul class="wp-block-list">
<li>✔ 홈서버 / NAS 서비스 운영</li>



<li>✔ 웹서버 (WordPress, Nginx)</li>



<li>✔ AI 서버 (Whisper, Stable Diffusion 등)</li>



<li>✔ 자동화 도구 (n8n, Home Assistant)</li>



<li>✔ 테스트 환경 구성</li>
</ul>



<p>👉 <strong>한 번 익혀두면 서버 운영 난이도가 확 내려갑니다.</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">마무리 정리</h2>



<ul class="wp-block-list">
<li>Docker는 <strong>환경 충돌 없이 서비스 실행</strong>을 가능하게 해주는 도구</li>



<li>Ubuntu에서는 <strong>공식 저장소 설치가 가장 안정적</strong></li>



<li>sudo 없이 사용 설정하면 훨씬 편리</li>



<li>Docker Compose까지 익히면 서버 관리가 쉬워짐</li>
</ul>



<p></p>
<p>게시물 <a href="https://howinfo.kr/%f0%9f%90%b3-docker-%ec%84%a4%ec%b9%98-%eb%b0%a9%eb%b2%95-ubuntu-%ea%b8%b0%ec%a4%80-docker-%ea%b0%9c%eb%85%90%eb%b6%80%ed%84%b0-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ed%95%9c-%eb%b2%88/">🐳 Docker 설치 방법 (Ubuntu 기준) – Docker 개념부터 설치까지 한 번에 정리</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%f0%9f%90%b3-docker-%ec%84%a4%ec%b9%98-%eb%b0%a9%eb%b2%95-ubuntu-%ea%b8%b0%ec%a4%80-docker-%ea%b0%9c%eb%85%90%eb%b6%80%ed%84%b0-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ed%95%9c-%eb%b2%88/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>우분투에서 비주얼 스튜디오 코드 설치 방법 (초보자도 OK)</title>
		<link>https://howinfo.kr/%ec%9a%b0%eb%b6%84%ed%88%ac%ec%97%90%ec%84%9c-%eb%b9%84%ec%a5%ac%ec%96%bc%ec%8a%a4%ed%8a%9c%eb%94%94%ec%96%b4-%ec%84%a4%ec%b9%98-%ec%b4%88%ea%b8%b0%ed%99%94/</link>
					<comments>https://howinfo.kr/%ec%9a%b0%eb%b6%84%ed%88%ac%ec%97%90%ec%84%9c-%eb%b9%84%ec%a5%ac%ec%96%bc%ec%8a%a4%ed%8a%9c%eb%94%94%ec%96%b4-%ec%84%a4%ec%b9%98-%ec%b4%88%ea%b8%b0%ed%99%94/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Tue, 03 Feb 2026 09:52:45 +0000</pubDate>
				<category><![CDATA[개발·코딩]]></category>
		<category><![CDATA[ir기초]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vscode]]></category>
		<category><![CDATA[개발환경]]></category>
		<category><![CDATA[리눅스]]></category>
		<category><![CDATA[비주얼스튜디오코드]]></category>
		<category><![CDATA[우분투]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=1221</guid>

					<description><![CDATA[<p>리눅스 환경에서 개발을 시작하려면 가장 먼저 설치하게 되는 도구가 바로Visual Studio Code(VS Code)입니다. 가볍고 빠르면서도 확장성이 뛰어나,파이썬·웹·서버 관리까지 폭넓게 사용할...</p>
<p>게시물 <a href="https://howinfo.kr/%ec%9a%b0%eb%b6%84%ed%88%ac%ec%97%90%ec%84%9c-%eb%b9%84%ec%a5%ac%ec%96%bc%ec%8a%a4%ed%8a%9c%eb%94%94%ec%96%b4-%ec%84%a4%ec%b9%98-%ec%b4%88%ea%b8%b0%ed%99%94/">우분투에서 비주얼 스튜디오 코드 설치 방법 (초보자도 OK)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p id="SE-c8fb7103-343b-4e27-a1bf-2cc82a1084a4">리눅스 환경에서 개발을 시작하려면 가장 먼저 설치하게 되는 도구가 바로<br><strong>Visual Studio Code</strong>(VS Code)입니다.</p>



<p>가볍고 빠르면서도 확장성이 뛰어나,<br>파이썬·웹·서버 관리까지 폭넓게 사용할 수 있어 우분투 사용자에게 특히 인기가 많습니다.</p>



<p>이번 글에서는 <strong>우분투(Ubuntu)에서 VS Code를 설치하는 가장 쉬운 방법</strong>을 정리해보겠습니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">🐧 왜 우분투에서 VS Code를 많이 쓸까?</h2>



<ul class="wp-block-list">
<li>마이크로소프트 공식 지원</li>



<li>터미널·SSH·Docker 연동에 강함</li>



<li>확장 프로그램으로 IDE급 활용 가능</li>



<li>서버·홈서버·개발 환경에 잘 어울림</li>
</ul>



<p>CLI 중심인 우분투와 VS Code는 궁합이 아주 좋은 조합입니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">✅ 방법 1. 스냅(Snap)으로 설치하기 (가장 간단)</h2>



<p>우분투 기본 패키지 관리자인 <strong>Snap</strong>을 이용하면 한 줄로 설치할 수 있습니다.</p>



<pre class="wp-block-code"><code>sudo snap install code --classic
</code></pre>



<h3 class="wp-block-heading">장점</h3>



<ul class="wp-block-list">
<li>설치가 매우 간단</li>



<li>자동 업데이트 지원</li>



<li>공식 패키지</li>
</ul>



<p>설치가 끝나면 앱 메뉴에서 <strong>Visual Studio Code</strong>를 바로 실행할 수 있습니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">✅ 방법 2. 공식 .deb 패키지로 설치하기 (권장)</h2>



<p>마이크로소프트에서 제공하는 공식 저장소를 등록해 설치하는 방법입니다.</p>



<h3 class="wp-block-heading">1️⃣ 필수 패키지 설치</h3>



<pre class="wp-block-code"><code>sudo apt update
sudo apt install wget gpg -y
</code></pre>



<h3 class="wp-block-heading">2️⃣ 마이크로소프트 GPG 키 추가</h3>



<pre class="wp-block-code"><code>wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor &gt; packages.microsoft.gpg
sudo install -o root -g root -m 644 packages.microsoft.gpg /usr/share/keyrings/
</code></pre>



<h3 class="wp-block-heading">3️⃣ VS Code 저장소 추가</h3>



<pre class="wp-block-code"><code>echo "deb &#91;arch=amd64 signed-by=/usr/share/keyrings/packages.microsoft.gpg] \
https://packages.microsoft.com/repos/code stable main" | \
sudo tee /etc/apt/sources.list.d/vscode.list
</code></pre>



<h3 class="wp-block-heading">4️⃣ 설치</h3>



<pre class="wp-block-code"><code>sudo apt update
sudo apt install code -y
</code></pre>



<p>👉 이 방식은 <strong>apt 업데이트와 함께 관리</strong>할 수 있어 안정적입니다.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">▶ 설치 확인 및 실행</h2>



<p>터미널에서 아래 명령어를 입력해보세요.</p>



<pre class="wp-block-code"><code>code
</code></pre>



<p>정상적으로 실행되면 설치 성공입니다 🎉</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">🔧 설치 후 꼭 해볼 설정</h2>



<ul class="wp-block-list">
<li>한글 입력 문제 → <code>ibus</code> 설정 확인</li>



<li>확장 추천
<ul class="wp-block-list">
<li>Python</li>



<li>Remote &#8211; SSH</li>



<li>Docker</li>



<li>GitLens</li>
</ul>
</li>



<li>테마 변경으로 가독성 개선</li>
</ul>



<p>VS Code는 <strong>설치 후 설정에 따라 생산성이 크게 달라집니다.</strong></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">✨ 마무리</h2>



<p>우분투에서 VS Code를 설치하는 방법은 여러 가지가 있지만,<br><strong>Snap 또는 공식 저장소 방식</strong>만 알아도 충분합니다.</p>



<p id="SE-c8fb7103-343b-4e27-a1bf-2cc82a1084a4">개발, 서버 관리, 홈서버 운영까지<br>우분투 환경에서 VS Code 하나면 대부분의 작업을 커버할 수 있습니다.</p>



<p id="SE-c8fb7103-343b-4e27-a1bf-2cc82a1084a4"></p>
<p>게시물 <a href="https://howinfo.kr/%ec%9a%b0%eb%b6%84%ed%88%ac%ec%97%90%ec%84%9c-%eb%b9%84%ec%a5%ac%ec%96%bc%ec%8a%a4%ed%8a%9c%eb%94%94%ec%96%b4-%ec%84%a4%ec%b9%98-%ec%b4%88%ea%b8%b0%ed%99%94/">우분투에서 비주얼 스튜디오 코드 설치 방법 (초보자도 OK)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%ec%9a%b0%eb%b6%84%ed%88%ac%ec%97%90%ec%84%9c-%eb%b9%84%ec%a5%ac%ec%96%bc%ec%8a%a4%ed%8a%9c%eb%94%94%ec%96%b4-%ec%84%a4%ec%b9%98-%ec%b4%88%ea%b8%b0%ed%99%94/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
