<?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>하우인포-IT·테크</title>
	<atom:link href="https://howinfo.kr/feed/" rel="self" type="application/rss+xml" />
	<link>https://howinfo.kr/</link>
	<description>IT·AI 자동화 &#38; 인프라 전문 블로그 (하우인포)</description>
	<lastBuildDate>Fri, 27 Mar 2026 11:22:59 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://howinfo.kr/wp-content/uploads/2026/02/cropped-ChatGPT-Image-2026년-2월-12일-오후-05_39_40-32x32.png</url>
	<title>하우인포-IT·테크</title>
	<link>https://howinfo.kr/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>시놀로지에서 admin@howinfo.kr 메일 받는 방법, 가비아 DNS와 MailPlus 설정 정리</title>
		<link>https://howinfo.kr/%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80%ec%97%90%ec%84%9c-adminhowinfo-kr-%eb%a9%94%ec%9d%bc-%eb%b0%9b%eb%8a%94-%eb%b0%a9%eb%b2%95-%ea%b0%80%eb%b9%84%ec%95%84-dns%ec%99%80-mailplus-%ec%84%a4%ec%a0%95/</link>
					<comments>https://howinfo.kr/%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80%ec%97%90%ec%84%9c-adminhowinfo-kr-%eb%a9%94%ec%9d%bc-%eb%b0%9b%eb%8a%94-%eb%b0%a9%eb%b2%95-%ea%b0%80%eb%b9%84%ec%95%84-dns%ec%99%80-mailplus-%ec%84%a4%ec%a0%95/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Fri, 27 Mar 2026 09:34:56 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[admin메일설정]]></category>
		<category><![CDATA[A레코드]]></category>
		<category><![CDATA[howinfo.kr]]></category>
		<category><![CDATA[MailPlus설정]]></category>
		<category><![CDATA[MX레코드]]></category>
		<category><![CDATA[NAS메일서버]]></category>
		<category><![CDATA[가비아DNS]]></category>
		<category><![CDATA[도메인메일]]></category>
		<category><![CDATA[블로그운영]]></category>
		<category><![CDATA[시놀로지메일]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2168</guid>

					<description><![CDATA[<p>블로그나 사이트를 운영하다 보면 admin@howinfo.kr 같은 도메인 메일 주소가 필요해지는 순간이 있습니다. 문의 대응, 운영 알림, 제휴 메일 수신처럼 사이트...</p>
<p>게시물 <a href="https://howinfo.kr/%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80%ec%97%90%ec%84%9c-adminhowinfo-kr-%eb%a9%94%ec%9d%bc-%eb%b0%9b%eb%8a%94-%eb%b0%a9%eb%b2%95-%ea%b0%80%eb%b9%84%ec%95%84-dns%ec%99%80-mailplus-%ec%84%a4%ec%a0%95/">시놀로지에서 admin@howinfo.kr 메일 받는 방법, 가비아 DNS와 MailPlus 설정 정리</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>블로그나 사이트를 운영하다 보면 <code>admin@howinfo.kr</code> 같은 도메인 메일 주소가 필요해지는 순간이 있습니다. 문의 대응, 운영 알림, 제휴 메일 수신처럼 사이트 관리에 꼭 필요한 역할을 하기 때문입니다.</p>



<p>저도 처음에는 단순히 메일만 들어오면 된다고 생각했는데, 막상 설정해보니 MX 레코드, A 레코드, 시놀로지 MailPlus, 루트 도메인 접속 문제까지 함께 이해해야 제대로 동작했습니다. 특히 가비아 DNS에서 MX 값에 무엇을 넣어야 하는지, 그리고 why <code>howinfo.kr</code> 자체가 안 열리는지에서 가장 많이 헷갈렸습니다.</p>



<p>이번 글은 그런 시행착오를 줄이기 위해 정리한 실전 기록입니다.<br>설명에 사용하는 IP는 실제 값이 아니라 <strong>예시용 가상 IP</strong>입니다.</p>



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



<h2 class="wp-block-heading">이 글에서 정리하는 내용</h2>



<p>이 글에서는 아래 내용을 한 번에 정리합니다.</p>



<ul class="wp-block-list">
<li><code>admin@howinfo.kr</code> 메일을 시놀로지에서 받는 전체 구조</li>



<li>가비아 DNS에서 A, MX 레코드를 어떻게 넣어야 하는지</li>



<li><code>howinfo.kr</code> 접속이 안 될 때 무엇을 먼저 봐야 하는지</li>



<li>시놀로지 MailPlus에서 어떤 방식으로 계정을 연결하면 편한지</li>



<li>설정 중 자주 만나는 오류와 해결 포인트</li>
</ul>



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



<h2 class="wp-block-heading">왜 도메인 메일이 필요한가</h2>



<p>개인 메일 주소 대신 사이트 도메인 메일을 쓰면 운영 체계가 훨씬 정돈되어 보입니다. 예를 들어 <code>admin@howinfo.kr</code> 라는 주소는 사이트 관리자용 공식 창구처럼 보이기 때문에 방문자 입장에서도 신뢰도가 높습니다.</p>



<p>또한 도메인 메일은 문의 메일, 협업 요청, 운영 경고, 서비스 알림을 한곳으로 모으기 좋습니다. 이미 시놀로지 NAS를 사용하고 있다면 별도 외부 메일 서비스를 추가하지 않고도 직접 메일 수신 환경을 만들 수 있다는 점도 장점입니다.</p>



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



<h2 class="wp-block-heading">먼저 이해해야 하는 전체 구조</h2>



<p>도메인 메일은 아래 순서로 동작합니다.</p>



<ol class="wp-block-list">
<li>누군가 <code>admin@howinfo.kr</code> 로 메일을 보냅니다.</li>



<li>발신 서버는 <code>howinfo.kr</code> 의 MX 레코드를 조회합니다.</li>



<li>MX 레코드는 메일을 받을 서버 이름을 알려줍니다.</li>



<li>그 서버 이름은 다시 A 레코드를 통해 IP와 연결됩니다.</li>



<li>최종적으로 시놀로지 MailPlus Server가 메일을 수신합니다.</li>
</ol>



<p>여기서 핵심은 두 가지입니다.</p>



<p>첫째, <strong>MX는 메일 서버의 이름을 가리킵니다.</strong><br>둘째, <strong>A 레코드는 그 이름을 실제 IP와 연결합니다.</strong></p>



<p>즉 MX에는 IP를 넣는 것이 아니라 <code>mail.howinfo.kr</code> 같은 주소를 넣어야 합니다.</p>



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



<h2 class="wp-block-heading">MX에 IP를 넣으면 안 되는 이유</h2>



<p>처음 가장 많이 하는 실수가 바로 이 부분입니다.</p>



<p>아래처럼 설정하면 안 됩니다.</p>



<pre class="wp-block-preformatted">MX / @ / 203.0.113.25</pre>



<p>이건 잘못된 방식입니다.<br>MX는 메일 서버 이름을 가리켜야 하기 때문입니다.</p>



<p>올바른 예시는 아래와 같습니다.</p>



<pre class="wp-block-preformatted">A  / mail / 203.0.113.25<br>MX / @    / mail.howinfo.kr</pre>



<p>즉 먼저 <code>mail.howinfo.kr</code> 이라는 이름을 만들고, 그 이름을 A 레코드로 IP에 연결한 다음, MX는 그 이름을 바라보게 해야 합니다.</p>



<p>이 구조를 이해하면 메일 DNS 설정은 훨씬 쉬워집니다.</p>



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



<h2 class="wp-block-heading">howinfo.kr 기준 DNS 예시</h2>



<p>설명을 위한 가상 IP <code>203.0.113.25</code> 를 기준으로 하면, 최소한 아래처럼 구성하면 됩니다.</p>



<h3 class="wp-block-heading">웹 접속용</h3>



<pre class="wp-block-preformatted">A / @   / 203.0.113.25<br>A / www / 203.0.113.25</pre>



<h3 class="wp-block-heading">메일 수신용</h3>



<pre class="wp-block-preformatted">A  / mail / 203.0.113.25<br>MX / @    / mail.howinfo.kr</pre>



<p>표로 정리하면 아래와 같습니다.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>타입</th><th>호스트</th><th>값/위치</th><th>용도</th></tr></thead><tbody><tr><td>A</td><td>@</td><td>203.0.113.25</td><td>루트 도메인 접속</td></tr><tr><td>A</td><td>www</td><td>203.0.113.25</td><td>www 접속</td></tr><tr><td>A</td><td>mail</td><td>203.0.113.25</td><td>메일 서버 이름 연결</td></tr><tr><td>MX</td><td>@</td><td>mail.howinfo.kr</td><td>도메인 메일 수신 서버 지정</td></tr></tbody></table></figure>



<p>이 4줄이 가장 기본적인 핵심 설정입니다.</p>



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



<h2 class="wp-block-heading">howinfo.kr 이 안 열릴 때 먼저 볼 것</h2>



<p>실제로 설정 중 자주 겪는 문제가 있습니다.</p>



<ul class="wp-block-list">
<li><code>www.howinfo.kr</code> 는 열리는데</li>



<li><code>howinfo.kr</code> 는 안 열리는 경우</li>
</ul>



<p>이 경우는 대부분 아래 레코드가 빠져 있습니다.</p>



<pre class="wp-block-preformatted">A / @ / 203.0.113.25</pre>



<p>많은 분들이 <code>www</code> 만 설정하고 루트 도메인 <code>@</code> 를 빼먹습니다. 하지만 <code>howinfo.kr</code> 와 <code>www.howinfo.kr</code> 는 별도로 동작할 수 있기 때문에 둘 다 잡아줘야 합니다.</p>



<p>즉, howinfo.kr 자체 접속이 안 된다면 가장 먼저 <code>A / @</code> 레코드를 확인하면 됩니다.</p>



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



<h2 class="wp-block-heading">가비아 DNS에서 헷갈리는 부분</h2>



<p>가비아 DNS 화면을 보면 <code>호스트</code> 와 <code>값/위치</code> 입력칸 때문에 처음에는 조금 헷갈릴 수 있습니다.</p>



<p>예를 들어 아래처럼 입력하면 됩니다.</p>



<h3 class="wp-block-heading">A 레코드</h3>



<ul class="wp-block-list">
<li>타입: A</li>



<li>호스트: <code>mail</code></li>



<li>값/위치: <code>203.0.113.25</code></li>
</ul>



<p>이 뜻은 <code>mail.howinfo.kr</code> 이라는 주소를 해당 IP로 연결한다는 의미입니다.</p>



<h3 class="wp-block-heading">MX 레코드</h3>



<ul class="wp-block-list">
<li>타입: MX</li>



<li>호스트: <code>@</code></li>



<li>값/위치: <code>mail.howinfo.kr</code></li>



<li>우선순위: <code>10</code></li>
</ul>



<p>이 뜻은 <code>howinfo.kr</code> 로 들어오는 메일을 <code>mail.howinfo.kr</code> 가 받는다는 의미입니다.</p>



<p>여기서 가장 중요한 점은 <strong>MX 값에는 IP가 아니라 도메인 이름이 들어간다</strong>는 점입니다.</p>



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



<h2 class="wp-block-heading">시놀로지 MailPlus에서는 어떻게 구성하면 좋은가</h2>



<p>DNS가 끝나면 이제 시놀로지에서 메일을 받을 준비를 해야 합니다.</p>



<p>기본 순서는 아래와 같습니다.</p>



<ol class="wp-block-list">
<li>DSM 패키지 센터에서 MailPlus Server 설치</li>



<li>필요하면 MailPlus도 설치</li>



<li>대표 메일 서버 이름 설정</li>



<li>SMTP, IMAP 활성화</li>



<li>사용자 생성</li>



<li><code>admin@howinfo.kr</code> 수신 연결</li>
</ol>



<p>실무적으로는 내부 로그인용 계정과 외부 공개용 메일 주소를 분리하는 편이 편합니다.</p>



<p>예를 들어 아래처럼 운영할 수 있습니다.</p>



<ul class="wp-block-list">
<li>내부 사용자: <code>adminmail</code></li>



<li>외부 메일 주소: <code>admin@howinfo.kr</code></li>
</ul>



<p>이렇게 하면 외부에는 깔끔한 공식 메일 주소를 보여주면서도, 실제 시놀로지 내부에서는 관리하기 쉬운 사용자명으로 운영할 수 있습니다.</p>



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



<h2 class="wp-block-heading">가장 단순한 추천 구성</h2>



<p>howinfo.kr 하나만 기준으로 본다면 아래처럼 구성하면 충분합니다.</p>



<h3 class="wp-block-heading">DNS</h3>



<pre class="wp-block-preformatted">A  / @    / 203.0.113.25<br>A  / www  / 203.0.113.25<br>A  / mail / 203.0.113.25<br>MX / @    / mail.howinfo.kr</pre>



<h3 class="wp-block-heading">시놀로지</h3>



<ul class="wp-block-list">
<li>MailPlus Server 설치</li>



<li>도메인 <code>howinfo.kr</code> 등록</li>



<li>사용자 <code>adminmail</code> 생성</li>



<li><code>admin@howinfo.kr</code> 수신 연결</li>
</ul>



<h3 class="wp-block-heading">운영 방식</h3>



<ul class="wp-block-list">
<li>외부에서는 <code>admin@howinfo.kr</code> 로 메일 발송</li>



<li>시놀로지 MailPlus 받은편지함에서 확인</li>
</ul>



<p>이 구성이 가장 단순하면서도 관리하기 쉬운 형태입니다.</p>



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



<h2 class="wp-block-heading">설정 중 자주 만나는 문제</h2>



<h3 class="wp-block-heading">MX를 넣었는데 메일이 안 들어오는 경우</h3>



<p>이 경우는 보통 아래 둘 중 하나입니다.</p>



<ul class="wp-block-list">
<li>MX 값에 IP를 넣었음</li>



<li><code>mail</code> A 레코드가 없음</li>
</ul>



<p>정상 예시는 아래입니다.</p>



<pre class="wp-block-preformatted">A  / mail / 203.0.113.25<br>MX / @    / mail.howinfo.kr</pre>



<h3 class="wp-block-heading">가비아에서 저장이 안 되는 경우</h3>



<p><code>호스트를 입력해 주세요</code> 같은 메시지가 뜬다면 새 레코드를 추가해놓고 빈 칸이 남아 있는 경우가 많습니다. 새 줄을 만들었으면 타입, 호스트, 값/위치를 모두 채운 뒤 저장해야 합니다.</p>



<h3 class="wp-block-heading">howinfo.kr 자체가 접속되지 않는 경우</h3>



<p>이 경우는 아래가 빠졌을 가능성이 큽니다.</p>



<pre class="wp-block-preformatted">A / @ / 203.0.113.25</pre>



<h3 class="wp-block-heading">DNS는 맞는데 메일이 안 들어오는 경우</h3>



<p>이때는 DNS가 아니라 네트워크 문제일 수 있습니다. 아래를 같이 확인해야 합니다.</p>



<ul class="wp-block-list">
<li>공유기 포트포워딩</li>



<li>외부 25번 포트 수신 가능 여부</li>



<li>DSM 방화벽 허용 여부</li>



<li>MailPlus Server 정상 실행 여부</li>
</ul>



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



<h2 class="wp-block-heading">실제 작업은 이 순서가 가장 편했습니다</h2>



<p>제가 정리해보면 아래 순서가 가장 덜 헷갈립니다.</p>



<h3 class="wp-block-heading">1단계. DNS 먼저 정리</h3>



<pre class="wp-block-preformatted">A  / @    / 203.0.113.25<br>A  / www  / 203.0.113.25<br>A  / mail / 203.0.113.25<br>MX / @    / mail.howinfo.kr</pre>



<h3 class="wp-block-heading">2단계. 시놀로지 MailPlus 설치</h3>



<ul class="wp-block-list">
<li>MailPlus Server</li>



<li>MailPlus</li>
</ul>



<h3 class="wp-block-heading">3단계. 도메인 등록</h3>



<ul class="wp-block-list">
<li><code>howinfo.kr</code></li>
</ul>



<h3 class="wp-block-heading">4단계. 사용자 생성</h3>



<ul class="wp-block-list">
<li><code>adminmail</code></li>
</ul>



<h3 class="wp-block-heading">5단계. 수신 주소 연결</h3>



<ul class="wp-block-list">
<li><code>admin@howinfo.kr</code></li>
</ul>



<h3 class="wp-block-heading">6단계. 외부 발송 테스트</h3>



<ul class="wp-block-list">
<li>다른 메일 계정에서 <code>admin@howinfo.kr</code> 로 발송</li>



<li>시놀로지 받은편지함에서 정상 수신 확인</li>
</ul>



<p>이 순서대로 하면 중간에 꼬일 일이 많이 줄어듭니다.</p>



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



<h2 class="wp-block-heading">운영 관점에서 느낀 점</h2>



<p>howinfo.kr 같은 블로그나 정보 사이트를 운영할 때는 메일 시스템이 지나치게 복잡할 필요는 없습니다. 중요한 것은 문의를 놓치지 않고, 운영자가 쉽게 확인할 수 있으며, 외부에서 봤을 때 신뢰감을 주는 구조입니다.</p>



<p><code>admin@howinfo.kr</code> 메일 주소는 그런 점에서 꽤 실용적입니다. 시놀로지 NAS를 이미 사용 중이라면 추가 비용 없이 직접 운영할 수 있다는 것도 장점입니다.</p>



<p>물론 발신까지 안정적으로 운영하려면 SPF, DKIM, DMARC, PTR 같은 설정도 추가로 고려해야 합니다. 하지만 첫 단계에서는 수신 구조부터 정확히 잡는 것이 우선입니다.</p>



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



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



<p>이번 설정에서 가장 중요한 포인트는 두 가지였습니다.</p>



<p>하나는 <strong>MX에는 IP가 아니라 <code>mail.howinfo.kr</code> 같은 메일 서버 이름을 넣어야 한다</strong>는 점입니다.<br>다른 하나는 <strong>howinfo.kr 자체 접속을 위해 <code>A / @</code> 레코드가 꼭 필요하다</strong>는 점입니다.</p>



<p>결국 핵심은 아래 4줄입니다.</p>



<pre class="wp-block-preformatted">A  / @    / 203.0.113.25<br>A  / www  / 203.0.113.25<br>A  / mail / 203.0.113.25<br>MX / @    / mail.howinfo.kr</pre>



<p>이후 시놀로지 MailPlus에서 <code>admin@howinfo.kr</code> 수신 구조만 연결하면 기본적인 도메인 메일 환경은 완성됩니다.</p>



<p>처음에는 조금 복잡해 보여도 MX와 A 레코드의 역할만 제대로 구분하면 생각보다 어렵지 않게 정리할 수 있습니다.</p>



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



<h2 class="wp-block-heading">체크리스트</h2>



<p>아래 항목만 확인해도 대부분의 기본 오류는 줄일 수 있습니다.</p>



<ul class="wp-block-list">
<li><code>A / @</code> 레코드가 있는지</li>



<li><code>A / mail</code> 레코드가 있는지</li>



<li><code>MX / @ / mail.howinfo.kr</code> 로 설정했는지</li>



<li>MailPlus Server가 실행 중인지</li>



<li>공유기 포트포워딩이 되어 있는지</li>



<li>외부에서 테스트 메일을 보내봤는지</li>
</ul>



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



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



<h3 class="wp-block-heading">Q1. MX에는 왜 IP를 넣으면 안 되나요?</h3>



<p>MX는 메일 서버의 이름을 지정하는 레코드이기 때문입니다. IP는 A 레코드가 담당합니다.</p>



<h3 class="wp-block-heading">Q2. <code>mail.howinfo.kr</code> 는 꼭 필요한가요?</h3>



<p>반드시 <code>mail</code> 이어야 하는 것은 아니지만, 메일 서버용 서브도메인을 따로 두는 방식이 일반적이고 관리하기도 쉽습니다.</p>



<h3 class="wp-block-heading">Q3. howinfo.kr 는 안 열리고 www만 열리면 왜 그런가요?</h3>



<p>대부분 <code>A / @</code> 레코드가 빠져 있기 때문입니다.</p>



<h3 class="wp-block-heading">Q4. <code>admin@howinfo.kr</code> 를 실제 로그인 계정으로 꼭 만들어야 하나요?</h3>



<p>꼭 그렇지는 않습니다. 내부에서는 <code>adminmail</code> 같은 사용자로 운영하고, 외부 수신 주소만 <code>admin@howinfo.kr</code> 로 연결해도 됩니다.</p>



<h3 class="wp-block-heading">Q5. 이 글의 IP를 그대로 써도 되나요?</h3>



<p>아니요. 이 글의 IP는 예시용 가상 IP입니다. 실제 운영 시에는 본인의 공인 IP로 바꿔야 합니다.</p>



<p></p>
<p>게시물 <a href="https://howinfo.kr/%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80%ec%97%90%ec%84%9c-adminhowinfo-kr-%eb%a9%94%ec%9d%bc-%eb%b0%9b%eb%8a%94-%eb%b0%a9%eb%b2%95-%ea%b0%80%eb%b9%84%ec%95%84-dns%ec%99%80-mailplus-%ec%84%a4%ec%a0%95/">시놀로지에서 admin@howinfo.kr 메일 받는 방법, 가비아 DNS와 MailPlus 설정 정리</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80%ec%97%90%ec%84%9c-adminhowinfo-kr-%eb%a9%94%ec%9d%bc-%eb%b0%9b%eb%8a%94-%eb%b0%a9%eb%b2%95-%ea%b0%80%eb%b9%84%ec%95%84-dns%ec%99%80-mailplus-%ec%84%a4%ec%a0%95/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Docker란 무엇인가? 시놀로지 NAS DSM 7.3 Container Manager와 함께 이해하는 실전 입문 가이드</title>
		<link>https://howinfo.kr/docker%eb%9e%80-%eb%ac%b4%ec%97%87%ec%9d%b8%ea%b0%80-%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80-nas-dsm-7-3-container-manager%ec%99%80-%ed%95%a8%ea%bb%98-%ec%9d%b4%ed%95%b4%ed%95%98%eb%8a%94-%ec%8b%a4/</link>
					<comments>https://howinfo.kr/docker%eb%9e%80-%eb%ac%b4%ec%97%87%ec%9d%b8%ea%b0%80-%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80-nas-dsm-7-3-container-manager%ec%99%80-%ed%95%a8%ea%bb%98-%ec%9d%b4%ed%95%b4%ed%95%98%eb%8a%94-%ec%8b%a4/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Sat, 14 Mar 2026 00:08:33 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[ContainerManager]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[DockerCompose]]></category>
		<category><![CDATA[DSM7.3]]></category>
		<category><![CDATA[NAS활용]]></category>
		<category><![CDATA[도커]]></category>
		<category><![CDATA[시놀로지NAS]]></category>
		<category><![CDATA[워드프레스도커]]></category>
		<category><![CDATA[컨테이너]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2161</guid>

					<description><![CDATA[<p>도커(Docker)를 처음 접하면 가장 먼저 드는 생각이 있습니다.“가상머신이랑 뭐가 다른 거지?”“내 NAS에서도 쓸 수 있나?”“시놀로지의 Container Manager는 Docker랑 같은 건가?”...</p>
<p>게시물 <a href="https://howinfo.kr/docker%eb%9e%80-%eb%ac%b4%ec%97%87%ec%9d%b8%ea%b0%80-%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80-nas-dsm-7-3-container-manager%ec%99%80-%ed%95%a8%ea%bb%98-%ec%9d%b4%ed%95%b4%ed%95%98%eb%8a%94-%ec%8b%a4/">Docker란 무엇인가? 시놀로지 NAS DSM 7.3 Container Manager와 함께 이해하는 실전 입문 가이드</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>도커(Docker)를 처음 접하면 가장 먼저 드는 생각이 있습니다.<br>“가상머신이랑 뭐가 다른 거지?”<br>“내 NAS에서도 쓸 수 있나?”<br>“시놀로지의 Container Manager는 Docker랑 같은 건가?”</p>



<p>저도 처음에는 이 부분이 제일 헷갈렸습니다. PC에서는 Docker 명령어가 보이고, 시놀로지 NAS에서는 Container Manager라는 이름으로 보이니 완전히 다른 제품처럼 느껴졌거든요. 그런데 실제로 써보면 구조는 생각보다 단순합니다. <strong>Docker는 컨테이너를 실행하는 기반 기술</strong>이고, <strong>DSM 7.3의 Container Manager는 NAS에서 그걸 좀 더 쉽게 다루게 해주는 관리 도구</strong>에 가깝습니다. Docker 컨테이너는 호스트의 커널을 공유하는 가벼운 격리 프로세스라 VM보다 부담이 적고, Docker Compose는 여러 서비스를 한 번에 정의하고 띄울 수 있게 해줍니다.</p>



<p>이번 글에서는</p>



<ul class="wp-block-list">
<li>Docker가 왜 필요한지</li>



<li>시놀로지 NAS에서 Container Manager로 무엇을 할 수 있는지</li>



<li>둘의 차이를 어떻게 이해하면 쉬운지</li>



<li>실제 예시는 어떤 식으로 시작하면 좋은지</li>
</ul>



<p>이 순서로 정리해보겠습니다.</p>



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



<h2 class="wp-block-heading">Docker를 한 문장으로 설명하면</h2>



<p>Docker는 <strong>애플리케이션을 필요한 실행 환경과 함께 묶어서, 어느 서버에서든 비슷하게 실행할 수 있게 해주는 컨테이너 플랫폼</strong>입니다. Docker 공식 문서도 Docker를 “애플리케이션을 개발·배포·실행하기 위한 오픈 플랫폼”으로 설명하고 있고, 컨테이너는 필요한 파일을 포함한 격리된 프로세스로 설명합니다.</p>



<p>쉽게 말하면 이런 느낌입니다.</p>



<p>예전 방식은<br>“서버마다 설치 환경이 달라서 여기서는 되는데 저기서는 안 된다”는 문제가 자주 생겼습니다.</p>



<p>Docker 방식은<br>“앱 + 라이브러리 + 실행 환경”을 이미지로 묶어두고, 그 이미지를 어디서든 같은 방식으로 실행하는 구조입니다.</p>



<p>그래서 개발 PC에서 잘 돌던 앱을 NAS나 리눅스 서버로 옮길 때도 훨씬 예측 가능해집니다.</p>



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



<h2 class="wp-block-heading">컨테이너와 가상머신은 무엇이 다를까</h2>



<p>처음 입문할 때 가장 많이 비교하는 대상이 VM입니다.</p>



<p>가상머신은 운영체제 자체를 통째로 하나 더 올리는 느낌입니다.<br>반면 컨테이너는 <strong>호스트 OS의 커널을 공유하면서 필요한 프로세스만 격리해서 실행</strong>합니다. Docker 문서에서도 여러 컨테이너가 같은 커널을 공유한다고 설명합니다. 그래서 보통 컨테이너가 더 가볍고, 시작도 빠르고, 작은 단위의 서비스 배포에 잘 맞습니다.</p>



<p>제가 실무나 홈서버 관점에서 느낀 차이는 이렇습니다.</p>



<ul class="wp-block-list">
<li><strong>가상머신</strong>: 운영체제까지 따로 필요, 무겁지만 독립성이 큼</li>



<li><strong>컨테이너</strong>: 앱 단위 배포에 유리, 가볍고 빠름</li>



<li><strong>홈서버/NAS</strong>: 제한된 자원에서 여러 서비스를 띄우려면 컨테이너가 훨씬 효율적</li>
</ul>



<p>즉, NAS처럼 CPU·메모리가 아주 넉넉하지 않은 환경에서는 Docker가 특히 잘 맞습니다.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="512" height="768" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_contaner.png" alt="" class="wp-image-2163" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_contaner.png 512w, https://howinfo.kr/wp-content/uploads/2026/03/docker_contaner-200x300.png 200w" sizes="(max-width: 512px) 100vw, 512px" /></figure>



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



<h2 class="wp-block-heading">Docker에서 자주 보는 핵심 용어 5가지</h2>



<h3 class="wp-block-heading">1) 이미지(Image)</h3>



<p>컨테이너를 만들기 위한 템플릿입니다.<br>예를 들어 <code>nginx</code>, <code>postgres</code>, <code>wordpress</code> 같은 것들이 이미지입니다.</p>



<h3 class="wp-block-heading">2) 컨테이너(Container)</h3>



<p>이미지를 실제로 실행한 상태입니다.<br>이미지는 설계도, 컨테이너는 실행 중인 인스턴스라고 생각하면 이해가 쉽습니다.</p>



<h3 class="wp-block-heading">3) 볼륨(Volume)</h3>



<p>컨테이너를 지워도 데이터를 남기기 위한 저장소입니다.<br>DB 데이터, 업로드 파일, 설정 파일은 보통 볼륨에 분리합니다. Docker Engine 문서는 이미지·컨테이너 외에도 볼륨과 네트워크 같은 객체를 daemon이 관리한다고 설명합니다.</p>



<h3 class="wp-block-heading">4) 네트워크(Network)</h3>



<p>컨테이너끼리 통신하거나 외부와 연결될 때 쓰는 가상 네트워크입니다.</p>



<h3 class="wp-block-heading">5) Compose</h3>



<p>여러 컨테이너를 한 번에 정의하는 방식입니다. Docker는 Compose를 단일 YAML 파일로 서비스·네트워크·볼륨을 관리하는 도구로 설명합니다.</p>



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



<h2 class="wp-block-heading">Docker Engine과 Synology Container Manager의 관계</h2>



<p>이 부분이 가장 중요합니다.</p>



<p><strong>Docker Engine</strong>은 실제로 컨테이너를 실행하는 핵심 엔진입니다. Docker 공식 문서에 따르면 Docker Engine은 <code>dockerd</code> 데몬, API, CLI로 구성되고 이미지·컨테이너·네트워크·볼륨 등을 관리합니다.</p>



<p>반면 <strong>시놀로지 DSM 7.3의 Container Manager</strong>는<br>NAS 환경에서 컨테이너를 GUI로 다루기 쉽게 만든 관리 레이어라고 보면 됩니다. Synology 공식 문서에서는 Project 메뉴에서 하나 또는 여러 컨테이너로 구성된 프로젝트를 생성·운영·관리할 수 있다고 안내합니다.</p>



<p>즉,</p>



<ul class="wp-block-list">
<li><strong>Docker Engine</strong> = 실제 실행 엔진</li>



<li><strong>Container Manager</strong> = NAS에서 쉽게 다루는 관리 화면</li>



<li><strong>Compose / Project</strong> = 여러 컨테이너를 한 세트로 관리하는 방식</li>
</ul>



<p>이라고 이해하면 거의 맞습니다.</p>



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



<h2 class="wp-block-heading">DSM 7.3 Container Manager가 편한 이유</h2>



<p>시놀로지 NAS를 쓰는 분이라면 명령어보다 GUI가 편한 순간이 많습니다.</p>



<p>Container Manager의 장점은 이런 쪽에서 크게 느껴집니다.</p>



<h3 class="wp-block-heading">1) GUI로 이미지 검색과 다운로드가 쉬움</h3>



<p>Docker Hub에서 이미지를 찾고 내려받는 과정을 NAS 화면에서 처리할 수 있습니다.</p>



<h3 class="wp-block-heading">2) 컨테이너 생성이 쉬움</h3>



<p>포트, 환경변수, 볼륨 마운트, 재시작 정책 등을 화면에서 입력할 수 있어 초보자 진입장벽이 낮습니다.</p>



<h3 class="wp-block-heading">3) 로그와 상태 확인이 쉬움</h3>



<p>실행 여부, 에러 로그, 리소스 사용 현황을 빠르게 확인할 수 있습니다.</p>



<h3 class="wp-block-heading">4) Project 방식으로 Compose 운영이 가능함</h3>



<p>여러 컨테이너를 하나의 프로젝트처럼 묶어 관리할 수 있어서, 웹앱 + DB 같이 함께 움직여야 하는 구성을 다루기 편합니다. Synology 공식 Project 문서도 이 개념을 지원한다고 설명합니다.</p>



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



<h2 class="wp-block-heading">반대로 CLI Docker가 더 좋은 경우</h2>



<p>Container Manager가 편하긴 하지만, 모든 상황에서 최고는 아닙니다.</p>



<p>직접 <code>docker</code> 나 <code>docker compose</code> 명령어를 쓰면 좋은 경우도 분명합니다.</p>



<h3 class="wp-block-heading">1) 재현성이 좋음</h3>



<p>Compose 파일 하나만 있으면 다른 서버에서도 거의 같은 구조로 올리기 쉽습니다. Docker Compose는 다중 컨테이너 앱을 YAML로 정의하고 전체 라이프사이클을 관리할 수 있다고 공식 문서가 설명합니다.</p>



<h3 class="wp-block-heading">2) 백업과 버전관리가 쉬움</h3>



<p>설정이 파일로 남기 때문에 Git으로 관리하기 좋습니다.</p>



<h3 class="wp-block-heading">3) 자동화에 강함</h3>



<p>스크립트, CI/CD, 배포 자동화와 연결하기 좋습니다.</p>



<h3 class="wp-block-heading">4) 옵션을 세밀하게 다루기 좋음</h3>



<p>GUI에서 안 보이는 옵션도 CLI로는 직접 제어하기 쉽습니다.</p>



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



<h2 class="wp-block-heading">한눈에 비교: Docker CLI vs DSM 7.3 Container Manager</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>항목</th><th>Docker CLI / Compose</th><th>DSM 7.3 Container Manager</th></tr></thead><tbody><tr><td>진입장벽</td><td>초반엔 높음</td><td>낮음</td></tr><tr><td>설정 방식</td><td>텍스트 파일, 명령어</td><td>GUI 중심</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><tr><td>초보자 추천도</td><td>중간</td><td>높음</td></tr><tr><td>실무 확장성</td><td>매우 높음</td><td>홈서버/소규모 운영에 좋음</td></tr></tbody></table></figure>



<p>제 경험상</p>



<ul class="wp-block-list">
<li><strong>처음 시작</strong>은 Container Manager</li>



<li><strong>구성이 커지면 Compose 파일 관리</strong><br>이 흐름이 가장 안정적이었습니다.</li>
</ul>



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



<h2 class="wp-block-heading">실제 예시 1: 가장 쉬운 시작, Nginx 하나 띄워보기</h2>



<p>Docker 입문에서 제일 쉬운 예시는 정적 웹서버입니다.</p>



<p>예를 들어 Nginx 컨테이너 하나를 띄우면<br>“이미지 다운로드 → 컨테이너 실행 → 포트 연결”<br>이라는 Docker의 핵심 흐름을 빠르게 익힐 수 있습니다.</p>



<p>Docker 공식 문서에서 <code>docker run</code>은 이미지로부터 컨테이너를 실행하는 기본 명령이고, 이미지 참조에는 태그를 붙여 특정 버전을 지정할 수 있다고 설명합니다.</p>



<p>예시 명령은 이런 형태입니다.</p>



<pre class="wp-block-preformatted">docker run -d --name my-nginx -p 8080:80 nginx:latest</pre>



<p>이 의미는 다음과 같습니다.</p>



<ul class="wp-block-list">
<li><code>-d</code> : 백그라운드 실행</li>



<li><code>--name my-nginx</code> : 컨테이너 이름 지정</li>



<li><code>-p 8080:80</code> : NAS나 서버의 8080 포트를 컨테이너 80 포트와 연결</li>



<li><code>nginx:latest</code> : 실행할 이미지</li>
</ul>



<h3 class="wp-block-heading">DSM 7.3 Container Manager에서는?</h3>



<p>같은 작업을 GUI로 할 수 있습니다.</p>



<ol class="wp-block-list">
<li>이미지 검색에서 <code>nginx</code> 다운로드</li>



<li>새 컨테이너 생성</li>



<li>로컬 포트 8080 → 컨테이너 포트 80 연결</li>



<li>실행</li>



<li>브라우저에서 <code>NAS주소:8080</code> 접속</li>
</ol>



<p>처음 Docker를 이해할 때는 이 예시 하나만 성공해도 감이 많이 잡힙니다.</p>



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



<h2 class="wp-block-heading">실제 예시 2: 웹서비스답게, WordPress + MariaDB 같이 올리기</h2>



<p>여기부터는 Compose 개념이 정말 편해집니다.</p>



<p>워드프레스는 단독으로 끝나지 않고 보통</p>



<ul class="wp-block-list">
<li>WordPress 컨테이너</li>



<li>MariaDB 또는 MySQL 컨테이너<br>두 개 이상이 함께 필요합니다.</li>
</ul>



<p>이런 구조를 각각 따로 만들 수도 있지만, Compose로 관리하면 훨씬 정리됩니다. Compose는 여러 서비스를 한 YAML로 정의하는 방식이고, Docker 공식 빠른 시작도 Python 앱 + Redis 예시로 이런 멀티 컨테이너 구조를 보여줍니다.</p>



<p>아래는 입문용 예시입니다.</p>



<pre class="wp-block-preformatted">services:<br>  db:<br>    image: mariadb:11<br>    container_name: wp-db<br>    restart: unless-stopped<br>    environment:<br>      MYSQL_ROOT_PASSWORD: strong_root_password<br>      MYSQL_DATABASE: wordpress<br>      MYSQL_USER: wpuser<br>      MYSQL_PASSWORD: strong_wp_password<br>    volumes:<br>      - ./db_data:/var/lib/mysql  wordpress:<br>    image: wordpress:php8.2-apache<br>    container_name: wp-app<br>    restart: unless-stopped<br>    depends_on:<br>      - db<br>    ports:<br>      - "8081:80"<br>    environment:<br>      WORDPRESS_DB_HOST: db:3306<br>      WORDPRESS_DB_USER: wpuser<br>      WORDPRESS_DB_PASSWORD: strong_wp_password<br>      WORDPRESS_DB_NAME: wordpress<br>    volumes:<br>      - ./wp_data:/var/www/html</pre>



<h3 class="wp-block-heading">이 예시에서 중요한 포인트</h3>



<ul class="wp-block-list">
<li><code>services</code> 아래에 앱과 DB를 같이 정의</li>



<li><code>depends_on</code>으로 실행 순서를 어느 정도 정리</li>



<li><code>volumes</code>로 데이터를 컨테이너 밖에 보관</li>



<li>포트 <code>8081:80</code>으로 워드프레스 접속 가능</li>
</ul>



<h3 class="wp-block-heading">DSM 7.3 Container Manager에서는?</h3>



<p>Project 기능에서 이런 YAML 기반 구성을 가져와 관리할 수 있습니다. Synology 공식 문서도 Project가 하나 또는 여러 컨테이너로 구성된 프로젝트를 생성·관리하는 메뉴라고 설명합니다.</p>



<p>즉, NAS에서도<br>“단순 GUI 클릭”만이 아니라<br>“Compose 스타일의 프로젝트 운영”이 가능하다는 점이 꽤 큰 장점입니다.</p>



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



<h2 class="wp-block-heading">시놀로지 NAS에서 Docker를 쓸 때 특히 좋은 사례</h2>



<p>제가 보기엔 DSM 7.3 Container Manager는 아래 같은 용도에서 특히 강합니다.</p>



<h3 class="wp-block-heading">1) 홈서버 서비스 운영</h3>



<ul class="wp-block-list">
<li>워드프레스</li>



<li>n8n</li>



<li>Jellyfin</li>



<li>Joplin Server</li>



<li>Grafana</li>



<li>Portainer</li>
</ul>



<h3 class="wp-block-heading">2) 작은 사내 서비스 테스트</h3>



<ul class="wp-block-list">
<li>내부용 웹앱</li>



<li>API 서버</li>



<li>대시보드</li>



<li>DB 실험 환경</li>
</ul>



<h3 class="wp-block-heading">3) 개발·검증용 분리 환경</h3>



<p>같은 NAS 안에서도 프로젝트별로 분리해서 돌리기 좋습니다.</p>



<p>특히 시놀로지는 파일 접근, 폴더 권한, 백업 구조를 NAS 친화적으로 관리할 수 있어서 “홈랩 + 운영 연습” 용도로 꽤 괜찮습니다.</p>



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



<h2 class="wp-block-heading">Docker를 처음 쓸 때 가장 많이 하는 실수</h2>



<p>실제로 처음 할 때는 기술 자체보다 운영 습관에서 문제가 많이 납니다.</p>



<h3 class="wp-block-heading">1) 데이터를 컨테이너 안에만 저장함</h3>



<p>컨테이너 삭제 시 데이터가 같이 날아갈 수 있습니다.<br>DB, 업로드 파일, 설정 파일은 볼륨 또는 바인드 마운트로 분리하는 습관이 중요합니다. Docker Engine 문서도 persistent data에 volume 사용을 안내합니다.</p>



<h3 class="wp-block-heading">2) 포트 충돌을 확인하지 않음</h3>



<p>NAS에서 80, 443, 8080, 5000 계열 포트는 이미 다른 서비스가 쓰고 있을 수 있습니다.</p>



<h3 class="wp-block-heading">3) latest 태그만 무조건 사용함</h3>



<p>처음에는 편하지만, 나중에 버전이 달라져 예기치 않은 변경이 생길 수 있습니다. Docker 문서도 이미지 참조에 태그를 써서 특정 버전을 지정할 수 있다고 설명합니다.</p>



<h3 class="wp-block-heading">4) 환경변수를 정리하지 않음</h3>



<p>비밀번호나 설정값을 하드코딩하면 나중에 관리가 어렵습니다.</p>



<h3 class="wp-block-heading">5) 백업을 안 함</h3>



<p>Compose 파일, 데이터 폴더, DB 덤프는 반드시 따로 백업하는 습관이 필요합니다.</p>



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



<h2 class="wp-block-heading">입문자에게 추천하는 시작 순서</h2>



<p>처음이면 너무 어렵게 가지 않는 게 좋습니다.</p>



<h3 class="wp-block-heading">1단계</h3>



<p>Container Manager에서 <strong>Nginx 하나</strong> 띄워보기</p>



<h3 class="wp-block-heading">2단계</h3>



<p>볼륨 마운트와 포트 매핑 이해하기</p>



<h3 class="wp-block-heading">3단계</h3>



<p>환경변수 넣는 컨테이너 실행해보기<br>예: DB, 워드프레스</p>



<h3 class="wp-block-heading">4단계</h3>



<p>Project 기능으로 Compose 스타일 구성 써보기</p>



<h3 class="wp-block-heading">5단계</h3>



<p>나중에는 YAML 파일을 따로 관리하면서 버전관리까지 연결하기</p>



<p>이렇게 가면 GUI의 편의성과 Docker 본질 둘 다 잡을 수 있습니다.</p>



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



<h2 class="wp-block-heading">결국 무엇이 더 좋을까</h2>



<p>정리하면 이렇습니다.</p>



<p><strong>Docker</strong>는 컨테이너를 실행하는 기술 자체이고,<br><strong>DSM 7.3 Container Manager</strong>는 그 기술을 시놀로지 NAS에서 쉽게 다루는 도구입니다. Docker는 애플리케이션을 컨테이너로 패키징해 실행하게 해주고, Docker Compose는 여러 서비스를 하나의 YAML로 정의·운영하게 해주며, Synology의 Project 기능은 이런 멀티 컨테이너 구성을 NAS GUI에서 관리하는 데 초점을 둡니다.</p>



<p>그래서 제 추천은 단순합니다.</p>



<ul class="wp-block-list">
<li><strong>처음 배우는 단계</strong>라면 → DSM 7.3 Container Manager부터</li>



<li><strong>반복 배포와 구조화가 필요해지면</strong> → Compose 파일 관리까지</li>



<li><strong>실무형으로 확장하고 싶다면</strong> → CLI와 YAML 중심으로 이동</li>
</ul>



<p>처음부터 명령어만 붙잡고 씨름할 필요는 없습니다.<br>반대로 GUI만 쓰다 보면 구조를 놓칠 수도 있습니다.<br>가장 좋은 방법은 <strong>시놀로지 GUI로 감을 잡고, 나중에 Compose로 정리하는 흐름</strong>입니다.</p>



<p>이 방식이 홈서버 운영에도 좋고, 나중에 리눅스 서버나 클라우드로 넘어갈 때도 가장 자연스럽습니다.</p>



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



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



<p>Docker를 배우면 단순히 “앱 하나 실행하는 법”만 익히는 게 아닙니다.<br><strong>서비스를 더 깔끔하게 배포하고, 더 쉽게 옮기고, 더 안정적으로 관리하는 방식</strong>을 배우게 됩니다.</p>



<p>시놀로지 NAS의 DSM 7.3 Container Manager는 그 첫걸음을 꽤 쉽게 만들어줍니다.<br>특히 홈서버, 개인 블로그, 자동화 도구, DB 실험 환경, 내부 웹서비스를 운영하려는 분들에게는 정말 좋은 입문 도구입니다.</p>



<p>저도 처음에는 NAS에서 GUI로 시작했지만, 나중에는 Compose 파일을 직접 관리하는 쪽이 훨씬 편해졌습니다.<br>그래서 처음 시작하시는 분이라면 이렇게 말씀드리고 싶습니다.</p>



<p><strong>“Container Manager로 시작하고, Docker Compose로 정리해가면 됩니다.”</strong></p>



<p>그 흐름만 잡혀도 Docker가 훨씬 덜 어렵게 느껴질 겁니다.</p>



<p></p>
<p>게시물 <a href="https://howinfo.kr/docker%eb%9e%80-%eb%ac%b4%ec%97%87%ec%9d%b8%ea%b0%80-%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80-nas-dsm-7-3-container-manager%ec%99%80-%ed%95%a8%ea%bb%98-%ec%9d%b4%ed%95%b4%ed%95%98%eb%8a%94-%ec%8b%a4/">Docker란 무엇인가? 시놀로지 NAS DSM 7.3 Container Manager와 함께 이해하는 실전 입문 가이드</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/docker%eb%9e%80-%eb%ac%b4%ec%97%87%ec%9d%b8%ea%b0%80-%ec%8b%9c%eb%86%80%eb%a1%9c%ec%a7%80-nas-dsm-7-3-container-manager%ec%99%80-%ed%95%a8%ea%bb%98-%ec%9d%b4%ed%95%b4%ed%95%98%eb%8a%94-%ec%8b%a4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>메모리플레이션 시대: D램 가격 7배 폭등이 IT 시장을 뒤흔드는 이유</title>
		<link>https://howinfo.kr/%eb%a9%94%eb%aa%a8%eb%a6%ac%ed%94%8c%eb%a0%88%ec%9d%b4%ec%85%98-%ec%8b%9c%eb%8c%80-d%eb%9e%a8-%ea%b0%80%ea%b2%a9-7%eb%b0%b0-%ed%8f%ad%eb%93%b1%ec%9d%b4-it-%ec%8b%9c%ec%9e%a5%ec%9d%84-%eb%92%a4/</link>
					<comments>https://howinfo.kr/%eb%a9%94%eb%aa%a8%eb%a6%ac%ed%94%8c%eb%a0%88%ec%9d%b4%ec%85%98-%ec%8b%9c%eb%8c%80-d%eb%9e%a8-%ea%b0%80%ea%b2%a9-7%eb%b0%b0-%ed%8f%ad%eb%93%b1%ec%9d%b4-it-%ec%8b%9c%ec%9e%a5%ec%9d%84-%eb%92%a4/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Fri, 06 Mar 2026 01:21:53 +0000</pubDate>
				<category><![CDATA[트렌드·이슈]]></category>
		<category><![CDATA[AI데이터센터]]></category>
		<category><![CDATA[AI반도체]]></category>
		<category><![CDATA[DDR4]]></category>
		<category><![CDATA[DDR5]]></category>
		<category><![CDATA[D램가격]]></category>
		<category><![CDATA[HBM]]></category>
		<category><![CDATA[IT트렌드]]></category>
		<category><![CDATA[램테크]]></category>
		<category><![CDATA[메모리플레이션]]></category>
		<category><![CDATA[반도체시장]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2152</guid>

					<description><![CDATA[<p>최근 IT 산업에서는 새로운 경제 현상이 등장했습니다.바로 ‘메모리플레이션(Memory + Inflation)’ 입니다. 메모리 반도체 가격 상승이 스마트폰, PC, 서버, 자동차 등...</p>
<p>게시물 <a href="https://howinfo.kr/%eb%a9%94%eb%aa%a8%eb%a6%ac%ed%94%8c%eb%a0%88%ec%9d%b4%ec%85%98-%ec%8b%9c%eb%8c%80-d%eb%9e%a8-%ea%b0%80%ea%b2%a9-7%eb%b0%b0-%ed%8f%ad%eb%93%b1%ec%9d%b4-it-%ec%8b%9c%ec%9e%a5%ec%9d%84-%eb%92%a4/">메모리플레이션 시대: D램 가격 7배 폭등이 IT 시장을 뒤흔드는 이유</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>최근 IT 산업에서는 새로운 경제 현상이 등장했습니다.<br>바로 <strong>‘메모리플레이션(Memory + Inflation)’</strong> 입니다.</p>



<p>메모리 반도체 가격 상승이 스마트폰, PC, 서버, 자동차 등 <strong>전자제품 가격을 동시에 끌어올리는 현상</strong>을 의미합니다.</p>



<p>최근 시장 조사에 따르면 <strong>PC용 DRAM 가격이 1년 사이 약 7배 상승</strong>했습니다.</p>



<p>이러한 가격 상승은 단순한 공급 부족이 아니라 <strong>AI 산업의 폭발적인 성장과 데이터센터 투자 확대</strong> 때문으로 분석되고 있습니다.</p>



<p>이번 글에서는</p>



<ul class="wp-block-list">
<li>메모리 가격 폭등의 구조적 원인</li>



<li>글로벌 IT 기업 가격 인상 사례</li>



<li>‘램테크’라는 새로운 투자 트렌드</li>



<li>자동차 산업까지 확산되는 영향</li>



<li>향후 반도체 시장 전망</li>
</ul>



<p>을 <strong>국내외 시장 분석과 기술 흐름을 기반으로 정리했습니다.</strong></p>



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



<h1 class="wp-block-heading">메모리플레이션이란 무엇인가</h1>



<p>메모리플레이션은 <strong>메모리 반도체 가격 상승이 IT 제품 가격 상승으로 이어지는 현상</strong>입니다.</p>



<p>대표적인 메모리 반도체는 다음과 같습니다.</p>



<h3 class="wp-block-heading">DRAM</h3>



<p>컴퓨터와 스마트폰에서 <strong>작업용 메모리</strong>로 사용됩니다.</p>



<h3 class="wp-block-heading">NAND Flash</h3>



<p>SSD와 스마트폰 저장공간에 사용되는 <strong>데이터 저장 메모리</strong>입니다.</p>



<p>최근 AI 산업 성장으로 이 두 가지 메모리의 수요가 크게 증가했습니다.</p>



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



<h1 class="wp-block-heading">PC용 DRAM 가격이 7배 상승한 이유</h1>



<p>최근 시장에서 가장 큰 변화는 <strong>범용 DRAM 가격 폭등</strong>입니다.</p>



<p>대표적인 PC 메모리</p>



<p><strong>DDR4 8Gb DRAM</strong></p>



<p>가격 변화</p>



<p>2025년<br>약 <strong>1.6달러</strong></p>



<p>2026년<br>약 <strong>11~17달러</strong></p>



<p>즉 <strong>1년 사이 최대 7배 상승</strong>했습니다.</p>



<p>이러한 상승에는 몇 가지 핵심 원인이 있습니다.</p>



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



<h1 class="wp-block-heading">AI 데이터센터가 메모리를 빨아들이고 있다</h1>



<p>현재 전 세계 빅테크 기업들은 <strong>AI 데이터센터 투자 경쟁</strong>을 벌이고 있습니다.</p>



<p>대표 기업</p>



<ul class="wp-block-list">
<li>Microsoft</li>



<li>Google</li>



<li>Amazon</li>



<li>Meta</li>



<li>OpenAI</li>
</ul>



<p>이 기업들은 AI 모델 학습을 위해 <strong>대규모 GPU 서버</strong>를 구축하고 있습니다.</p>



<p>AI 서버 특징</p>



<p>일반 서버보다</p>



<p><strong>메모리 사용량이 10배 이상</strong></p>



<p>많습니다.</p>



<p>특히 GPU 서버에는</p>



<ul class="wp-block-list">
<li>DDR5 메모리</li>



<li>HBM 메모리</li>



<li>초고속 SSD</li>
</ul>



<p>가 대량으로 사용됩니다.</p>



<p>이 때문에 <strong>메모리 수요가 폭발적으로 증가</strong>했습니다.</p>



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



<h1 class="wp-block-heading">메모리 제조사 전략 변화</h1>



<p>메모리 시장은 현재 <strong>3개 기업이 대부분을 공급</strong>합니다.</p>



<p>주요 기업</p>



<ul class="wp-block-list">
<li>삼성전자</li>



<li>SK하이닉스</li>



<li>마이크론</li>
</ul>



<p>이 기업들은 최근 생산 전략을 바꾸고 있습니다.</p>



<p>과거</p>



<p>범용 DRAM 중심</p>



<p>현재</p>



<p>AI용 메모리 중심</p>



<p>대표적인 AI 메모리</p>



<p><strong>HBM (High Bandwidth Memory)</strong></p>



<p>HBM은 GPU와 함께 사용되는 고성능 메모리입니다.</p>



<p>AI 시장이 성장하면서 제조사들은 <strong>HBM 생산을 늘리고 일반 DRAM 생산을 줄이고 있습니다.</strong></p>



<p>그 결과 <strong>PC와 스마트폰용 메모리 공급이 줄어 가격이 상승</strong>했습니다.</p>



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



<h1 class="wp-block-heading">스마트폰 가격 상승의 숨은 이유</h1>



<p>메모리 가격 상승은 스마트폰 가격에도 직접 영향을 주고 있습니다.</p>



<p>과거 스마트폰 원가 구조</p>



<p>메모리 비중<br>약 <strong>10~15%</strong></p>



<p>현재</p>



<p>약 <strong>30% 수준</strong></p>



<p>으로 증가한 것으로 업계는 분석합니다.</p>



<p>AI 기능이 강화되면서</p>



<ul class="wp-block-list">
<li>메모리 용량 증가</li>



<li>저장공간 증가</li>



<li>AI 연산 기능</li>
</ul>



<p>이 추가됐기 때문입니다.</p>



<p>최근 일부 프리미엄 스마트폰은</p>



<p><strong>200만 원을 넘어가는 가격</strong></p>



<p>까지 등장했습니다.</p>



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



<h1 class="wp-block-heading">노트북과 PC 가격도 상승 중</h1>



<p>AI PC 시대가 시작되면서 노트북 가격도 빠르게 상승하고 있습니다.</p>



<p>AI PC 특징</p>



<ul class="wp-block-list">
<li>32GB 이상 메모리</li>



<li>NPU AI 프로세서</li>



<li>대용량 SSD</li>
</ul>



<p>이러한 구조 때문에 <strong>노트북 원가가 크게 증가</strong>했습니다.</p>



<p>최근 프리미엄 노트북은</p>



<p><strong>300만 ~ 400만 원대</strong></p>



<p>가격도 등장하고 있습니다.</p>



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



<h1 class="wp-block-heading">중고 시장에서 등장한 ‘램테크’</h1>



<p>최근 IT 커뮤니티와 중고 거래 시장에서는 새로운 트렌드가 나타났습니다.</p>



<p>바로 <strong>램테크(RAM + 재테크)</strong> 입니다.</p>



<p>의미</p>



<p>메모리를 미리 구매해 두었다가 가격 상승 후 판매하는 방식입니다.</p>



<p>실제로 중고 거래 플랫폼에서는</p>



<ul class="wp-block-list">
<li>DDR4</li>



<li>DDR5</li>



<li>서버용 메모리</li>
</ul>



<p>거래량이 <strong>수백 퍼센트 증가</strong>했습니다.</p>



<p>일부 시장에서는 <strong>자동화 프로그램이 메모리를 대량 구매하는 현상</strong>도 보고되었습니다.</p>



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



<h1 class="wp-block-heading">맥미니 사재기 현상</h1>



<p>최근 해외 IT 커뮤니티에서는 <strong>맥미니 사재기 현상</strong>도 나타났습니다.</p>



<p>이유는 간단합니다.</p>



<p>맥미니 기본 모델에는</p>



<ul class="wp-block-list">
<li>16GB 메모리</li>



<li>Apple Silicon 칩</li>
</ul>



<p>이 탑재되어 있는데 <strong>제품 가격 대비 성능이 매우 높기 때문</strong>입니다.</p>



<p>일부 사용자들은</p>



<ul class="wp-block-list">
<li>가격 상승 전에 구매</li>



<li>중고 재판매</li>
</ul>



<p>목적으로 제품을 확보하고 있습니다.</p>



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



<h1 class="wp-block-heading">자동차 산업까지 영향 가능성</h1>



<p>메모리플레이션은 IT 산업을 넘어 <strong>자동차 산업에도 영향을 줄 가능성</strong>이 있습니다.</p>



<p>최근 자동차에는</p>



<ul class="wp-block-list">
<li>자율주행 시스템</li>



<li>ADAS</li>



<li>차량용 OS</li>



<li>인포테인먼트</li>
</ul>



<p>등이 들어갑니다.</p>



<p>이 시스템들은 모두 <strong>반도체와 메모리를 필요로 합니다.</strong></p>



<p>만약 차량용 메모리 공급이 부족해지면</p>



<ul class="wp-block-list">
<li>자동차 생산 지연</li>



<li>차량 가격 상승</li>
</ul>



<p>같은 문제가 발생할 수 있습니다.</p>



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



<h1 class="wp-block-heading">메모리 슈퍼사이클이 시작됐을까</h1>



<p>반도체 업계에서는 현재 상황을</p>



<p><strong>“메모리 슈퍼사이클”</strong></p>



<p>초기 단계로 보는 의견도 있습니다.</p>



<p>전문가 전망</p>



<p>2026년 메모리 시장 성장률</p>



<p>약 <strong>30% 이상</strong></p>



<p>AI용 메모리 시장은</p>



<p><strong>연평균 30% 성장</strong></p>



<p>할 것으로 예상됩니다.</p>



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



<h1 class="wp-block-heading">소비자가 알아야 할 변화</h1>



<p>현재 메모리플레이션은 단순한 가격 상승이 아닙니다.</p>



<p>앞으로는</p>



<ul class="wp-block-list">
<li>스마트폰</li>



<li>PC</li>



<li>서버</li>



<li>자동차</li>
</ul>



<p>모든 전자 제품에서 <strong>반도체 가격이 핵심 변수</strong>가 될 가능성이 높습니다.</p>



<p>소비자 행동도 바뀌고 있습니다.</p>



<p>대표 사례</p>



<ul class="wp-block-list">
<li>전자제품 미리 구매</li>



<li>부품 투자</li>



<li>중고 거래 증가</li>
</ul>



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



<h1 class="wp-block-heading">앞으로 메모리 가격 전망</h1>



<p>전문가들은 메모리 가격 상승이 <strong>단기간에 끝나지 않을 가능성</strong>이 높다고 보고 있습니다.</p>



<p>이유</p>



<p>1️⃣ AI 데이터센터 투자 확대<br>2️⃣ GPU 서버 증가<br>3️⃣ HBM 수요 폭증<br>4️⃣ 신규 반도체 공장 건설 지연</p>



<p>일부 신규 공장은</p>



<p><strong>2027년 이후</strong></p>



<p>에야 본격 생산을 시작할 예정입니다.</p>



<p>즉 당분간 <strong>공급 부족 상황이 지속될 가능성</strong>이 있습니다.</p>



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



<h1 class="wp-block-heading">핵심 정리</h1>



<p>현재 IT 산업에서는 <strong>메모리 중심 경제 구조</strong>가 형성되고 있습니다.</p>



<p>핵심 변화</p>



<ul class="wp-block-list">
<li>DRAM 가격 1년 사이 최대 7배 상승</li>



<li>AI 데이터센터가 메모리 수요 폭증</li>



<li>스마트폰·PC 가격 상승</li>



<li>중고 시장 ‘램테크’ 등장</li>



<li>자동차 산업까지 영향 가능성</li>
</ul>



<p>AI 시대가 본격화되면서 메모리 반도체는 <strong>석유와 비슷한 전략 자원</strong>이 될 가능성도 있습니다.</p>



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



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



<h3 class="wp-block-heading">메모리플레이션이란 무엇인가요</h3>



<p>메모리 반도체 가격 상승이 IT 제품 가격 상승으로 이어지는 현상을 의미합니다.</p>



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



<h3 class="wp-block-heading">왜 DRAM 가격이 갑자기 상승했나요</h3>



<p>AI 데이터센터 확대로 메모리 수요가 급증했기 때문입니다.</p>



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



<h3 class="wp-block-heading">앞으로 스마트폰 가격이 계속 오를까요</h3>



<p>AI 기능과 메모리 증가 때문에 <strong>프리미엄 스마트폰 가격 상승 가능성</strong>이 높습니다.</p>



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



<h3 class="wp-block-heading">램테크는 실제로 가능한 투자 방법인가요</h3>



<p>가격 변동이 큰 부품 시장이기 때문에 <strong>단기적인 수익 가능성은 있지만 안정적인 투자 방식은 아닙니다.</strong></p>



<p></p>
<p>게시물 <a href="https://howinfo.kr/%eb%a9%94%eb%aa%a8%eb%a6%ac%ed%94%8c%eb%a0%88%ec%9d%b4%ec%85%98-%ec%8b%9c%eb%8c%80-d%eb%9e%a8-%ea%b0%80%ea%b2%a9-7%eb%b0%b0-%ed%8f%ad%eb%93%b1%ec%9d%b4-it-%ec%8b%9c%ec%9e%a5%ec%9d%84-%eb%92%a4/">메모리플레이션 시대: D램 가격 7배 폭등이 IT 시장을 뒤흔드는 이유</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%eb%a9%94%eb%aa%a8%eb%a6%ac%ed%94%8c%eb%a0%88%ec%9d%b4%ec%85%98-%ec%8b%9c%eb%8c%80-d%eb%9e%a8-%ea%b0%80%ea%b2%a9-7%eb%b0%b0-%ed%8f%ad%eb%93%b1%ec%9d%b4-it-%ec%8b%9c%ec%9e%a5%ec%9d%84-%eb%92%a4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>너무나 쉬운 윈도우즈11+docker 이용 베드락 마인크래프트 설치하고 외부에서 접근하여 게임즐기기</title>
		<link>https://howinfo.kr/%eb%84%88%eb%ac%b4%eb%82%98-%ec%89%ac%ec%9a%b4-%ec%9c%88%eb%8f%84%ec%9a%b0%ec%a6%8811docker-%ec%9d%b4%ec%9a%a9-%eb%b2%a0%eb%93%9c%eb%9d%bd-%eb%a7%88%ec%9d%b8%ed%81%ac%eb%9e%98%ed%94%84%ed%8a%b8/</link>
					<comments>https://howinfo.kr/%eb%84%88%eb%ac%b4%eb%82%98-%ec%89%ac%ec%9a%b4-%ec%9c%88%eb%8f%84%ec%9a%b0%ec%a6%8811docker-%ec%9d%b4%ec%9a%a9-%eb%b2%a0%eb%93%9c%eb%9d%bd-%eb%a7%88%ec%9d%b8%ed%81%ac%eb%9e%98%ed%94%84%ed%8a%b8/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Wed, 04 Mar 2026 08:43:59 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[BDS]]></category>
		<category><![CDATA[bedrock]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[gameserver]]></category>
		<category><![CDATA[iptime]]></category>
		<category><![CDATA[게임서버]]></category>
		<category><![CDATA[마인크래프트]]></category>
		<category><![CDATA[포트포워딩]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2143</guid>

					<description><![CDATA[<p>집에서 마인크래프트(베드락) 서버를 운영할 때 제일 깔끔한 방법은 BDS(Bedrock Dedicated Server) 를 Docker 컨테이너로 실행하는 것입니다.이번 글은 플러그인/애드온 없이, 서버가...</p>
<p>게시물 <a href="https://howinfo.kr/%eb%84%88%eb%ac%b4%eb%82%98-%ec%89%ac%ec%9a%b4-%ec%9c%88%eb%8f%84%ec%9a%b0%ec%a6%8811docker-%ec%9d%b4%ec%9a%a9-%eb%b2%a0%eb%93%9c%eb%9d%bd-%eb%a7%88%ec%9d%b8%ed%81%ac%eb%9e%98%ed%94%84%ed%8a%b8/">너무나 쉬운 윈도우즈11+docker 이용 베드락 마인크래프트 설치하고 외부에서 접근하여 게임즐기기</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>집에서 마인크래프트(베드락) 서버를 운영할 때 제일 깔끔한 방법은 <strong>BDS(Bedrock Dedicated Server)</strong> 를 <strong>Docker 컨테이너로 실행</strong>하는 것입니다.<br>이번 글은 <strong>플러그인/애드온 없이</strong>, 서버가 실제로 동작하는지 <strong>안드로이드에서 접속 확인</strong>하고, 마지막으로 <strong>ipTIME 포트포워딩</strong>으로 <strong>집 밖(외부) 접속</strong>까지 완성하는 실전 절차를 정리합니다.</p>



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



<h2 class="wp-block-heading">1) 준비물 체크</h2>



<ul class="wp-block-list">
<li>Windows 11 (Pro/Home 무관)</li>



<li>Docker Desktop 설치 완료 (<code>docker ps</code>가 에러 없이 동작해야 함)</li>



<li>공유기: ipTIME (KT 회선 환경 가정)</li>



<li>접속 클라이언트: 안드로이드 Minecraft(베드락)</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="789" height="447" src="https://howinfo.kr/wp-content/uploads/2026/03/bedrock01.png" alt="" class="wp-image-2148" srcset="https://howinfo.kr/wp-content/uploads/2026/03/bedrock01.png 789w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock01-300x170.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock01-768x435.png 768w" sizes="(max-width: 789px) 100vw, 789px" /></figure>



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



<h2 class="wp-block-heading">2) BDS 기본 포트(중요)</h2>



<p>베드락 서버 기본 포트는 다음과 같습니다.</p>



<ul class="wp-block-list">
<li><strong>UDP 19132</strong> (게임 접속 포트)</li>
</ul>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="37" src="https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-1024x37.png" alt="" class="wp-image-2144" srcset="https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-1024x37.png 1024w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-300x11.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-768x28.png 768w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock05.png 1427w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>즉, 내부/외부 모두 <strong>UDP 19132</strong>만 제대로 열리면 접속이 됩니다.</p>



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



<h2 class="wp-block-heading">3) Docker로 BDS 설치(Compose 방식)</h2>



<h3 class="wp-block-heading">3-1. 서버 폴더 만들기 (월드/설정 영구 저장)</h3>



<p>예시: <code>D:\minecraft\bedrock</code></p>



<p>PowerShell:</p>



<pre class="wp-block-preformatted">mkdir D:\minecraft\bedrock<br>cd D:\minecraft\bedrock</pre>



<h3 class="wp-block-heading">3-2. docker-compose.yml 만들기</h3>



<p><code>D:\minecraft\bedrock\docker-compose.yml</code> 파일을 만들고 아래 내용을 그대로 붙여넣습니다.</p>



<pre class="wp-block-preformatted">services:<br>  bds:<br>    image: itzg/minecraft-bedrock-server:latest<br>    container_name: mc-bedrock<br>    ports:<br>      - "19132:19132/udp"<br>    environment:<br>      EULA: "TRUE"<br>      SERVER_NAME: "Howinfo Bedrock Server"<br>      GAMEMODE: "survival"<br>      DIFFICULTY: "normal"<br>      LEVEL_NAME: "HowinfoWorld"<br>      MAX_PLAYERS: "10"<br>      ONLINE_MODE: "true"<br>      TZ: "Asia/Seoul"<br>    volumes:<br>      - ./data:/data<br>    restart: unless-stopped</pre>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="675" height="616" src="https://howinfo.kr/wp-content/uploads/2026/03/bedrock04.png" alt="" class="wp-image-2145" srcset="https://howinfo.kr/wp-content/uploads/2026/03/bedrock04.png 675w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock04-300x274.png 300w" sizes="auto, (max-width: 675px) 100vw, 675px" /></figure>



<h3 class="wp-block-heading">3-3. 서버 실행</h3>



<pre class="wp-block-preformatted">docker compose up -d</pre>



<p>정상 동작 확인:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="102" src="https://howinfo.kr/wp-content/uploads/2026/03/bedrock03-1024x102.png" alt="" class="wp-image-2146" srcset="https://howinfo.kr/wp-content/uploads/2026/03/bedrock03-1024x102.png 1024w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock03-300x30.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock03-768x76.png 768w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock03.png 1029w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<pre class="wp-block-preformatted">docker ps<br>docker logs -f mc-bedrock</pre>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="735" height="374" src="https://howinfo.kr/wp-content/uploads/2026/03/bedrock02.png" alt="" class="wp-image-2147" srcset="https://howinfo.kr/wp-content/uploads/2026/03/bedrock02.png 735w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock02-300x153.png 300w" sizes="auto, (max-width: 735px) 100vw, 735px" /></figure>



<ul class="wp-block-list">
<li><code>docker ps</code>에서 <code>mc-bedrock</code>이 Running이면 1차 성공</li>



<li><code>docker logs -f</code>에서 심각한 에러 없이 대기 상태로 들어가면 OK</li>
</ul>



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



<h2 class="wp-block-heading">4) Windows 방화벽 열기 (UDP 19132)</h2>



<p>서버 PC(Windows 11)에서 방화벽이 막고 있으면, 같은 집에서도 접속이 안 될 수 있습니다.</p>



<p><strong>Windows 보안 → 방화벽 및 네트워크 보호 → 고급 설정 → 인바운드 규칙 → 새 규칙</strong></p>



<ul class="wp-block-list">
<li>규칙 유형: <strong>포트</strong></li>



<li>프로토콜: <strong>UDP</strong></li>



<li>포트: <strong>19132</strong></li>



<li>허용</li>



<li>프로필: 보통 <strong>개인(Private)</strong> 포함(필요 시 도메인도)</li>



<li>이름 예: <code>Minecraft Bedrock UDP 19132</code></li>
</ul>



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



<h2 class="wp-block-heading">5) 안드로이드에서 “같은 와이파이”로 접속 확인 (내부 접속)</h2>



<p>외부 설정 전에 먼저 내부에서 정상 접속되는지 확인하는 게 가장 빠릅니다.</p>



<h3 class="wp-block-heading">5-1. 서버 PC 내부 IP 확인</h3>



<p>PowerShell:</p>



<pre class="wp-block-preformatted">ipconfig</pre>



<p>예: <code>192.168.0.15</code></p>



<h3 class="wp-block-heading">5-2. 안드로이드 Minecraft에서 서버 추가</h3>



<p>Minecraft(베드락) → <strong>플레이</strong> → <strong>서버</strong> → <strong>서버 추가</strong> (핸드폰에서 연결할 서버주소 또는 도메인 직접 입력)</p>



<ul class="wp-block-list">
<li>서버 이름: 아무거나</li>



<li>서버 주소: <code>192.168.0.15</code> (서버 PC 내부 IP)</li>



<li>포트: <code>19132</code></li>
</ul>



<p>✅ 같은 와이파이에서 접속이 되면, <strong>BDS 설치/컨테이너/방화벽은 거의 끝난 것</strong>입니다.</p>



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



<h2 class="wp-block-heading">6) ipTIME 공유기 포트포워딩(외부 접속) 설정</h2>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="37" src="https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-1024x37.png" alt="" class="wp-image-2144" srcset="https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-1024x37.png 1024w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-300x11.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock05-768x28.png 768w, https://howinfo.kr/wp-content/uploads/2026/03/bedrock05.png 1427w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>이제 집 밖(모바일 데이터, 회사, 외부 PC)에서도 접속되게 하려면 공유기에서 포트를 열어야 합니다.</p>



<h3 class="wp-block-heading">6-1. 서버 PC 내부 IP 고정(권장)</h3>



<p>서버 PC의 내부 IP가 바뀌면 포트포워딩이 무용지물이 됩니다.</p>



<ul class="wp-block-list">
<li>ipTIME 관리자 페이지 접속(보통 <code>192.168.0.1</code>)</li>



<li><strong>DHCP 서버 설정 / 주소 예약</strong> 메뉴에서<br>서버 PC의 MAC 주소에 <code>192.168.0.15</code>처럼 고정 예약 권장</li>
</ul>



<h3 class="wp-block-heading">6-2. 포트포워딩 추가</h3>



<p>ipTIME 관리자 페이지 → <strong>NAT/라우터관리 → 포트포워드</strong></p>



<ul class="wp-block-list">
<li>프로토콜: <strong>UDP</strong></li>



<li>외부 포트: <strong>19132</strong></li>



<li>내부 IP: 서버 PC 내부 IP (예: <code>192.168.0.15</code>)</li>



<li>내부 포트: <strong>19132</strong></li>
</ul>



<p>저장 후 적용</p>



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



<h2 class="wp-block-heading">7) 집 밖(외부)에서 접속 확인</h2>



<h3 class="wp-block-heading">7-1. 공인 IP 확인</h3>



<p>서버 PC 또는 휴대폰에서 “내 IP” 검색(공인 IP 확인)<br>외부 접속 테스트 시 주소로 사용합니다.</p>



<h3 class="wp-block-heading">7-2. 안드로이드에서 모바일 데이터로 접속 테스트</h3>



<p>안드로이드에서 와이파이를 끄고(모바일 데이터로 전환) Minecraft → 서버 추가:</p>



<ul class="wp-block-list">
<li>서버 주소: <strong>공인 IP</strong></li>



<li>포트: <strong>19132</strong></li>
</ul>



<p>✅ 모바일 데이터에서 접속되면 외부 접속까지 성공입니다.</p>



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



<h2 class="wp-block-heading">8) 외부 접속이 안 될 때(가장 흔한 원인 3가지)</h2>



<ol class="wp-block-list">
<li><strong>UDP 포트포워딩을 TCP로 걸어둔 경우</strong>
<ul class="wp-block-list">
<li>베드락은 기본이 UDP입니다. 포워딩 프로토콜이 UDP인지 다시 확인하세요.</li>
</ul>
</li>



<li><strong>Windows 방화벽 규칙 누락</strong>
<ul class="wp-block-list">
<li>UDP 19132 인바운드가 실제로 허용됐는지 재확인</li>
</ul>
</li>



<li><strong>이중 NAT (KT 장비 + ipTIME)</strong>
<ul class="wp-block-list">
<li>KT 모뎀/공유기가 라우팅을 하고, ipTIME도 라우팅을 하면 “겹 NAT”가 생겨 외부 접속이 막히는 경우가 있습니다.</li>



<li>이때 해결 방법은 보통:
<ul class="wp-block-list">
<li>KT 장비를 <strong>브릿지 모드</strong>로 전환하거나</li>



<li>KT 장비에서 ipTIME을 <strong>DMZ</strong>로 지정하거나</li>



<li>ipTIME을 <strong>AP 모드</strong>로 전환(권장 시나리오에 따라 다름)</li>
</ul>
</li>
</ul>
</li>
</ol>



<p>외부 접속이 막히면, 집 네트워크 구조(“KT 장비가 따로 있는지”)부터 확인하는 게 제일 빠릅니다.</p>



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



<h2 class="wp-block-heading">9) 운영 팁(최소한만)</h2>



<ul class="wp-block-list">
<li>서버 재시작:</li>
</ul>



<pre class="wp-block-preformatted">docker restart mc-bedrock</pre>



<ul class="wp-block-list">
<li>서버 종료/시작:</li>
</ul>



<pre class="wp-block-preformatted">docker stop mc-bedrock<br>docker start mc-bedrock</pre>



<ul class="wp-block-list">
<li>데이터(월드/설정) 저장 위치:
<ul class="wp-block-list">
<li><code>D:\minecraft\bedrock\data\</code><br>이 폴더만 백업하면 됩니다(서버 중지 후 압축 권장).</li>
</ul>
</li>
</ul>



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



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



<p>정리하면, <strong>Windows 11에서 Docker로 BDS 운영</strong>은 아래 순서로 끝납니다.</p>



<ol class="wp-block-list">
<li>Docker Compose로 BDS 실행</li>



<li>Windows 방화벽 UDP 19132 허용</li>



<li>안드로이드(같은 와이파이) 접속 확인</li>



<li>ipTIME UDP 19132 포트포워딩</li>



<li>안드로이드(모바일 데이터)로 외부 접속 확인</li>
</ol>



<p>여기까지 되면 “서버가 실제로 운영 가능한 상태”입니다.</p>



<p></p>
<p>게시물 <a href="https://howinfo.kr/%eb%84%88%eb%ac%b4%eb%82%98-%ec%89%ac%ec%9a%b4-%ec%9c%88%eb%8f%84%ec%9a%b0%ec%a6%8811docker-%ec%9d%b4%ec%9a%a9-%eb%b2%a0%eb%93%9c%eb%9d%bd-%eb%a7%88%ec%9d%b8%ed%81%ac%eb%9e%98%ed%94%84%ed%8a%b8/">너무나 쉬운 윈도우즈11+docker 이용 베드락 마인크래프트 설치하고 외부에서 접근하여 게임즐기기</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%eb%84%88%eb%ac%b4%eb%82%98-%ec%89%ac%ec%9a%b4-%ec%9c%88%eb%8f%84%ec%9a%b0%ec%a6%8811docker-%ec%9d%b4%ec%9a%a9-%eb%b2%a0%eb%93%9c%eb%9d%bd-%eb%a7%88%ec%9d%b8%ed%81%ac%eb%9e%98%ed%94%84%ed%8a%b8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows 11 Pro Docker 설치 가이드 (WSL 2 백엔드) + 오류 해결</title>
		<link>https://howinfo.kr/windows-11-pro-docker-%ec%84%a4%ec%b9%98-%ea%b0%80%ec%9d%b4%eb%93%9c-wsl-2-%eb%b0%b1%ec%97%94%eb%93%9c-%ec%98%a4%eb%a5%98-%ed%95%b4%ea%b2%b0/</link>
					<comments>https://howinfo.kr/windows-11-pro-docker-%ec%84%a4%ec%b9%98-%ea%b0%80%ec%9d%b4%eb%93%9c-wsl-2-%eb%b0%b1%ec%97%94%eb%93%9c-%ec%98%a4%eb%a5%98-%ed%95%b4%ea%b2%b0/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Mon, 02 Mar 2026 09:10:34 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[Docker Desktop]]></category>
		<category><![CDATA[Hyper-V]]></category>
		<category><![CDATA[nas]]></category>
		<category><![CDATA[Window 11 pro]]></category>
		<category><![CDATA[WSL2]]></category>
		<category><![CDATA[개발환경]]></category>
		<category><![CDATA[나스]]></category>
		<category><![CDATA[도커]]></category>
		<category><![CDATA[미니스포럼 N5 PRO]]></category>
		<category><![CDATA[컨테이너]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2128</guid>

					<description><![CDATA[<p>NAS나 개발 서버를 운영하다 보면, 결국 Docker를 만나게 됩니다. 서비스 하나 올릴 때마다 “설치 → 설정 → 충돌”을 반복하는 대신,...</p>
<p>게시물 <a href="https://howinfo.kr/windows-11-pro-docker-%ec%84%a4%ec%b9%98-%ea%b0%80%ec%9d%b4%eb%93%9c-wsl-2-%eb%b0%b1%ec%97%94%eb%93%9c-%ec%98%a4%eb%a5%98-%ed%95%b4%ea%b2%b0/">Windows 11 Pro Docker 설치 가이드 (WSL 2 백엔드) + 오류 해결</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>NAS나 개발 서버를 운영하다 보면, 결국 <strong>Docker</strong>를 만나게 됩니다. 서비스 하나 올릴 때마다 “설치 → 설정 → 충돌”을 반복하는 대신, 컨테이너로 깔끔하게 분리해서 관리할 수 있으니까요.</p>



<p>저는 미니스포럼 N5 Pro 같은 <strong>저전력·고효율 미니PC</strong>를 홈서버/NAS 보조 서버로 쓰는 경우가 많은데, 이때 Windows 11 Pro에서 Docker를 가장 쾌적하게 돌리는 방식은 <strong>Docker Desktop + WSL 2 백엔드</strong> 조합이었습니다.</p>



<p>이 글은 <strong>초보자도 그대로 따라 하면 설치가 끝나는 흐름</strong>으로 정리했고, 실제로 많이 막히는 <strong>오류 해결</strong>까지 함께 넣었습니다. (붙여넣기용 완성본)</p>



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



<h2 class="wp-block-heading">1) 오늘 설치할 구성 (핵심 요약)</h2>



<ul class="wp-block-list">
<li>Windows 11 Pro</li>



<li>WSL 2 활성화</li>



<li>Docker Desktop 설치 (WSL 2 백엔드 사용)</li>



<li><code>docker run hello-world</code>로 최종 검증</li>



<li>오류 발생 시 체크 순서 제공</li>
</ul>



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



<h2 class="wp-block-heading">2) 사전 준비 체크 (여기서 80%가 결정됩니다)</h2>



<h3 class="wp-block-heading">(1) BIOS 가상화(VT-x/AMD-V) 활성화 확인</h3>



<p>WSL 2와 Docker는 가상화 기능에 의존합니다.</p>



<ul class="wp-block-list">
<li>BIOS 메뉴에서 아래 항목이 <strong>Enabled</strong>인지 확인
<ul class="wp-block-list">
<li>Intel Virtualization Technology (VT-x)</li>



<li>또는 SVM / AMD-V</li>
</ul>
</li>
</ul>



<p>✅ 증상 힌트</p>



<ul class="wp-block-list">
<li>가상화가 꺼져 있으면 WSL 설치가 되더라도 Docker가 정상 실행되지 않거나, WSL이 1로 떨어지는 경우가 있습니다.</li>
</ul>



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



<h3 class="wp-block-heading">(2) Windows 기능 켜기 (필수)</h3>



<p>시작 메뉴 → <strong>“Windows 기능 켜기/끄기”</strong> 검색 후 실행, 아래 항목을 체크합니다.</p>



<ul class="wp-block-list">
<li><strong>Linux용 Windows 하위 시스템</strong></li>



<li><strong>가상 머신 플랫폼</strong></li>



<li>(Pro라면 켜두면 좋은 편) <strong>Hyper-V</strong></li>
</ul>



<p>체크 후 [확인] → 재부팅</p>



<p>✅ 포인트</p>



<ul class="wp-block-list">
<li>WSL 2는 “가상 머신 플랫폼”이 꺼져 있으면 정상 동작이 어렵습니다.</li>



<li>Hyper-V는 WSL 2 백엔드에서도 환경에 따라 도움이 됩니다(특히 회사 PC/보안정책 환경).</li>
</ul>



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



<h2 class="wp-block-heading">3) WSL 2 설치 및 업데이트 (PowerShell 관리자)</h2>



<p>PowerShell을 <strong>관리자 권한</strong>으로 실행합니다.</p>



<h3 class="wp-block-heading">(1) WSL 설치/업데이트</h3>



<pre class="wp-block-preformatted">wsl --install<br>wsl --update</pre>



<h3 class="wp-block-heading">(2) WSL 기본 버전 2 고정</h3>



<pre class="wp-block-preformatted">wsl --set-default-version 2</pre>



<h3 class="wp-block-heading">(3) WSL 상태 확인(선택)</h3>



<pre class="wp-block-preformatted">wsl --status<br>wsl -l -v</pre>



<p>✅ 여기서 확인할 것</p>



<ul class="wp-block-list">
<li><code>wsl -l -v</code> 출력에서 배포판이 보이고, VERSION이 <strong>2</strong>인지 확인</li>
</ul>



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



<h2 class="wp-block-heading">4) 리눅스 배포판(Ubuntu) 설치 (없으면 반드시)</h2>



<p><code>wsl -l -v</code>에서 배포판이 하나도 없다면 Ubuntu를 설치합니다.</p>



<pre class="wp-block-preformatted">wsl --install -d Ubuntu</pre>



<p>설치 후 Ubuntu를 한 번 실행하면 <strong>Linux 사용자 이름/비밀번호</strong>를 설정하는 단계가 나옵니다.<br>(비밀번호는 입력해도 화면에 안 보이는 게 정상입니다)</p>



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



<h2 class="wp-block-heading">5) Docker Desktop 설치 (WSL 2 백엔드로)</h2>



<h3 class="wp-block-heading">(1) 설치 파일 실행</h3>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="705" height="499" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_003.png" alt="" class="wp-image-2131" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_003.png 705w, https://howinfo.kr/wp-content/uploads/2026/03/docker_003-300x212.png 300w" sizes="auto, (max-width: 705px) 100vw, 705px" /></figure>



<p>Docker Desktop Installer.exe 실행</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="729" height="501" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_002.png" alt="" class="wp-image-2130" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_002.png 729w, https://howinfo.kr/wp-content/uploads/2026/03/docker_002-300x206.png 300w" sizes="auto, (max-width: 729px) 100vw, 729px" /></figure>



<h3 class="wp-block-heading">(2) 설치 중 가장 중요한 옵션</h3>



<p>설치 과정에서 아래 옵션이 나오면 <strong>반드시 체크된 상태</strong>로 진행합니다.</p>



<ul class="wp-block-list">
<li>✅ <strong>Use WSL 2 instead of Hyper-V (recommended)</strong></li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="591" height="436" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_001.png" alt="" class="wp-image-2129" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_001.png 591w, https://howinfo.kr/wp-content/uploads/2026/03/docker_001-300x221.png 300w" sizes="auto, (max-width: 591px) 100vw, 591px" /></figure>



<h3 class="wp-block-heading">(3) 설치 완료 후 재부팅</h3>



<p>설치가 끝나면 <strong>Close and restart</strong>로 재부팅합니다.</p>



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



<h2 class="wp-block-heading">6) Docker Desktop 설정 확인 (WSL 통합)</h2>



<p>재부팅 후 Docker Desktop 실행 → Settings에서 확인합니다.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="803" height="512" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_005.png" alt="" class="wp-image-2133" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_005.png 803w, https://howinfo.kr/wp-content/uploads/2026/03/docker_005-300x191.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/docker_005-768x490.png 768w" sizes="auto, (max-width: 803px) 100vw, 803px" /></figure>



<ul class="wp-block-list">
<li><strong>Settings → Resources → WSL Integration</strong>
<ul class="wp-block-list">
<li>Ubuntu(또는 설치한 배포판)에 대해</li>



<li>✅ <strong>Enable integration</strong> 켬</li>
</ul>
</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="686" height="670" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_006.png" alt="" class="wp-image-2134" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_006.png 686w, https://howinfo.kr/wp-content/uploads/2026/03/docker_006-300x293.png 300w" sizes="auto, (max-width: 686px) 100vw, 686px" /></figure>



<p>✅ 추천</p>



<ul class="wp-block-list">
<li>배포판이 여러 개라면, 실제 사용할 배포판 하나만 통합 켜두는 게 관리가 편합니다.</li>
</ul>



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



<h2 class="wp-block-heading">7) 설치 확인 테스트 (여기까지 오면 끝)</h2>



<p>PowerShell 또는 Windows Terminal에서 실행합니다.</p>



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



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



<h3 class="wp-block-heading">(2) hello-world 테스트</h3>



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



<p>아래 문구가 나오면 성공입니다.</p>



<ul class="wp-block-list">
<li><code>Hello from Docker!</code></li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="573" src="https://howinfo.kr/wp-content/uploads/2026/03/docker_007-1024x573.png" alt="" class="wp-image-2135" srcset="https://howinfo.kr/wp-content/uploads/2026/03/docker_007-1024x573.png 1024w, https://howinfo.kr/wp-content/uploads/2026/03/docker_007-300x168.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/docker_007-768x430.png 768w, https://howinfo.kr/wp-content/uploads/2026/03/docker_007.png 1266w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



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



<h1 class="wp-block-heading">8) 오류 해결 모음 (실제로 제일 많이 막히는 구간)</h1>



<p>아래는 “증상 → 원인 → 해결” 순서로 정리했습니다.</p>



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



<h2 class="wp-block-heading">오류 1) <code>docker</code> 명령어가 인식되지 않음</h2>



<p><strong>증상</strong></p>



<ul class="wp-block-list">
<li><code>docker : The term 'docker' is not recognized...</code></li>
</ul>



<p><strong>원인</strong></p>



<ul class="wp-block-list">
<li>Docker Desktop 설치가 안 되었거나, 재부팅 전 상태이거나, PATH 적용이 안 된 케이스</li>
</ul>



<p><strong>해결</strong></p>



<ol class="wp-block-list">
<li>Docker Desktop이 설치되어 있는지 확인</li>



<li>재부팅 1회</li>



<li>그래도 안 되면 Docker Desktop 재설치</li>
</ol>



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



<h2 class="wp-block-heading">오류 2) <code>WSL 2 installation is incomplete</code></h2>



<p><strong>증상</strong></p>



<ul class="wp-block-list">
<li>Docker Desktop 실행 시 WSL 2 커널 관련 경고</li>
</ul>



<p><strong>원인</strong></p>



<ul class="wp-block-list">
<li>WSL 업데이트/Windows 업데이트 미반영 또는 재부팅 누락</li>
</ul>



<p><strong>해결</strong></p>



<ol class="wp-block-list">
<li>PowerShell(관리자) 실행</li>
</ol>



<pre class="wp-block-preformatted">wsl --update</pre>



<ol start="2" class="wp-block-list">
<li>재부팅</li>



<li>Windows Update 최신 상태 확인(선택)</li>
</ol>



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



<h2 class="wp-block-heading">오류 3) <code>wsl -l -v</code>에서 VERSION이 1로 뜸</h2>



<p><strong>원인</strong></p>



<ul class="wp-block-list">
<li>기본 버전이 2로 고정되지 않았거나, 배포판이 1로 생성된 상태</li>
</ul>



<p><strong>해결</strong></p>



<pre class="wp-block-preformatted">wsl --set-default-version 2<br>wsl --set-version Ubuntu 2</pre>



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



<h2 class="wp-block-heading">오류 4) <code>0x80370102</code> / “가상 머신 플랫폼” 관련 오류</h2>



<p><strong>증상</strong></p>



<ul class="wp-block-list">
<li>WSL 실행/설치 중 가상화 관련 오류 코드 발생</li>
</ul>



<p><strong>원인</strong></p>



<ul class="wp-block-list">
<li>BIOS 가상화 꺼짐, Windows 기능 미활성화, 보안 기능 충돌</li>
</ul>



<p><strong>해결 체크 순서</strong></p>



<ol class="wp-block-list">
<li>BIOS VT-x/AMD-V Enabled</li>



<li>Windows 기능: Linux용 Windows 하위 시스템 / 가상 머신 플랫폼 체크</li>



<li>재부팅</li>



<li>PowerShell 관리자에서 <code>wsl --update</code></li>
</ol>



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



<h2 class="wp-block-heading">오류 5) <code>docker run hello-world</code>가 다운로드에서 멈춤</h2>



<p><strong>원인</strong></p>



<ul class="wp-block-list">
<li>회사망/프록시/방화벽/DNS 이슈가 흔함</li>
</ul>



<p><strong>해결</strong></p>



<ul class="wp-block-list">
<li>집 인터넷/모바일 핫스팟에서 한 번 테스트</li>



<li>Docker Desktop의 네트워크/프록시 설정 확인</li>



<li>회사 PC라면 보안 정책상 Docker 허용 여부 확인 필요</li>
</ul>



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



<h2 class="wp-block-heading">오류 6) Docker Desktop이 “Starting…”에서 멈춤</h2>



<p><strong>원인</strong></p>



<ul class="wp-block-list">
<li>WSL 통합 문제, 배포판 손상, 업데이트 충돌</li>
</ul>



<p><strong>해결(가벼운 순서)</strong></p>



<ol class="wp-block-list">
<li>Docker Desktop 종료 후 재실행</li>



<li>재부팅</li>



<li>PowerShell 관리자:</li>
</ol>



<pre class="wp-block-preformatted">wsl --shutdown</pre>



<ol start="4" class="wp-block-list">
<li>Docker Desktop 다시 실행</li>



<li>그래도 안 되면 WSL 배포판 재설치 고려(마지막 수단)</li>
</ol>



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



<h1 class="wp-block-heading">9) 설치 후 추천: 홈서버/NAS 운영에 바로 쓰는 기본 명령어</h1>



<p>컨테이너 목록 보기</p>



<pre class="wp-block-preformatted">docker ps<br>docker ps -a</pre>



<p>이미지 목록 보기</p>



<pre class="wp-block-preformatted">docker images</pre>



<p>컨테이너 중지/삭제</p>



<pre class="wp-block-preformatted">docker stop &lt;컨테이너ID&gt;<br>docker rm &lt;컨테이너ID&gt;</pre>



<p>이미지 삭제</p>



<pre class="wp-block-preformatted">docker rmi &lt;이미지ID&gt;</pre>



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



<h1 class="wp-block-heading">10) 마무리 (제가 이 구성을 추천하는 이유)</h1>



<p>Windows 11 Pro에서 Docker를 운영할 때, Hyper-V 기반으로도 가능하지만<br>실사용(특히 미니PC/홈서버)에서는 <strong>WSL 2 백엔드가 설치·유지보수 난이도가 낮고 안정적인 편</strong>이었습니다.</p>



<ul class="wp-block-list">
<li>개발 환경(리눅스 도구)도 WSL에서 자연스럽게 이어지고</li>



<li>컨테이너 운영도 Docker Desktop에서 시각적으로 관리 가능해서</li>



<li>“홈서버 운영 + 개발” 둘 다 잡기 좋았습니다.</li>
</ul>



<p></p>
<p>게시물 <a href="https://howinfo.kr/windows-11-pro-docker-%ec%84%a4%ec%b9%98-%ea%b0%80%ec%9d%b4%eb%93%9c-wsl-2-%eb%b0%b1%ec%97%94%eb%93%9c-%ec%98%a4%eb%a5%98-%ed%95%b4%ea%b2%b0/">Windows 11 Pro Docker 설치 가이드 (WSL 2 백엔드) + 오류 해결</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/windows-11-pro-docker-%ec%84%a4%ec%b9%98-%ea%b0%80%ec%9d%b4%eb%93%9c-wsl-2-%eb%b0%b1%ec%97%94%eb%93%9c-%ec%98%a4%eb%a5%98-%ed%95%b4%ea%b2%b0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[리뷰/팁] 미니스포럼 N5 Pro NAS 구축기: 윈도우 11에서 WOL 완벽 설정하기 (BIOS + Windows + ipTIME 외부 WOL까지)</title>
		<link>https://howinfo.kr/%eb%a6%ac%eb%b7%b0-%ed%8c%81-%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-nas-%ea%b5%ac%ec%b6%95%ea%b8%b0-%ec%9c%88%eb%8f%84%ec%9a%b0-11%ec%97%90%ec%84%9c-wol-%ec%99%84%eb%b2%bd-%ec%84%a4/</link>
					<comments>https://howinfo.kr/%eb%a6%ac%eb%b7%b0-%ed%8c%81-%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-nas-%ea%b5%ac%ec%b6%95%ea%b8%b0-%ec%9c%88%eb%8f%84%ec%9a%b0-11%ec%97%90%ec%84%9c-wol-%ec%99%84%eb%b2%bd-%ec%84%a4/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Mon, 02 Mar 2026 02:13:25 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[bios]]></category>
		<category><![CDATA[ddns]]></category>
		<category><![CDATA[erp]]></category>
		<category><![CDATA[minisforum]]></category>
		<category><![CDATA[n5 pro]]></category>
		<category><![CDATA[nas]]></category>
		<category><![CDATA[wake on lan]]></category>
		<category><![CDATA[window 11]]></category>
		<category><![CDATA[wol]]></category>
		<category><![CDATA[원격관리]]></category>
		<category><![CDATA[원격부팅]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2124</guid>

					<description><![CDATA[<p>안녕하세요!오늘은 미니스포럼(Minisforum) N5 Pro를 윈도우 11 기반 NAS(홈서버)로 쓰는 분들을 위해, 제가 실제로 시행착오 끝에 성공한 WOL(Wake-on-LAN, 원격부팅) 설정을 한...</p>
<p>게시물 <a href="https://howinfo.kr/%eb%a6%ac%eb%b7%b0-%ed%8c%81-%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-nas-%ea%b5%ac%ec%b6%95%ea%b8%b0-%ec%9c%88%eb%8f%84%ec%9a%b0-11%ec%97%90%ec%84%9c-wol-%ec%99%84%eb%b2%bd-%ec%84%a4/">[리뷰/팁] 미니스포럼 N5 Pro NAS 구축기: 윈도우 11에서 WOL 완벽 설정하기 (BIOS + Windows + ipTIME 외부 WOL까지)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>안녕하세요!<br>오늘은 <strong>미니스포럼(Minisforum) N5 Pro</strong>를 윈도우 11 기반 NAS(홈서버)로 쓰는 분들을 위해, 제가 실제로 시행착오 끝에 성공한 <strong>WOL(Wake-on-LAN, 원격부팅) 설정</strong>을 한 번에 정리해드립니다.</p>



<p>NAS는 결국 “필요할 때만 켜서 쓰고, 평소엔 꺼두는” 운영이 핵심이죠.<br>그런데 <strong>윈도우 11 Pro 설치 후 기본 설정만으로는 WOL이 안 되는 경우가 정말 많습니다.</strong><br>저도 “다 설정했는데 왜 안 켜지지?”를 반복하다가, 결론적으로 아래 2개가 핵심 원인이었습니다.</p>



<ul class="wp-block-list">
<li><strong>BIOS의 ErP Ready</strong></li>



<li><strong>윈도우의 빠른 시작(Fast Startup)</strong></li>
</ul>



<p>게다가 외부에서 깨우려면 <strong>ipTIME 공유기 설정</strong>까지 연결되어야 완성됩니다.<br>이 글 하나로 **BIOS → Windows → ipTIME(외부 WOL)**까지 끝낼 수 있게 구성해볼게요.</p>



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



<h2 class="wp-block-heading">요약</h2>



<ol class="wp-block-list">
<li>BIOS에서 <strong>ErP Ready = Disabled</strong>, <strong>Wake on PCI-E = Enabled</strong></li>



<li>Windows에서 랜카드 <strong>Wake on Magic Packet = Enabled</strong>, 전원관리에서 <strong>매직 패킷만 허용</strong></li>



<li>Windows 전원 옵션에서 <strong>‘빠른 시작 켜기’ 해제</strong></li>



<li>ipTIME은 **WOL 기능 + DDNS(원격 접속)**로 외부에서도 깨우기</li>
</ol>



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



<h2 class="wp-block-heading">1. WOL이 안 되는 대표 증상 (제가 겪었던 것들)</h2>



<p>아래 중 하나라도 해당되면, 거의 확실히 이 글의 설정이 필요합니다.</p>



<ul class="wp-block-list">
<li>절전(Sleep)에서는 깨우는데 <strong>종료(Shut down) 후에는 WOL이 안 됨</strong></li>



<li>종료 후 랜포트 LED가 꺼지거나 링크가 사라짐</li>



<li>같은 집(내부망)에서는 되는데 <strong>외부(LTE/회사)에서는 안 됨</strong></li>



<li>어떤 날은 되고 어떤 날은 안 됨 (대개 빠른 시작/드라이버 전원정책 영향)</li>
</ul>



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



<h2 class="wp-block-heading">2. BIOS 설정 (전원 꺼져도 랜카드가 살아있게 만들기)</h2>



<p>목표는 딱 하나입니다.<br><strong>PC가 꺼져 있어도(Soft Off) 랜카드가 전원을 유지하고 매직패킷을 받을 수 있게 하는 것.</strong></p>



<h3 class="wp-block-heading">2-1) BIOS 진입</h3>



<ul class="wp-block-list">
<li>부팅 시 <strong>Del 키 연타</strong></li>
</ul>



<h3 class="wp-block-heading">2-2) ErP Ready 비활성화 (가장 중요)</h3>



<ul class="wp-block-list">
<li><code>Advanced</code> → <code>ACPI Settings</code></li>



<li><strong>ErP Ready = Disabled</strong></li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>ErP가 켜져 있으면 대기전력을 줄이려고 <strong>랜카드 전원까지 차단</strong>하는 경우가 많습니다.<br>이 상태에서는 WOL 신호가 와도 받을 수가 없습니다.</p>
</blockquote>



<h3 class="wp-block-heading">2-3) WOL 활성화 (PCI-E Wake)</h3>



<p>아래 중 하나로 보이는 항목을 찾아 켭니다(보드/BIOS마다 명칭이 조금 다름).</p>



<ul class="wp-block-list">
<li><code>Wake configuration</code></li>



<li><code>Resume By PCI-E Device</code></li>



<li><code>Wake on PCI-E</code></li>



<li><code>Wake on LAN</code></li>
</ul>



<p>→ 해당 항목을 <strong>Enabled</strong></p>



<h3 class="wp-block-heading">2-4) 저장 후 재부팅</h3>



<ul class="wp-block-list">
<li><strong>F10 → Save &amp; Exit</strong></li>
</ul>



<p>✅ <strong>BIOS 체크포인트(매우 유용)</strong><br>PC를 “종료”한 뒤, <strong>랜포트 LED가 살아있는지</strong> 보세요.<br>LED가 완전히 꺼진다면 ErP나 전원 항목이 아직 막고 있을 가능성이 큽니다.</p>



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



<h2 class="wp-block-heading">3. Windows 11에서 네트워크 어댑터 WOL 설정</h2>



<p>BIOS가 준비되었으면, 이제 Windows가 랜카드를 “깨울 수 있는 장치”로 허용해야 합니다.</p>



<h3 class="wp-block-heading">3-1) 장치 관리자 열기</h3>



<ul class="wp-block-list">
<li>시작 버튼 우클릭 → <strong>장치 관리자</strong></li>



<li><strong>네트워크 어댑터</strong> 펼치기</li>



<li>사용 중인 유선 어댑터(예: <code>Realtek PCIe 2.5GbE</code>) 우클릭 → <strong>속성</strong></li>
</ul>



<h3 class="wp-block-heading">3-2) [고급] 탭 설정</h3>



<ul class="wp-block-list">
<li><strong>Wake on Magic Packet = Enabled</strong></li>



<li>(있다면) <strong>Shutdown Wake-On-LAN = Enabled</strong></li>



<li>(있다면) <strong>Wake on pattern match = Disabled</strong> 권장<br>→ 원치 않는 트래픽에 혼자 켜지는 현상을 줄여줍니다.</li>
</ul>



<h3 class="wp-block-heading">3-3) [전원 관리] 탭 설정</h3>



<p>아래 두 개는 거의 필수입니다.</p>



<ul class="wp-block-list">
<li>✅ “이 장치를 사용하여 컴퓨터의 대기 모드를 종료할 수 있음” 체크</li>



<li>✅ “매직 패킷에서만 컴퓨터의 대기 모드를 종료할 수 있음” 체크</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>두 번째 체크가 없으면, 네트워크 브로드캐스트/스캔 패킷에 의해 의도치 않게 켜질 수 있습니다.</p>
</blockquote>



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



<h2 class="wp-block-heading">4. 결정타: ‘빠른 시작(Fast Startup)’ 끄기</h2>



<p>윈도우 10/11의 <strong>빠른 시작</strong>은 종료를 완전 종료가 아니라 “하이브리드 종료”처럼 만들어서,<br>환경에 따라 <strong>종료 후 WOL이 무시되는 경우</strong>가 꽤 많습니다.</p>



<h3 class="wp-block-heading">4-1) 빠른 시작 해제 경로</h3>



<ul class="wp-block-list">
<li>제어판 → <strong>하드웨어 및 소리</strong> → <strong>전원 옵션</strong></li>



<li>좌측 <strong>전원 단추 작동 설정</strong></li>



<li>상단 <strong>‘현재 사용할 수 없는 설정 변경’</strong> 클릭</li>



<li>하단 <strong>[빠른 시작 켜기(권장)] 체크 해제</strong></li>



<li>저장</li>
</ul>



<p>✅ <strong>실전 팁</strong><br>“절전은 되는데 종료는 안 됨”이면, 이 단계가 진짜 마지막 퍼즐일 가능성이 큽니다.</p>



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



<h2 class="wp-block-heading">5. 내부망(집 안)에서 먼저 WOL 테스트하기</h2>



<p>외부 WOL로 바로 가지 말고, 먼저 집 안에서 성공시키는 게 순서입니다.</p>



<ul class="wp-block-list">
<li>스마트폰 WOL 앱 또는 PC 도구로 <strong>같은 와이파이/내부망에서</strong> 매직패킷 전송</li>



<li>N5 Pro가 켜지면 → Windows/BIOS는 성공</li>



<li>안 켜지면 → 2~4단계를 다시 점검</li>
</ul>



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



<h1 class="wp-block-heading">6. ipTIME 공유기에서 외부 WOL 완성하기 (진짜 NAS 운영의 핵심)</h1>



<p>이제 핵심입니다.<br>집 안에서는 되었는데 <strong>외부에서 안 된다</strong>면, 대부분 ipTIME에서 아래 이슈 때문입니다.</p>



<ul class="wp-block-list">
<li>PC가 꺼지면 공유기 ARP 테이블에서 MAC↔IP 정보가 사라짐</li>



<li>외부에서 들어온 매직패킷이 내부 브로드캐스트로 전달되지 않음</li>
</ul>



<p>그래서 ipTIME 환경에서는 가장 안정적으로 <strong>“공유기의 WOL 기능”을 쓰는 방식</strong>을 추천합니다.</p>



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



<h2 class="wp-block-heading">6-1) 사전 준비: 고정 IP + MAC 주소 확보</h2>



<p>외부 WOL은 “고정 IP”가 거의 필수입니다.</p>



<h3 class="wp-block-heading">① MAC 주소 확인</h3>



<ul class="wp-block-list">
<li><code>cmd</code> 실행 → <code>ipconfig /all</code></li>



<li>“물리적 주소(Physical Address)” 확인<br>예: <code>AA-BB-CC-DD-EE-FF</code></li>
</ul>



<h3 class="wp-block-heading">② ipTIME에서 DHCP 고정할당(권장)</h3>



<ul class="wp-block-list">
<li>관리자 페이지 접속: <code>192.168.0.1</code></li>



<li>메뉴 예시: <code>고급 설정 → 네트워크 관리 → 내부 네트워크 설정(DHCP 서버)</code></li>



<li><strong>DHCP 고정할당 / IP-MAC 바인딩</strong> 메뉴에서<br>N5 Pro MAC 주소 등록 + 고정 IP(예: <code>192.168.0.15</code>) 지정</li>
</ul>



<p>✅ 이걸 해두면 WOL 목록 등록/ARP 유지가 훨씬 안정적입니다.</p>



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



<h2 class="wp-block-heading">6-2) ipTIME WOL 기능으로 내부 WOL 등록</h2>



<ul class="wp-block-list">
<li><code>192.168.0.1</code> 접속 후 로그인</li>



<li>WOL 메뉴(펌웨어/모델에 따라 다름)
<ul class="wp-block-list">
<li><code>고급 설정 → 특수 기능 → WOL</code></li>



<li>또는 <code>시스템 관리 → 기타 설정 → WOL</code></li>
</ul>
</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="989" height="584" src="https://howinfo.kr/wp-content/uploads/2026/03/wol.png" alt="" class="wp-image-2125" srcset="https://howinfo.kr/wp-content/uploads/2026/03/wol.png 989w, https://howinfo.kr/wp-content/uploads/2026/03/wol-300x177.png 300w, https://howinfo.kr/wp-content/uploads/2026/03/wol-768x454.png 768w" sizes="auto, (max-width: 989px) 100vw, 989px" /></figure>



<h3 class="wp-block-heading">WOL 목록에 N5 Pro 등록</h3>



<ul class="wp-block-list">
<li>장치 이름: <code>N5Pro-NAS</code></li>



<li>MAC 주소: 위에서 확인한 값 입력</li>



<li>(필요 시) IP 주소도 함께 입력</li>



<li>저장</li>
</ul>



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



<h2 class="wp-block-heading">6-3) 외부에서 깨우는 방법 1 (가장 단순): ipTIME DDNS + 원격 접속 후 WOL 버튼</h2>



<p>ipTIME 공유기 관리페이지에 외부에서 들어가서 “WOL 버튼”을 누르는 방식입니다.<br>구성이 단순하고 성공률도 높습니다.</p>



<h3 class="wp-block-heading">① ipTIME DDNS 설정</h3>



<ul class="wp-block-list">
<li><code>고급 설정 → 특수 기능 → DDNS 설정</code></li>



<li>ipTIME 계정으로 DDNS 도메인 생성<br>예: <code>myhome.iptime.org</code></li>
</ul>



<h3 class="wp-block-heading">② 원격관리(외부 접속) 설정</h3>



<ul class="wp-block-list">
<li><code>고급 설정 → 시스템 관리 → 원격 관리(또는 웹 관리)</code></li>



<li>원격 관리 활성화</li>



<li><strong>관리 포트는 꼭 변경</strong>(보안상 매우 중요)<br>예: <code>8443</code> 같은 값으로 변경</li>
</ul>



<h3 class="wp-block-heading">③ 외부에서 접속해서 WOL 실행</h3>



<ul class="wp-block-list">
<li>외부(모바일 LTE)에서 브라우저로 접속<br><code>myhome.iptime.org:8443</code></li>



<li>로그인 → WOL 메뉴 → <code>N5Pro-NAS</code> 깨우기 실행</li>
</ul>



<p>✅ 장점</p>



<ul class="wp-block-list">
<li>복잡한 브로드캐스트/포트포워딩보다 성공률 높음</li>



<li>공유기가 내부로 매직패킷을 뿌려주므로 안정적</li>
</ul>



<p>⚠️ 보안 팁(꼭!)</p>



<ul class="wp-block-list">
<li>관리자 비번 강하게</li>



<li>원격관리 포트 변경 필수</li>



<li>가능하면 원격관리 허용 IP 제한(기능이 있다면) 사용 권장</li>
</ul>



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



<h2 class="wp-block-heading">6-4) 외부에서 깨우는 방법 2 (실전 최강 안정성): 내부 “대리 송신기” 구성</h2>



<p>저는 개인적으로 이 방식이 가장 마음 편했습니다.</p>



<ul class="wp-block-list">
<li>집에 항상 켜져 있는 장치(시놀로지/오렌지파이/라즈베리파이)가 있다면</li>



<li>외부에서 그 장치로 접속(SSH/VPN) → 내부에서 WOL 송신</li>
</ul>



<p>✅ 장점</p>



<ul class="wp-block-list">
<li>공유기 브로드캐스트/ARP 문제를 대부분 회피</li>



<li>공유기 원격관리 포트를 외부에 열지 않아도 되는 경우가 많아 보안도 좋음</li>
</ul>



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



<h2 class="wp-block-heading">7. 최종 점검 체크리스트 (이대로만 하면 됩니다)</h2>



<h3 class="wp-block-heading">BIOS</h3>



<ul class="wp-block-list">
<li>ErP Ready = <strong>Disabled</strong></li>



<li>Wake on LAN / Resume by PCI-E = <strong>Enabled</strong></li>



<li>종료 후 랜포트 LED가 살아있음</li>
</ul>



<h3 class="wp-block-heading">Windows (장치 관리자)</h3>



<ul class="wp-block-list">
<li>Wake on Magic Packet = <strong>Enabled</strong></li>



<li>(있으면) Shutdown WOL = <strong>Enabled</strong></li>



<li>전원 관리: “장치로 깨우기” 체크</li>



<li>전원 관리: “매직 패킷만” 체크</li>
</ul>



<h3 class="wp-block-heading">Windows (전원 옵션)</h3>



<ul class="wp-block-list">
<li><strong>빠른 시작 끔</strong></li>
</ul>



<h3 class="wp-block-heading">ipTIME(외부 WOL)</h3>



<ul class="wp-block-list">
<li>DHCP 고정할당으로 내부 IP 고정</li>



<li>ipTIME WOL 목록에 MAC 등록</li>



<li>(선택) DDNS + 원격관리 포트 변경 후 외부에서 WOL 실행<br>또는</li>



<li>(강추) 내부 대리 송신기(홈서버/나스/라즈베리파이) 구성</li>
</ul>



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



<h2 class="wp-block-heading">8. 자주 묻는 질문(FAQ)</h2>



<h3 class="wp-block-heading">Q1. 절전에서는 되는데 종료에서는 안 돼요.</h3>



<ul class="wp-block-list">
<li>빠른 시작이 켜져 있거나</li>



<li>드라이버에서 Shutdown WOL이 꺼져 있거나</li>



<li>BIOS ErP가 켜져 있을 가능성이 큽니다.<br>→ 이 글의 2~4장 순서대로 다시 체크하세요.</li>
</ul>



<h3 class="wp-block-heading">Q2. 집에서는 되는데 밖에서는 안 돼요.</h3>



<ul class="wp-block-list">
<li>공유기의 ARP/브로드캐스트 이슈일 가능성이 큽니다.<br>→ ipTIME <strong>WOL 기능 + DDNS 원격 접속 방식</strong>을 쓰면 성공률이 올라갑니다.<br>→ 가장 안정적인 건 “내부 대리 송신기” 방식입니다.</li>
</ul>



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



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



<p>미니스포럼 N5 Pro를 NAS로 운영할 때, WOL이 잡히면 운영 난이도가 확 내려갑니다.<br><strong>필요할 때만 깨워서 쓰고 다시 끄는</strong> 패턴이 가능해지니까요.</p>



<p>핵심은 한 줄입니다.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>ErP 끄고, 빠른 시작 끄고, ipTIME WOL로 외부에서도 깨우기.</strong></p>



<p></p>
</blockquote>
<p>게시물 <a href="https://howinfo.kr/%eb%a6%ac%eb%b7%b0-%ed%8c%81-%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-nas-%ea%b5%ac%ec%b6%95%ea%b8%b0-%ec%9c%88%eb%8f%84%ec%9a%b0-11%ec%97%90%ec%84%9c-wol-%ec%99%84%eb%b2%bd-%ec%84%a4/">[리뷰/팁] 미니스포럼 N5 Pro NAS 구축기: 윈도우 11에서 WOL 완벽 설정하기 (BIOS + Windows + ipTIME 외부 WOL까지)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%eb%a6%ac%eb%b7%b0-%ed%8c%81-%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-nas-%ea%b5%ac%ec%b6%95%ea%b8%b0-%ec%9c%88%eb%8f%84%ec%9a%b0-11%ec%97%90%ec%84%9c-wol-%ec%99%84%eb%b2%bd-%ec%84%a4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>미니스포럼 N5 Pro 언박싱부터 OS 설치까지: 집 NAS 세팅 실전기</title>
		<link>https://howinfo.kr/%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-%ec%96%b8%eb%b0%95%ec%8b%b1%eb%b6%80%ed%84%b0-os-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ec%a7%91-nas-%ec%84%b8%ed%8c%85-%ec%8b%a4%ec%a0%84%ea%b8%b0/</link>
					<comments>https://howinfo.kr/%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-%ec%96%b8%eb%b0%95%ec%8b%b1%eb%b6%80%ed%84%b0-os-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ec%a7%91-nas-%ec%84%b8%ed%8c%85-%ec%8b%a4%ec%a0%84%ea%b8%b0/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Sat, 28 Feb 2026 11:19:19 +0000</pubDate>
				<category><![CDATA[서버·인프라]]></category>
		<category><![CDATA[MinisCloud OS]]></category>
		<category><![CDATA[n5 pro]]></category>
		<category><![CDATA[nas]]></category>
		<category><![CDATA[OS설치]]></category>
		<category><![CDATA[SSD 장착]]></category>
		<category><![CDATA[메모리 장착]]></category>
		<category><![CDATA[미니스포럼]]></category>
		<category><![CDATA[언박싱]]></category>
		<category><![CDATA[초기 세팅]]></category>
		<category><![CDATA[홈서버]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2111</guid>

					<description><![CDATA[<p>오늘 미니스포럼 N5 Pro가 드디어 도착했습니다. ^^그런데… 저는 첫날부터 한 번 크게 삽질을 시작합니다.**SSD 128GB / 메모리 16GB가 ‘같이 왔는데...</p>
<p>게시물 <a href="https://howinfo.kr/%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-%ec%96%b8%eb%b0%95%ec%8b%b1%eb%b6%80%ed%84%b0-os-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ec%a7%91-nas-%ec%84%b8%ed%8c%85-%ec%8b%a4%ec%a0%84%ea%b8%b0/">미니스포럼 N5 Pro 언박싱부터 OS 설치까지: 집 NAS 세팅 실전기</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>오늘 <strong>미니스포럼 N5 Pro</strong>가 드디어 도착했습니다. ^^<br>그런데… 저는 첫날부터 한 번 크게 삽질을 시작합니다.<br>**SSD 128GB / 메모리 16GB가 ‘같이 왔는데 어디를 봐도 없더라구요 그런데 본체에 탑재 되어 있음 , OS가 설치되어 있을 줄 알고 전원을 넣었다가 <strong>부팅이 안 되는 상황</strong>을 겪었습니다. 이게 뭘까나 . <br>결국 제조사 안내와 <strong>MinisCloud OS Installation step(PDF)</strong> 문서를 참고해 <strong>OS를 새로 설치</strong>하고 나서야 정상 부팅에 성공했어요.</p>
</blockquote>



<p>이 글은 저처럼 “처음 받자마자 바로 쓰려다 막히는” 분들을 위해, <strong>언박싱 → SSD/메모리 장착 → OS 설치(재설치) → 첫 세팅</strong>까지 한 번에 정리한 실전 기록입니다.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="440" height="464" src="https://howinfo.kr/wp-content/uploads/2026/02/m07.png" alt="" class="wp-image-2113" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m07.png 440w, https://howinfo.kr/wp-content/uploads/2026/02/m07-284x300.png 284w" sizes="auto, (max-width: 440px) 100vw, 440px" /></figure>



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



<h2 class="wp-block-heading">1) 언박싱: 사진 몇장 올립니다. </h2>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="510" height="610" src="https://howinfo.kr/wp-content/uploads/2026/02/m08.png" alt="" class="wp-image-2114" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m08.png 510w, https://howinfo.kr/wp-content/uploads/2026/02/m08-251x300.png 251w" sizes="auto, (max-width: 510px) 100vw, 510px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="319" height="491" src="https://howinfo.kr/wp-content/uploads/2026/02/m01.png" alt="" class="wp-image-2115" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m01.png 319w, https://howinfo.kr/wp-content/uploads/2026/02/m01-195x300.png 195w" sizes="auto, (max-width: 319px) 100vw, 319px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="547" src="https://howinfo.kr/wp-content/uploads/2026/02/m02-1024x547.png" alt="" class="wp-image-2116" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m02-1024x547.png 1024w, https://howinfo.kr/wp-content/uploads/2026/02/m02-300x160.png 300w, https://howinfo.kr/wp-content/uploads/2026/02/m02-768x410.png 768w, https://howinfo.kr/wp-content/uploads/2026/02/m02.png 1038w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



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



<h2 class="wp-block-heading">2) 첫날 멘붕 포인트: “동봉 = 탑재 = OS 설치”가 아니었다</h2>



<div data-wp-interactive="core/file" class="wp-block-file"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://howinfo.kr/wp-content/uploads/2026/02/MinisCloudOSInstallationstep.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="MinisCloud+OS+Installation+step의 삽입."></object><a id="wp-block-file--media-836a2fc2-e1f5-4f07-8edd-e5a87a244eaf" href="https://howinfo.kr/wp-content/uploads/2026/02/MinisCloudOSInstallationstep.pdf">MinisCloud+OS+Installation+step</a><a href="https://howinfo.kr/wp-content/uploads/2026/02/MinisCloudOSInstallationstep.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-836a2fc2-e1f5-4f07-8edd-e5a87a244eaf">다운로드</a></div>



<p>제가 실수한 흐름은 이랬습니다.</p>



<ul class="wp-block-list">
<li>SSD 128GB / RAM 16GB가 같이 왔음 </li>



<li>당연히 본체에 장착돼 있고, OS도 설치돼 있을 줄 알고 전원 ON</li>



<li>결과: <strong>부팅 불가(또는 OS 진입 불가)</strong></li>



<li>해결: <strong>SSD/메모리 장착 후 MinisCloud OS를 새로 받아 설치</strong></li>
</ul>



<p>혹시 저처럼 “받자마자 부팅이 안 된다”면, 무조건 아래부터 확인하는 게 빠릅니다.</p>



<ul class="wp-block-list">
<li>SSD가 실제로 장착돼 있는지</li>



<li>메모리가 장착돼 있는지</li>



<li>OS가 비어있거나 손상된 상태는 아닌지(재설치 필요)</li>
</ul>



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



<h2 class="wp-block-heading">3) SSD / 메모리 장착: OS 설치 전에 먼저 끝내야 할 작업</h2>



<div data-wp-interactive="core/file" class="wp-block-file"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://howinfo.kr/wp-content/uploads/2026/02/F8NAA-UserManual-Korean-V2.0.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="F8NAA-UserManual-Korean-V2.0의 삽입."></object><a id="wp-block-file--media-c829a337-fb73-4650-9a1d-19fef687bbe2" href="https://howinfo.kr/wp-content/uploads/2026/02/F8NAA-UserManual-Korean-V2.0.pdf">F8NAA-UserManual-Korean-V2.0</a><a href="https://howinfo.kr/wp-content/uploads/2026/02/F8NAA-UserManual-Korean-V2.0.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-c829a337-fb73-4650-9a1d-19fef687bbe2">다운로드</a></div>



<h3 class="wp-block-heading">3-1. 작업 전 필수</h3>



<ul class="wp-block-list">
<li><strong>전원 케이블 완전 분리</strong></li>



<li>정전기 방지(금속 프레임 잠깐 만지기)</li>



<li>나사/부품 분실 주의</li>
</ul>



<h3 class="wp-block-heading">3-2. SSD 장착 체크(가장 흔한 실수)</h3>



<ul class="wp-block-list">
<li>M.2 SSD는 규격이 여러 종류라, <strong>NVMe인지</strong>부터 확인하고 장착합니다.</li>



<li>“예전에 쓰던 M.2”를 재활용하려다가 <strong>SATA 방식이라 인식이 안 되는</strong> 경우도 많아요.</li>
</ul>



<h3 class="wp-block-heading">3-3. 메모리 장착 체크</h3>



<ul class="wp-block-list">
<li>메모리 슬롯에 끝까지 밀어 넣고 “딱” 고정되는 느낌이 나야 합니다.</li>



<li>헐겁게 끼워지면 부팅 자체가 안 되거나, 전원만 들어오고 화면이 안 뜨는 경우가 생깁니다.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>저는 첫날 “어? 왜 안 켜지지?”에서 시간을 많이 썼는데, 지금 생각하면 <strong>SSD/메모리 장착 여부를 먼저 확인했으면 30분 컷</strong>이었어요.</p>
</blockquote>



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



<h2 class="wp-block-heading">4) OS 설치(재설치) 준비물: 이거 없으면 시작이 안 됨</h2>



<p>제가 실제로 사용한 “정석 루틴”은 이 준비물부터입니다.</p>



<ul class="wp-block-list">
<li>다른 PC 1대(Windows면 가장 편함)</li>



<li>USB 메모리(8GB 이상 권장)</li>



<li>모니터(HDMI), 키보드/마우스</li>



<li>유선 LAN(가능하면 권장)</li>



<li>MinisCloud OS 설치 파일 + 설치 안내 PDF(Installation step)</li>
</ul>



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



<div data-wp-interactive="core/file" class="wp-block-file"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://howinfo.kr/wp-content/uploads/2026/02/MinisCloud_OS_설치_절차_한글번역.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="MinisCloud_OS_설치_절차_한글번역의 삽입."></object><a id="wp-block-file--media-fa49863c-2786-4a13-8091-712399b11ddb" href="https://howinfo.kr/wp-content/uploads/2026/02/MinisCloud_OS_설치_절차_한글번역.pdf">MinisCloud_OS_설치_절차_한글번역</a><a href="https://howinfo.kr/wp-content/uploads/2026/02/MinisCloud_OS_설치_절차_한글번역.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-fa49863c-2786-4a13-8091-712399b11ddb">다운로드</a></div>



<h2 class="wp-block-heading">5) MinisCloud OS 설치(재설치) 실전 루틴</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>아래 흐름은 **PDF 설치 가이드(Installation step)**를 참고해서, 제가 실제로 해결한 방식대로 “실수 안 나게” 정리한 절차입니다.</p>
</blockquote>



<h3 class="wp-block-heading">5-1. 설치 USB 만들기</h3>



<ol class="wp-block-list">
<li>MinisCloud OS 설치 파일을 내려받습니다.</li>



<li>안내 문서에서 지정한 방식대로 <strong>부팅 USB를 생성</strong>합니다.
<ul class="wp-block-list">
<li>여기서 실패가 많습니다. “파일을 USB에 복사”가 아니라 **부팅 가능한 형태로 ‘굽기/쓰기’**가 되어야 합니다.</li>
</ul>
</li>
</ol>



<p><strong>자주 터지는 문제</strong></p>



<ul class="wp-block-list">
<li>USB가 부팅으로 안 잡힘 → “USB 생성이 제대로 안 됨” 가능성이 큼</li>



<li>USB 포트 변경/다른 USB로 재시도하면 해결되는 경우도 많습니다.</li>
</ul>



<h3 class="wp-block-heading">5-2. N5 Pro에 연결(설치 모드)</h3>



<ul class="wp-block-list">
<li>USB(설치용) 연결</li>



<li>HDMI로 모니터 연결</li>



<li>키보드/마우스 연결</li>



<li>유선 LAN 연결</li>



<li>전원 ON</li>
</ul>



<h3 class="wp-block-heading">5-3. 부팅 메뉴(또는 BIOS)에서 USB 부팅</h3>



<ul class="wp-block-list">
<li>전원을 켠 직후, <strong>부트 메뉴 키</strong>를 눌러 USB를 선택합니다.</li>



<li>메뉴 진입이 안 되면 재부팅하면서 타이밍을 조금씩 조정합니다.</li>
</ul>



<h3 class="wp-block-heading">5-4. 설치 대상 디스크 선택(중요)</h3>



<ul class="wp-block-list">
<li>설치 화면에서 “대상 디스크”를 고르게 됩니다.</li>



<li>보통 OS는 **내장 SSD(128GB)**에 설치하는 흐름이 가장 단순합니다.</li>
</ul>



<p>⚠️ <strong>주의</strong><br>이 단계에서 디스크 선택을 잘못하면, 데이터가 있는 드라이브를 포맷할 수 있습니다.<br><strong>첫 설치는 ‘새 디스크만’ 꽂고 시작</strong>하는 게 마음 편합니다.</p>



<h3 class="wp-block-heading">5-5. 설치 완료 → 재부팅 → USB 제거</h3>



<ul class="wp-block-list">
<li>설치가 끝나면 재부팅 후 <strong>USB를 뽑고</strong> 내장 SSD로 부팅되게 합니다.</li>



<li>여기서 USB를 꽂아둔 채로 두면 다시 설치 화면으로 들어가 “왜 또 설치 화면이지?”가 발생합니다.</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="800" height="369" src="https://howinfo.kr/wp-content/uploads/2026/02/m03.png" alt="" class="wp-image-2120" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m03.png 800w, https://howinfo.kr/wp-content/uploads/2026/02/m03-300x138.png 300w, https://howinfo.kr/wp-content/uploads/2026/02/m03-768x354.png 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure>



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



<h2 class="wp-block-heading">6) 설치 후 첫 세팅: “당일에 끝내는 기본 안정화”</h2>



<p>OS 설치가 끝났으면, 그 다음은 <strong>운영 안정화</strong>입니다. 저는 첫날에 아래만은 꼭 해둡니다.</p>



<h3 class="wp-block-heading">6-1. 계정/보안</h3>



<ul class="wp-block-list">
<li>관리자 계정 비밀번호는 강하게 설정</li>



<li>가능하면 2단계 인증/접근제한 옵션도 함께 확인</li>
</ul>



<h3 class="wp-block-heading">6-2. 네트워크</h3>



<ul class="wp-block-list">
<li>유선 LAN으로 먼저 안정화</li>



<li>이후에 필요하면 고속 포트(5G/10G) 환경을 단계적으로 업그레이드</li>
</ul>



<h3 class="wp-block-heading">6-3. 스토리지 구성</h3>



<ul class="wp-block-list">
<li>단일 디스크로 시작할지, 미러/RAID로 갈지 결정</li>



<li>“백업이 필요한 데이터”라면, <strong>초기부터 이중화/백업 루틴</strong>을 설계하는 게 마음 편합니다.</li>
</ul>



<h3 class="wp-block-heading">6-4. 설치 위치/발열</h3>



<ul class="wp-block-list">
<li>NAS는 24시간 도는 장비라, 통풍 확보가 중요합니다.</li>



<li>벽에 너무 붙이지 말고, 상단/후면 공기 흐름을 막지 않게 설치합니다.</li>
</ul>



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



<h2 class="wp-block-heading">7) 제가 느낀 N5 Pro 첫인상(짧은 후기)</h2>



<ul class="wp-block-list">
<li>“NAS + 미니PC” 성격이 강해서, 단순 파일서버를 넘어서 <strong>도커/자동화/개발</strong> 쪽으로 확장하기 좋아 보였습니다.</li>



<li>다만 첫날은 “기대(탑재/설치 완료)” 때문에 삽질을 했고,<br>이 경험 덕분에 오히려 <strong>설치 과정 전체를 내 손으로 정리</strong>해두게 되어 장기적으로는 더 든든해졌습니다.</li>
</ul>



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



<h2 class="wp-block-heading">8) 당일 체크리스트(복붙용)</h2>



<ul class="wp-block-list">
<li>SSD 128GB가 <strong>본체에 실제 장착</strong>됐는지 확인</li>



<li>메모리 16GB가 <strong>정상 장착</strong>됐는지 확인</li>



<li>설치 USB 생성(부팅 가능 형태로 쓰기 완료)</li>



<li>HDMI/키보드/마우스 연결 후 부팅</li>



<li>부트 메뉴/BIOS에서 USB 부팅 선택</li>



<li>설치 대상 디스크 선택 실수 방지(데이터 디스크 포맷 주의)</li>



<li>설치 완료 후 재부팅 + USB 제거</li>



<li>관리자 계정/보안 설정</li>



<li>스토리지 구성(단일/미러/RAID) 결정</li>



<li>통풍 확보/설치 위치 정리</li>
</ul>



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



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



<h3 class="wp-block-heading">Q1. “받자마자 부팅이 안 돼요.” 제일 먼저 뭘 봐야 하나요?</h3>



<p>A. SSD/메모리가 <strong>동봉만 되고 미장착</strong>인 경우가 있어요. 내부를 열어 <strong>실제로 장착되어 있는지</strong>가 1순위입니다.</p>



<h3 class="wp-block-heading">Q2. OS가 설치된 줄 알았는데 비어있을 수도 있나요?</h3>



<p>A. 네. 케이스에 따라 OS가 준비되어 있어도 손상/미탑재 상태일 수 있어, <strong>MinisCloud OS 재설치</strong> 루틴을 알아두면 가장 빨리 복구됩니다.</p>



<h3 class="wp-block-heading">Q3. 설치 USB 만들었는데 USB로 부팅이 안 돼요.</h3>



<p>A. 파일 복사가 아니라 **부팅 가능한 형태로 “쓰기/굽기”**가 되어야 합니다. USB를 바꾸거나 다른 포트로 재시도하면 해결되는 경우가 많습니다.</p>



<h3 class="wp-block-heading">Q4. 디스크 여러 개 꽂아도 되나요?</h3>



<p>A. 가능하지만 첫 설치는 <strong>새 디스크만</strong>으로 시작하는 편이 안전합니다. 설치 과정에서 디스크 선택을 잘못하면 포맷 사고가 날 수 있어요.</p>



<p>저처럼 삽질 하지 마시고 . 일단 중요한것은 </p>



<p>os가 설치가 안되어 있고 미니스포럼 사이트에서 os를 받아서 싱글보드 이미지 굽듯이 구워서 다시 설치하고 부팅 그리고 같은 네트워크에서 동일 대역에서 접근해야 함 할때 . 인증등 있음 아래 참고 </p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="756" height="443" src="https://howinfo.kr/wp-content/uploads/2026/02/m06.png" alt="" class="wp-image-2121" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m06.png 756w, https://howinfo.kr/wp-content/uploads/2026/02/m06-300x176.png 300w" sizes="auto, (max-width: 756px) 100vw, 756px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="960" height="443" src="https://howinfo.kr/wp-content/uploads/2026/02/m05.png" alt="" class="wp-image-2122" srcset="https://howinfo.kr/wp-content/uploads/2026/02/m05.png 960w, https://howinfo.kr/wp-content/uploads/2026/02/m05-300x138.png 300w, https://howinfo.kr/wp-content/uploads/2026/02/m05-768x354.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></figure>
<p>게시물 <a href="https://howinfo.kr/%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-%ec%96%b8%eb%b0%95%ec%8b%b1%eb%b6%80%ed%84%b0-os-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ec%a7%91-nas-%ec%84%b8%ed%8c%85-%ec%8b%a4%ec%a0%84%ea%b8%b0/">미니스포럼 N5 Pro 언박싱부터 OS 설치까지: 집 NAS 세팅 실전기</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%eb%af%b8%eb%8b%88%ec%8a%a4%ed%8f%ac%eb%9f%bc-n5-pro-%ec%96%b8%eb%b0%95%ec%8b%b1%eb%b6%80%ed%84%b0-os-%ec%84%a4%ec%b9%98%ea%b9%8c%ec%a7%80-%ec%a7%91-nas-%ec%84%b8%ed%8c%85-%ec%8b%a4%ec%a0%84%ea%b8%b0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>파이썬 프로그램을 윈도우 EXE로 만드는 방법 (PyInstaller 실전 가이드)</title>
		<link>https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9c%88%eb%8f%84%ec%9a%b0-exe%eb%a1%9c-%eb%a7%8c%eb%93%9c%eb%8a%94-%eb%b0%a9%eb%b2%95-pyinstaller-%ec%8b%a4%ec%a0%84/</link>
					<comments>https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9c%88%eb%8f%84%ec%9a%b0-exe%eb%a1%9c-%eb%a7%8c%eb%93%9c%eb%8a%94-%eb%b0%a9%eb%b2%95-pyinstaller-%ec%8b%a4%ec%a0%84/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Sat, 28 Feb 2026 00:28:23 +0000</pubDate>
				<category><![CDATA[IT기초]]></category>
		<category><![CDATA[exe배포]]></category>
		<category><![CDATA[Pyinstaller]]></category>
		<category><![CDATA[tkinter]]></category>
		<category><![CDATA[개발팁]]></category>
		<category><![CDATA[배포자동화]]></category>
		<category><![CDATA[빌드]]></category>
		<category><![CDATA[윈도우exe]]></category>
		<category><![CDATA[파이썬]]></category>
		<category><![CDATA[파이썬패키징]]></category>
		<category><![CDATA[프로그램 배포]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2108</guid>

					<description><![CDATA[<p>파이썬으로 만든 스크립트가 잘 돌아가도, 주변 사람에게 공유하려면 항상 이런 문제가 생깁니다. 그래서 결국 많이 선택하는 방법이 EXE로 패키징하는 겁니다.이번...</p>
<p>게시물 <a href="https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9c%88%eb%8f%84%ec%9a%b0-exe%eb%a1%9c-%eb%a7%8c%eb%93%9c%eb%8a%94-%eb%b0%a9%eb%b2%95-pyinstaller-%ec%8b%a4%ec%a0%84/">파이썬 프로그램을 윈도우 EXE로 만드는 방법 (PyInstaller 실전 가이드)</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>파이썬으로 만든 스크립트가 잘 돌아가도, 주변 사람에게 공유하려면 항상 이런 문제가 생깁니다.</p>



<ul class="wp-block-list">
<li>“파이썬 설치해야 해?”</li>



<li>“pip로 뭐 설치해야 해?”</li>



<li>“실행했더니 검은 창만 뜨고 꺼지는데?”</li>
</ul>



<p>그래서 결국 많이 선택하는 방법이 <strong>EXE로 패키징</strong>하는 겁니다.<br>이번 글은 제가 실제로 가장 많이 쓰는 도구인 <strong>PyInstaller</strong> 기준으로, “초보도 따라 할 수 있게” 정리했습니다.</p>



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



<h2 class="wp-block-heading">1) EXE 만들기 전에 꼭 알아야 할 것</h2>



<h3 class="wp-block-heading">✅ EXE로 만들면 좋은 점</h3>



<ul class="wp-block-list">
<li>파이썬이 설치되지 않은 PC에서도 실행 가능(대부분의 경우)</li>



<li>배포/공유가 편해짐</li>



<li>파일 1개(또는 폴더 1개)로 정리 가능</li>
</ul>



<h3 class="wp-block-heading">⚠️ 현실적으로 생기는 문제</h3>



<ul class="wp-block-list">
<li>용량이 커짐(수십~수백 MB도 흔함)</li>



<li>백신 오탐(특히 새로 만든 exe)</li>



<li>경로 문제(파일 저장/설정 파일 위치)</li>



<li>GUI(Tkinter 등)에서는 괜찮은데, 콘솔 출력은 안 보이기도 함</li>
</ul>



<p>이걸 미리 알고 가면 삽질이 크게 줄어요.</p>



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



<h2 class="wp-block-heading">2) 준비물: 파이썬/폴더 구조 추천</h2>



<h3 class="wp-block-heading">권장 폴더 구조 예시</h3>



<pre class="wp-block-preformatted">my_app/<br>  main.py<br>  core/<br>  assets/<br>  data/<br>  requirements.txt</pre>



<ul class="wp-block-list">
<li><strong>assets/</strong> : 이미지, 아이콘 등 리소스</li>



<li><strong>data/</strong> : 설정 파일, 저장 파일(앱 실행 중 생성되는 데이터)</li>



<li><strong>requirements.txt</strong> : 의존성 목록</li>
</ul>



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



<h2 class="wp-block-heading">3) PyInstaller 설치</h2>



<p>가장 먼저 <strong>가상환경</strong>을 추천합니다. (빌드가 깔끔해져요)</p>



<h3 class="wp-block-heading">(선택) 가상환경 만들기</h3>



<pre class="wp-block-preformatted">cd my_app<br>python -m venv .venv<br>.venv\Scripts\activate</pre>



<h3 class="wp-block-heading">PyInstaller 설치</h3>



<pre class="wp-block-preformatted">python -m pip install --upgrade pip<br>pip install pyinstaller</pre>



<p>설치 확인:</p>



<pre class="wp-block-preformatted">pyinstaller --version</pre>



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



<h2 class="wp-block-heading">4) 가장 기본 빌드: onefile로 EXE 만들기</h2>



<h3 class="wp-block-heading">콘솔 프로그램(터미널 창 필요)</h3>



<pre class="wp-block-preformatted">pyinstaller --onefile main.py</pre>



<h3 class="wp-block-heading">GUI 프로그램(창만 띄우고 콘솔 숨김)</h3>



<pre class="wp-block-preformatted">pyinstaller --onefile --noconsole main.py</pre>



<p>빌드가 끝나면 보통 아래 폴더가 생깁니다.</p>



<ul class="wp-block-list">
<li><code>dist/</code> : 실제 배포 파일(exe)</li>



<li><code>build/</code> : 빌드 캐시</li>



<li><code>main.spec</code> : 빌드 설정 파일</li>
</ul>



<p>결과 EXE는 <code>dist/main.exe</code> 에서 확인합니다.</p>



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



<h2 class="wp-block-heading">5) 아이콘 넣기(윈도우 exe 느낌 살리기)</h2>



<p>아이콘은 <code>.ico</code> 파일이 필요합니다. (png 그대로는 안됨)</p>



<pre class="wp-block-preformatted">pyinstaller --onefile --noconsole --icon=assets/app.ico main.py</pre>



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



<h2 class="wp-block-heading">6) 이미지/설정파일 등 “외부 파일” 포함하기</h2>



<p>여기서 많이 막힙니다.<br>파이썬에서는 상대경로로 잘 읽히는데, exe로 묶이면 경로가 달라져요.</p>



<h3 class="wp-block-heading">6-1) 빌드 옵션으로 파일 포함</h3>



<p>예: <code>assets/</code> 폴더를 함께 포함</p>



<pre class="wp-block-preformatted">pyinstaller --onefile --noconsole ^<br>  --add-data "assets;assets" ^<br>  main.py</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>윈도우에서 <code>--add-data "원본;대상"</code> 형태로 세미콜론(<code>;</code>)을 사용합니다.</p>
</blockquote>



<h3 class="wp-block-heading">6-2) exe 환경에서 경로 처리(핵심)</h3>



<p>파이썬 코드에서 “실행 위치”를 잡는 함수를 넣어두면 안정적입니다.</p>



<pre class="wp-block-preformatted">import os, sysdef resource_path(relative_path: str) -&gt; str:<br>    # PyInstaller로 묶이면 _MEIPASS 경로에 리소스가 풀림<br>    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))<br>    return os.path.join(base_path, relative_path)</pre>



<p>사용 예:</p>



<pre class="wp-block-preformatted">icon_path = resource_path("assets/app.ico")</pre>



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



<h2 class="wp-block-heading">7) “exe 실행하면 저장이 안돼요/초기화돼요” 문제 해결</h2>



<p>이 현상은 거의 대부분 <strong>저장 위치가 잘못 잡혀서</strong> 생깁니다.</p>



<ul class="wp-block-list">
<li>개발 중: 프로젝트 폴더에 저장</li>



<li>exe 실행: 사용자 PC의 다른 위치에서 실행 → 상대경로가 달라짐</li>



<li>또는 Program Files 아래라면 쓰기 권한 문제로 저장 실패</li>
</ul>



<h3 class="wp-block-heading">추천: 사용자 폴더(AppData) 아래에 저장 폴더 만들기</h3>



<pre class="wp-block-preformatted">import osdef get_app_data_dir(app_name="MyApp"):<br>    base = os.getenv("APPDATA")  # C:\Users\...\AppData\Roaming<br>    path = os.path.join(base, app_name)<br>    os.makedirs(path, exist_ok=True)<br>    return path</pre>



<p>저장 예:</p>



<pre class="wp-block-preformatted">cfg_path = os.path.join(get_app_data_dir("HStockGuard"), "config.json")</pre>



<p>이렇게 하면 exe로 배포해도 <strong>설정/저장 데이터가 유지</strong>됩니다.</p>



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



<h2 class="wp-block-heading">8) 자주 겪는 에러/해결 체크리스트</h2>



<h3 class="wp-block-heading">✅ 실행하자마자 창이 꺼짐</h3>



<ul class="wp-block-list">
<li>콘솔 모드로 빌드해서 에러 확인<br><code>--noconsole</code> 빼고 실행해보기</li>
</ul>



<h3 class="wp-block-heading">✅ 모듈 못 찾는다고 나옴</h3>



<ul class="wp-block-list">
<li>누락된 모듈을 hidden-import로 추가</li>
</ul>



<pre class="wp-block-preformatted">pyinstaller --onefile --hidden-import=패키지명 main.py</pre>



<h3 class="wp-block-heading">✅ 백신이 위험하다고 막음</h3>



<ul class="wp-block-list">
<li>새 exe는 오탐이 흔함</li>



<li>코드서명까지는 현실적으로 어렵고, 최소한 배포 파일을 자주 바꾸지 않는 게 도움</li>



<li>가능하면 <code>onedir</code> 배포도 고려(오탐이 덜 나는 경우가 있음)</li>
</ul>



<h3 class="wp-block-heading">✅ 용량이 너무 큼</h3>



<ul class="wp-block-list">
<li>가상환경을 깨끗하게 유지</li>



<li>불필요한 패키지 제거</li>



<li><code>--exclude-module</code> 사용 고려(상황에 따라)</li>
</ul>



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



<h2 class="wp-block-heading">9) 배포 방식 추천: onefile vs onedir</h2>



<h3 class="wp-block-heading">onefile</h3>



<ul class="wp-block-list">
<li>장점: 파일 1개로 배포 끝</li>



<li>단점: 실행 시 임시폴더에 풀리는 과정 때문에 첫 실행이 느릴 수 있음</li>
</ul>



<h3 class="wp-block-heading">onedir</h3>



<pre class="wp-block-preformatted">pyinstaller --noconsole main.py</pre>



<ul class="wp-block-list">
<li>장점: 실행 빠르고 문제 추적이 쉬움</li>



<li>단점: 폴더째로 배포해야 함</li>
</ul>



<p>개인적으로는 <strong>처음엔 onedir로 안정화 → 마지막에 onefile</strong>로 마무리하는 경우가 많았습니다.</p>



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



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



<p><strong>Q1. PyInstaller 말고 다른 방법도 있나요?</strong><br>A. 네. <code>cx_Freeze</code>, <code>Nuitka</code> 같은 대안도 있습니다. 다만 가장 대중적이고 자료가 많은 건 PyInstaller입니다.</p>



<p><strong>Q2. 32비트/64비트는 어떻게 맞추나요?</strong><br>A. 빌드에 사용하는 파이썬이 64비트면 보통 64비트 exe가 됩니다. 배포 대상 PC 환경과 맞추세요.</p>



<p><strong>Q3. exe로 만들면 소스가 완전히 숨겨지나요?</strong><br>A. 완전한 보안은 아닙니다. “배포 편의” 목적에 가깝다고 보는 게 현실적입니다.</p>



<h1 class="wp-block-heading">부록) 그대로 복사해서 쓰는 샘플 코드(저장 유지 + 리소스 경로)</h1>



<h2 class="wp-block-heading">core/paths.py</h2>



<pre class="wp-block-preformatted">import os<br>import sysdef resource_path(relative_path: str) -&gt; str:<br>    """<br>    PyInstaller(onefile)에서 리소스 경로를 안전하게 가져온다.<br>    """<br>    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))<br>    return os.path.join(base_path, relative_path)def appdata_dir(app_name: str = "MyApp") -&gt; str:<br>    """<br>    AppData\Roaming 아래에 앱 폴더를 생성해 저장 경로로 사용한다.<br>    """<br>    base = os.getenv("APPDATA") or os.path.expanduser("~")<br>    path = os.path.join(base, app_name)<br>    os.makedirs(path, exist_ok=True)<br>    return path</pre>



<h2 class="wp-block-heading">core/config.py</h2>



<pre class="wp-block-preformatted">import json<br>import os<br>from .paths import appdata_dirdef load_config(app_name: str = "MyApp", filename: str = "config.json") -&gt; dict:<br>    path = os.path.join(appdata_dir(app_name), filename)<br>    if not os.path.exists(path):<br>        return {}<br>    with open(path, "r", encoding="utf-8") as f:<br>        return json.load(f)def save_config(cfg: dict, app_name: str = "MyApp", filename: str = "config.json") -&gt; str:<br>    path = os.path.join(appdata_dir(app_name), filename)<br>    with open(path, "w", encoding="utf-8") as f:<br>        json.dump(cfg, f, ensure_ascii=False, indent=2)<br>    return path</pre>



<h2 class="wp-block-heading">main.py (테스트용)</h2>



<pre class="wp-block-preformatted">from core.config import load_config, save_configAPP_NAME = "HowinfoPyExeDemo"def main():<br>    cfg = load_config(APP_NAME)<br>    run_count = int(cfg.get("run_count", 0)) + 1<br>    cfg["run_count"] = run_count    saved_path = save_config(cfg, APP_NAME)<br>    print(f"[OK] 실행 횟수: {run_count}")<br>    print(f"[OK] 설정 저장 위치: {saved_path}")if __name__ == "__main__":<br>    main()</pre>



<h2 class="wp-block-heading">빌드 명령어(윈도우)</h2>



<pre class="wp-block-preformatted">pyinstaller --onefile main.py</pre>



<p>GUI + 아이콘 + assets 포함 예시:</p>



<pre class="wp-block-preformatted">pyinstaller --onefile --noconsole ^<br>  --icon=assets/app.ico ^<br>  --add-data "assets;assets" ^<br>  main.py<br></pre>
<p>게시물 <a href="https://howinfo.kr/%ed%8c%8c%ec%9d%b4%ec%8d%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9c%88%eb%8f%84%ec%9a%b0-exe%eb%a1%9c-%eb%a7%8c%eb%93%9c%eb%8a%94-%eb%b0%a9%eb%b2%95-pyinstaller-%ec%8b%a4%ec%a0%84/">파이썬 프로그램을 윈도우 EXE로 만드는 방법 (PyInstaller 실전 가이드)</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-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9c%88%eb%8f%84%ec%9a%b0-exe%eb%a1%9c-%eb%a7%8c%eb%93%9c%eb%8a%94-%eb%b0%a9%eb%b2%95-pyinstaller-%ec%8b%a4%ec%a0%84/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Orange Pi 5로 “주식/ETF 트레일링 스탑 + 손절 + 리스크 레벨” 알림봇 만들기 (Synology Chat 웹훅, 10~30분 자동 주기)_버전 두번째 full 소스</title>
		<link>https://howinfo.kr/orange-pi-5%eb%a1%9c-%ec%a3%bc%ec%8b%9d-etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%86%90%ec%a0%88-%eb%a6%ac%ec%8a%a4%ed%81%ac-%eb%a0%88%eb%b2%a8-%ec%95%8c/</link>
					<comments>https://howinfo.kr/orange-pi-5%eb%a1%9c-%ec%a3%bc%ec%8b%9d-etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%86%90%ec%a0%88-%eb%a6%ac%ec%8a%a4%ed%81%ac-%eb%a0%88%eb%b2%a8-%ec%95%8c/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Wed, 25 Feb 2026 13:12:23 +0000</pubDate>
				<category><![CDATA[개발·코딩]]></category>
		<category><![CDATA[ETF]]></category>
		<category><![CDATA[yfinance]]></category>
		<category><![CDATA[리스크관리]]></category>
		<category><![CDATA[손절]]></category>
		<category><![CDATA[시놀로지chat]]></category>
		<category><![CDATA[시놀로지나스]]></category>
		<category><![CDATA[오렌지파이5]]></category>
		<category><![CDATA[웹훅]]></category>
		<category><![CDATA[주식자동화]]></category>
		<category><![CDATA[트레일링스탑]]></category>
		<category><![CDATA[파이썬 자동화]]></category>
		<category><![CDATA[포트폴리오관리]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2104</guid>

					<description><![CDATA[<p>한 줄 요약 오렌지파이5에서 **보유 종목(주식/ETF)**을 파일로 관리하고, ※ 가격은 yfinance 기반이라 “지연 Close”로 동작합니다(실시간 아님).실시간으로 바꾸려면 추후 키움 API...</p>
<p>게시물 <a href="https://howinfo.kr/orange-pi-5%eb%a1%9c-%ec%a3%bc%ec%8b%9d-etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%86%90%ec%a0%88-%eb%a6%ac%ec%8a%a4%ed%81%ac-%eb%a0%88%eb%b2%a8-%ec%95%8c/">Orange Pi 5로 “주식/ETF 트레일링 스탑 + 손절 + 리스크 레벨” 알림봇 만들기 (Synology Chat 웹훅, 10~30분 자동 주기)_버전 두번째 full 소스</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">한 줄 요약</h2>



<p>오렌지파이5에서 **보유 종목(주식/ETF)**을 파일로 관리하고,</p>



<ul class="wp-block-list">
<li><strong>수익 최고점(peak) 대비 -X% 트레일링</strong></li>



<li><strong>매수가 대비 -Y% 손절</strong></li>



<li><strong>손절/트레일링 근접 경고</strong></li>



<li><strong>1시간 요약 / 15:35 요약 / 16:00 리포트</strong></li>



<li><strong>리스크 HIGH일 때만 30분→10분 자동 단축</strong></li>



<li><strong>다음날 자동 재감시(active=1 복구)</strong><br>를 <strong>시놀로지 Chat 웹훅으로 자동 알림</strong>해주는 파이썬 봇입니다.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>※ 가격은 yfinance 기반이라 “지연 Close”로 동작합니다(실시간 아님).<br>실시간으로 바꾸려면 추후 키움 API 등 연동이 필요합니다.</p>
</blockquote>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="734" height="639" src="https://howinfo.kr/wp-content/uploads/2026/02/sychat1.png" alt="" class="wp-image-2105" srcset="https://howinfo.kr/wp-content/uploads/2026/02/sychat1.png 734w, https://howinfo.kr/wp-content/uploads/2026/02/sychat1-300x261.png 300w" sizes="auto, (max-width: 734px) 100vw, 734px" /></figure>



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



<h1 class="wp-block-heading">1) 동작 개념(핵심 로직)</h1>



<h3 class="wp-block-heading">✅ 트레일링(수익 구간)</h3>



<ul class="wp-block-list">
<li>내 매수금액(평가금액 기준) 대비 최고점(peak)을 계속 갱신</li>



<li>기준선 = <code>peak × (1 - trailing%)</code></li>



<li>현재가가 기준선 이하로 내려오면 <strong>매도 알림</strong></li>
</ul>



<h3 class="wp-block-heading">✅ 가변 트레일링(수익이 커질수록 더 타이트)</h3>



<p>예: base trailing이 10%인 종목이라면</p>



<ul class="wp-block-list">
<li>수익 0~20%: 10%</li>



<li>수익 20~50%: 7% (10%×0.7)</li>



<li>수익 50% 이상: 5% (10%×0.5)</li>
</ul>



<h3 class="wp-block-heading">✅ 손절(매수가 기준)</h3>



<ul class="wp-block-list">
<li>손절선 = <code>매수금액 × (1 - stop_loss%)</code></li>



<li>현재가가 손절선 이하로 내려오면 <strong>손절 알림</strong></li>
</ul>



<h3 class="wp-block-heading">✅ 근접 경고</h3>



<ul class="wp-block-list">
<li>트레일링 기준선까지 <strong>2% 이내</strong>로 접근하면 “근접 경고”</li>



<li>손절선까지 <strong>2% 이내</strong>로 접근하면 “손절 근접 경고”</li>
</ul>



<h3 class="wp-block-heading">✅ 리스크 레벨(LOW / MEDIUM / HIGH)</h3>



<ul class="wp-block-list">
<li>Trigger(기준선 이하) / Near(근접) 종목 수</li>



<li>위험 노출 비중(Trigger+Near 종목 평가금액 합 / 전체 평가금액)<br>을 기준으로 <strong>LOW/MEDIUM/HIGH</strong> 표시<br>→ 장중 요약, 16:00 리포트에 같이 출력</li>
</ul>



<h3 class="wp-block-heading">✅ 실행 주기 자동 변경(장중만)</h3>



<ul class="wp-block-list">
<li>평소 장중: 30분</li>



<li>리스크 HIGH: 10분(더 촘촘히 감시)</li>



<li>장외: 120분(불필요 호출 절약)</li>
</ul>



<h3 class="wp-block-heading">✅ 다음날 자동 재활성화</h3>



<ul class="wp-block-list">
<li>매도/손절 알림 후 active=0으로 자동 비활성화(옵션)</li>



<li>다음날 09:01에 자동으로 active=1로 복구(옵션)</li>
</ul>



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



<h1 class="wp-block-heading">2) 폴더 구성(그대로 만들기)</h1>



<p>아래 3개 파일만 있으면 됩니다.</p>



<pre class="wp-block-preformatted">jusik_top10/<br> ├─ main.py<br> ├─ config.json<br> ├─ positions.csv<br> └─ state.json   (없으면 자동 생성됨, 처음엔 {} 권장)</pre>



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



<h1 class="wp-block-heading">3) 설치(오렌지파이5)</h1>



<pre class="wp-block-preformatted">sudo apt update<br>sudo apt install -y python3-pip<br>python3 -m pip install --user requests yfinance</pre>



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



<h1 class="wp-block-heading">4) config.json (복붙용)</h1>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><code>synology_chat_webhook_url</code>만 본인 값으로 바꿔주세요.</p>
</blockquote>



<pre class="wp-block-preformatted">{<br>  "synology_chat_webhook_url": "여기에_시놀로지챗_웹훅_URL_붙여넣기",  "default_trailing_pct": 0.10,<br>  "default_stop_loss_pct": 0.08,  "market_open": "09:00",<br>  "market_close": "15:30",  "startup_notify_enabled": true,  "near_alert_enabled": true,<br>  "near_alert_distance_pct": 2.0,<br>  "near_alert_cooldown_minutes": 60,  "stoploss_near_enabled": true,<br>  "stoploss_near_distance_pct": 2.0,<br>  "stoploss_near_cooldown_minutes": 180,  "auto_disable_on_alert": true,  "hourly_summary_enabled": true,<br>  "hourly_summary_interval_minutes": 60,  "daily_summary_time": "15:35",  "after_close_summary_enabled": true,<br>  "after_close_summary_time": "16:00",<br>  "after_close_include_inactive": false,  "adaptive_trailing_enabled": true,<br>  "adaptive_trailing_factors": [<br>    { "min_profit_pct": 0,  "factor": 1.0 },<br>    { "min_profit_pct": 20, "factor": 0.7 },<br>    { "min_profit_pct": 50, "factor": 0.5 }<br>  ],  "risk_high_near_count": 3,<br>  "risk_high_near_exposure_pct": 30,  "adaptive_interval_enabled": true,<br>  "interval_minutes_market": 30,<br>  "interval_minutes_high_risk": 10,<br>  "interval_minutes_off_market": 120,  "daily_reactivate_enabled": true,<br>  "daily_reactivate_time": "09:01"<br>}</pre>



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



<h1 class="wp-block-heading">5) positions.csv (복붙용)</h1>



<ul class="wp-block-list">
<li><code>market</code>: KS(코스피), KQ(코스닥)</li>



<li><code>trailing_pct</code>: 0.10 = 10%</li>



<li><code>stop_loss_pct</code>: 0.08 = -8%</li>



<li><code>active</code>: 1(감시), 0(감시중지)</li>
</ul>



<pre class="wp-block-preformatted">code,name,market,qty,buy_price,trailing_pct,stop_loss_pct,active<br>005930,삼성전자,KS,10,70000,0.10,0.08,1<br>069500,KODEX 200,KS,20,35000,0.08,0.07,1</pre>



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



<h1 class="wp-block-heading">6) state.json 초기화(권장)</h1>



<p>처음 적용할 때 state가 꼬였으면 초기화가 안전합니다.</p>



<pre class="wp-block-preformatted">echo "{}" &gt; state.json</pre>



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



<h1 class="wp-block-heading">7) main.py (전체 소스 — 그대로 복붙)</h1>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>아래 코드를 <code>main.py</code>로 저장하세요.</p>
</blockquote>



<pre class="wp-block-preformatted"># (아래 전체 코드 그대로 복붙)<br>"""<br>Orange Pi 5 (Ubuntu/ARM) 주식/ETF 트레일링 스탑 알림 시스템 (yfinance 기반, 지연 Close OK)[핵심 기능]<br>- positions.csv 관리: 종목/수량/매수가/trailing_pct/stop_loss_pct/active<br>- state.json 유지: peak_value, last_alerted_peak, 근접 경고 시각, 요약 발송 기록 등<br>- Synology Chat Incoming Webhook으로 알림 전송[장중(09:00~15:30) 기능]<br>1) 손절(매수가 기준) 알림: entry*(1-stop_loss_pct) 이하<br>2) 손절 근접 경고: 손절선까지 +X% 남으면(0% 이하면 손절)<br>3) 트레일링(수익구간) 알림: peak*(1-eff_trailing) 이하<br>4) 트레일링 근접 경고: 기준선까지 +X% 남으면<br>5) 1시간 요약(장중): 총 수익률 + 종목별 요약 + 리스크 레벨[장마감 이후]<br>- 15:35 일일 요약(TOP3/WORST3)<br>- 16:00 리포트(섹션 분리: TRIGGER/NEAR/SAFE + 손절 정보 + 리스크)[추가 보강]<br>- 가변 트레일링(Adaptive Trailing): base_trailing_pct × factor(수익구간별)<br>- 리스크 HIGH일 때 장중 주기 자동 단축(예: 30→10분)<br>- 매도/손절 알림 후 auto_disable_on_alert=true면 active=0 자동 변경<br>- 다음날 지정 시간에 active=0 → active=1 자동 재활성화(옵션)<br>- state.json 깨짐 자동복구 + 원자저장<br>- positions.csv 원자저장<br>- 시작 1회 안내 메시지[주의]<br>- yfinance는 지연 Close 기반(실시간 아님)<br>"""import os<br>import json<br>import time<br>import csv<br>import tempfile<br>from dataclasses import dataclass<br>from datetime import datetime, time as dtimeimport requests<br>import yfinance as yfBASE = os.path.dirname(os.path.abspath(__file__))<br>CONFIG_PATH = os.path.join(BASE, "config.json")<br>POSITIONS_PATH = os.path.join(BASE, "positions.csv")<br>STATE_PATH = os.path.join(BASE, "state.json")def log(step: str, msg: str = "", level: str = "INFO"):<br>    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")<br>    if msg:<br>        print(f"[{now}] [{level}] [{step}] {msg}")<br>    else:<br>        print(f"[{now}] [{level}] [{step}]")def fmt_money(x) -&gt; str:<br>    return f"{x:,.0f}"def parse_hhmm(s: str) -&gt; dtime:<br>    hh, mm = s.split(":")<br>    return dtime(hour=int(hh), minute=int(mm))def is_market_open(now: datetime, open_t: dtime, close_t: dtime) -&gt; bool:<br>    t = now.time()<br>    return open_t &lt;= t &lt;= close_tdef load_json_safe(path, default):<br>    if not os.path.exists(path):<br>        return default<br>    try:<br>        with open(path, "r", encoding="utf-8") as f:<br>            return json.load(f)<br>    except json.JSONDecodeError as e:<br>        ts = datetime.now().strftime("%Y%m%d_%H%M%S")<br>        bak = f"{path}.broken_{ts}"<br>        try:<br>            os.replace(path, bak)<br>        except:<br>            try:<br>                import shutil<br>                shutil.copy2(path, bak)<br>            except:<br>                pass<br>        print(f"[WARN] JSON이 깨져 자동 복구했습니다. 백업: {bak} / 오류: {e}")<br>        return defaultdef save_json_atomic(path, data):<br>    tmp_dir = os.path.dirname(path) or "."<br>    fd, tmp_path = tempfile.mkstemp(prefix="state_", suffix=".json", dir=tmp_dir)<br>    os.close(fd)<br>    try:<br>        with open(tmp_path, "w", encoding="utf-8") as f:<br>            json.dump(data, f, ensure_ascii=False, indent=2)<br>        os.replace(tmp_path, path)<br>    finally:<br>        if os.path.exists(tmp_path):<br>            try:<br>                os.remove(tmp_path)<br>            except:<br>                passdef parse_float_optional(x):<br>    if x is None:<br>        return None<br>    s = str(x).strip()<br>    if s == "":<br>        return None<br>    return float(s)def parse_int_optional(x, default=1):<br>    if x is None:<br>        return default<br>    s = str(x).strip()<br>    if s == "":<br>        return default<br>    try:<br>        return int(float(s))<br>    except:<br>        return default@dataclass<br>class Position:<br>    code: str<br>    name: str<br>    market: str<br>    qty: float<br>    buy_price: float<br>    trailing_pct: float<br>    stop_loss_pct: float<br>    active: int    @property<br>    def ticker(self) -&gt; str:<br>        return f"{self.code}.{self.market.upper()}"def load_positions_csv(path, default_trailing_pct: float, default_stop_loss_pct: float) -&gt; list[Position]:<br>    if not os.path.exists(path):<br>        raise RuntimeError(f"positions.csv가 없습니다: {path}")    positions = []<br>    with open(path, "r", encoding="utf-8-sig") as f:<br>        reader = csv.DictReader(f)<br>        required = {"code", "qty", "buy_price"}<br>        if not required.issubset(set(reader.fieldnames or [])):<br>            raise RuntimeError(f"positions.csv 컬럼이 필요합니다: {sorted(required)}")        for row in reader:<br>            code = row["code"].strip()<br>            name = (row.get("name") or code).strip()<br>            market = (row.get("market") or "KS").strip().upper()<br>            if market not in ("KS", "KQ"):<br>                raise RuntimeError(f"{code} market 값 오류: {market} (KS/KQ만 허용)")            qty = float(row["qty"])<br>            buy_price = float(row["buy_price"])            trailing_pct = parse_float_optional(row.get("trailing_pct"))<br>            if trailing_pct is None:<br>                trailing_pct = default_trailing_pct<br>            if not (0 &lt; trailing_pct &lt; 1):<br>                raise RuntimeError(f"{code} trailing_pct 비정상: {trailing_pct}")            stop_loss_pct = parse_float_optional(row.get("stop_loss_pct"))<br>            if stop_loss_pct is None:<br>                stop_loss_pct = default_stop_loss_pct<br>            if not (0 &lt;= stop_loss_pct &lt; 1):<br>                raise RuntimeError(f"{code} stop_loss_pct 비정상: {stop_loss_pct}")            active = parse_int_optional(row.get("active"), default=1)<br>            active = 1 if active != 0 else 0            positions.append(Position(code, name, market, qty, buy_price, trailing_pct, stop_loss_pct, active))<br>    return positionsdef save_positions_csv_atomic(path, positions: list[Position]):<br>    fieldnames = ["code", "name", "market", "qty", "buy_price", "trailing_pct", "stop_loss_pct", "active"]<br>    tmp_dir = os.path.dirname(path) or "."<br>    fd, tmp_path = tempfile.mkstemp(prefix="positions_", suffix=".csv", dir=tmp_dir)<br>    os.close(fd)<br>    try:<br>        with open(tmp_path, "w", encoding="utf-8-sig", newline="") as f:<br>            w = csv.DictWriter(f, fieldnames=fieldnames)<br>            w.writeheader()<br>            for p in positions:<br>                w.writerow({<br>                    "code": p.code, "name": p.name, "market": p.market,<br>                    "qty": p.qty, "buy_price": p.buy_price,<br>                    "trailing_pct": p.trailing_pct, "stop_loss_pct": p.stop_loss_pct,<br>                    "active": p.active<br>                })<br>        os.replace(tmp_path, path)<br>    finally:<br>        if os.path.exists(tmp_path):<br>            try: os.remove(tmp_path)<br>            except: passdef send_synology_chat(webhook_url: str, text: str):<br>    payload_json = json.dumps({"text": text}, ensure_ascii=False)<br>    r = requests.post(webhook_url, data={"payload": payload_json}, timeout=10)<br>    r.raise_for_status()def get_last_price_yf(ticker: str) -&gt; float:<br>    hist = yf.Ticker(ticker).history(period="7d")<br>    if hist is None or hist.empty:<br>        raise RuntimeError(f"가격 데이터 비어있음: {ticker}")<br>    return float(hist["Close"].iloc[-1])def get_adaptive_factor(cfg: dict, peak_profit_pct: float) -&gt; float:<br>    if not bool(cfg.get("adaptive_trailing_enabled", True)):<br>        return 1.0<br>    tiers = cfg.get("adaptive_trailing_factors", [])<br>    if not isinstance(tiers, list) or len(tiers) == 0:<br>        return 1.0    valid = []<br>    for t in tiers:<br>        try:<br>            m = float(t.get("min_profit_pct", 0))<br>            f = float(t.get("factor", 1.0))<br>            if f &gt; 0:<br>                valid.append((m, f))<br>        except:<br>            pass    if not valid:<br>        return 1.0    valid.sort(key=lambda x: x[0])<br>    chosen = valid[0][1]<br>    for m, f in valid:<br>        if peak_profit_pct &gt;= m:<br>            chosen = f<br>        else:<br>            break<br>    return chosendef effective_trailing_pct(cfg: dict, base_trailing_pct: float, entry_value: float, peak_value: float) -&gt; float:<br>    if entry_value &lt;= 0:<br>        return base_trailing_pct<br>    peak_profit_pct = (peak_value - entry_value) / entry_value * 100.0<br>    factor = get_adaptive_factor(cfg, peak_profit_pct)<br>    eff = base_trailing_pct * factor<br>    eff = max(eff, 0.01)<br>    eff = min(eff, base_trailing_pct)<br>    return effdef cleanup_state(state: dict, active_codes: set[str]):<br>    for k in list(state.keys()):<br>        if k in ("_summary", "_hourly_summary", "_startup", "_after_close_summary", "_reactivate"):<br>            continue<br>        if k not in active_codes:<br>            del state[k]def should_send_daily_summary(state: dict, now: datetime, summary_time: dtime) -&gt; bool:<br>    if now.time() &lt; summary_time:<br>        return False<br>    today = now.strftime("%Y-%m-%d")<br>    s = state.setdefault("_summary", {})<br>    return s.get("last_date") != todaydef should_send_hourly_summary_market_only(state: dict, now: datetime, interval_minutes: int, market_open: bool) -&gt; bool:<br>    if not market_open:<br>        return False<br>    hourly = state.setdefault("_hourly_summary", {})<br>    last_str = hourly.get("last_sent")<br>    if not last_str:<br>        return True<br>    last_dt = datetime.strptime(last_str, "%Y-%m-%d %H:%M:%S")<br>    diff_min = (now - last_dt).total_seconds() / 60.0<br>    return diff_min &gt;= interval_minutesdef should_send_after_close_summary(state: dict, now: datetime, summary_time: dtime) -&gt; bool:<br>    if now.time() &lt; summary_time:<br>        return False<br>    today = now.strftime("%Y-%m-%d")<br>    s = state.setdefault("_after_close_summary", {})<br>    return s.get("last_date") != todaydef should_send_startup_notify(state: dict) -&gt; bool:<br>    st = state.setdefault("_startup", {})<br>    return not bool(st.get("sent", False))def mark_startup_notify_sent(state: dict):<br>    st = state.setdefault("_startup", {})<br>    st["sent"] = True<br>    st["sent_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")def should_reactivate_today(state: dict, now: datetime, hhmm: str) -&gt; bool:<br>    t = parse_hhmm(hhmm)<br>    if now.time() &lt; t:<br>        return False<br>    today = now.strftime("%Y-%m-%d")<br>    s = state.setdefault("_reactivate", {})<br>    return s.get("last_date") != todaydef reactivate_all_positions(positions_all: list[Position], state: dict) -&gt; bool:<br>    changed = False<br>    for p in positions_all:<br>        if p.active == 0:<br>            p.active = 1<br>            changed = True<br>    if changed:<br>        state.setdefault("_reactivate", {})["last_date"] = datetime.now().strftime("%Y-%m-%d")<br>    return changeddef calc_risk_level(detail_list: list[dict], total_current_active: float, cfg: dict, near_dist: float) -&gt; dict:<br>    trigger = [d for d in detail_list if d.get("active") == 1 and d.get("to_stop", 999) &lt;= 0]<br>    near = [d for d in detail_list if d.get("active") == 1 and 0 &lt; d.get("to_stop", 999) &lt;= near_dist]    trigger_cnt = len(trigger)<br>    near_cnt = len(near)    risk_exposure = sum(float(d.get("cur", 0.0)) for d in (trigger + near))<br>    exposure_pct = (risk_exposure / total_current_active * 100.0) if total_current_active &gt; 0 else 0.0    high_near_cnt = int(cfg.get("risk_high_near_count", 3))<br>    high_exposure_pct = float(cfg.get("risk_high_near_exposure_pct", 30))    if trigger_cnt &gt; 0 or near_cnt &gt;= high_near_cnt or exposure_pct &gt;= high_exposure_pct:<br>        level = "HIGH"<br>    elif near_cnt &gt; 0:<br>        level = "MEDIUM"<br>    else:<br>        level = "LOW"    return {<br>        "level": level,<br>        "trigger_cnt": trigger_cnt,<br>        "near_cnt": near_cnt,<br>        "risk_exposure": risk_exposure,<br>        "exposure_pct": exposure_pct<br>    }def top_worst_lines(rows, n=3):<br>    rows_desc = sorted(rows, key=lambda r: r["rate_now"], reverse=True)[:n]<br>    rows_asc = sorted(rows, key=lambda r: r["rate_now"], reverse=False)[:n]    def line(r):<br>        sign = "+" if r["profit_now"] &gt;= 0 else ""<br>        return f"- {r['name']}({r['code']}): {r['rate_now']:+.2f}% ({sign}{fmt_money(r['profit_now'])}원)"    return [line(r) for r in rows_desc], [line(r) for r in rows_asc]def run_once(cfg: dict, positions_all: list[Position], state: dict):<br>    now = datetime.now()<br>    now_str = now.strftime("%Y-%m-%d %H:%M:%S")    webhook_url = cfg["synology_chat_webhook_url"]    market_open_t = parse_hhmm(cfg.get("market_open", "09:00"))<br>    market_close_t = parse_hhmm(cfg.get("market_close", "15:30"))<br>    daily_summary_t = parse_hhmm(cfg.get("daily_summary_time", "15:35"))    hourly_enabled = bool(cfg.get("hourly_summary_enabled", True))<br>    hourly_interval = int(cfg.get("hourly_summary_interval_minutes", 60))    auto_disable = bool(cfg.get("auto_disable_on_alert", True))    near_enabled = bool(cfg.get("near_alert_enabled", True))<br>    near_dist = float(cfg.get("near_alert_distance_pct", 2.0))<br>    near_cooldown = int(cfg.get("near_alert_cooldown_minutes", 60))    sl_near_enabled = bool(cfg.get("stoploss_near_enabled", True))<br>    sl_near_dist = float(cfg.get("stoploss_near_distance_pct", 2.0))<br>    sl_near_cooldown = int(cfg.get("stoploss_near_cooldown_minutes", 180))    after_close_enabled = bool(cfg.get("after_close_summary_enabled", True))<br>    after_close_time = parse_hhmm(cfg.get("after_close_summary_time", "16:00"))<br>    include_inactive = bool(cfg.get("after_close_include_inactive", False))    positions_active = [p for p in positions_all if p.active == 1]<br>    active_codes = {p.code for p in positions_active}<br>    cleanup_state(state, active_codes)    market_open = is_market_open(now, market_open_t, market_close_t)<br>    log("MARKET", f"장중={market_open}")    price_targets = positions_all if include_inactive else positions_active<br>    price_cache: dict[str, float] = {}    log("PRICE", f"조회 대상={len(price_targets)}")<br>    for p in price_targets:<br>        if p.code in price_cache:<br>            continue<br>        try:<br>            price_cache[p.code] = get_last_price_yf(p.ticker)<br>        except Exception as e:<br>            log("PRICE", f"FAIL {p.name}({p.code}) {e}", level="WARN")    positions_ok = [p for p in positions_active if p.code in price_cache]<br>    if not positions_ok:<br>        return False, "LOW", market_open    total_entry = total_current = total_peak = 0.0<br>    rows = []    for p in positions_ok:<br>        entry_value = p.qty * p.buy_price<br>        current_value = p.qty * price_cache[p.code]<br>        s = state.setdefault(p.code, {})        peak_value = float(s.get("peak_value", entry_value))<br>        if current_value &gt; peak_value:<br>            peak_value = current_value<br>        s["peak_value"] = peak_value        profit_now = current_value - entry_value<br>        rate_now = (profit_now / entry_value * 100.0) if entry_value else 0.0        total_entry += entry_value<br>        total_current += current_value<br>        total_peak += peak_value        rows.append({"code": p.code, "name": p.name, "profit_now": profit_now, "rate_now": rate_now})    total_profit_now = total_current - total_entry<br>    total_rate_now = (total_profit_now / total_entry * 100.0) if total_entry else 0.0    changed_positions = False<br>    if market_open:<br>        pos_map = {p.code: p for p in positions_all}        for p in positions_ok:<br>            entry_value = p.qty * p.buy_price<br>            current_value = p.qty * price_cache[p.code]<br>            s = state.setdefault(p.code, {})<br>            peak_value = float(s.get("peak_value", entry_value))            # 손절 근접 + 손절 트리거<br>            if p.stop_loss_pct &gt; 0:<br>                stop_loss_value = entry_value * (1 - p.stop_loss_pct)<br>                to_stoploss = (current_value - stop_loss_value) / stop_loss_value * 100.0 if stop_loss_value &gt; 0 else None                if sl_near_enabled and to_stoploss is not None and (0 &lt; to_stoploss &lt;= sl_near_dist):<br>                    ns = state.setdefault(p.code, {})<br>                    last_sl_near = ns.get("last_stoploss_near_alert_at")<br>                    can_send = True<br>                    if last_sl_near:<br>                        last_dt = datetime.strptime(last_sl_near, "%Y-%m-%d %H:%M:%S")<br>                        can_send = (now - last_dt).total_seconds() &gt;= sl_near_cooldown * 60<br>                    if can_send:<br>                        msg = (<br>                            f"[손절 근접 경고/매수가 -{int(p.stop_loss_pct*100)}%]\n"<br>                            f"- {p.name}({p.code})\n"<br>                            f"- 손절선까지 거리: {to_stoploss:+.2f}% (0% 이하이면 손절)\n"<br>                            f"- 최근가(지연 Close): {fmt_money(price_cache[p.code])}원\n"<br>                            f"- 손절선: {fmt_money(stop_loss_value)}원\n"<br>                            f"- 평가금액: {fmt_money(current_value)}원\n"<br>                            f"- 시각: {now_str}"<br>                        )<br>                        send_synology_chat(webhook_url, msg)<br>                        ns["last_stoploss_near_alert_at"] = now_str                stop_loss_triggered = current_value &lt;= stop_loss_value<br>                last_sl = s.get("last_stop_loss_alert_at")<br>                already_today = bool(last_sl and last_sl[:10] == now_str[:10])<br>                if stop_loss_triggered and not already_today:<br>                    msg = (<br>                        f"[손절 알림/매수가 -{int(p.stop_loss_pct*100)}%]\n"<br>                        f"- {p.name}({p.code})\n"<br>                        f"- 최근가(지연 Close): {fmt_money(price_cache[p.code])}원\n"<br>                        f"- 평가금액: {fmt_money(current_value)}원\n"<br>                        f"- 손절선: {fmt_money(stop_loss_value)}원\n"<br>                        f"- 매수금액: {fmt_money(entry_value)}원\n"<br>                        f"- 시각: {now_str}"<br>                    )<br>                    send_synology_chat(webhook_url, msg)<br>                    s["last_stop_loss_alert_at"] = now_str<br>                    if auto_disable and pos_map[p.code].active != 0:<br>                        pos_map[p.code].active = 0<br>                        changed_positions = True            # 트레일링 근접 + 트리거<br>            last_alerted_peak = float(s.get("last_alerted_peak", 0))<br>            if peak_value &gt; entry_value:<br>                eff_trailing = effective_trailing_pct(cfg, p.trailing_pct, entry_value, peak_value)<br>                stop_value = peak_value * (1 - eff_trailing)<br>                to_stop = (current_value - stop_value) / stop_value * 100.0<br>                drop_from_peak = (peak_value - current_value) / peak_value * 100.0<br>                triggered = current_value &lt;= stop_value                if near_enabled and (0 &lt; to_stop &lt;= near_dist):<br>                    ns = state.setdefault(p.code, {})<br>                    last_near = ns.get("last_near_alert_at")<br>                    can_send = True<br>                    if last_near:<br>                        last_dt = datetime.strptime(last_near, "%Y-%m-%d %H:%M:%S")<br>                        can_send = (now - last_dt).total_seconds() &gt;= near_cooldown * 60<br>                    if can_send:<br>                        msg = (<br>                            f"[근접 경고/트레일링 {int(eff_trailing*100)}%]\n"<br>                            f"- {p.name}({p.code})\n"<br>                            f"- 기준선까지 거리: {to_stop:+.2f}% (0% 이하이면 트리거)\n"<br>                            f"- 피크 대비 하락률: {drop_from_peak:.2f}%\n"<br>                            f"- 최근가(지연 Close): {fmt_money(price_cache[p.code])}원\n"<br>                            f"- 시각: {now_str}"<br>                        )<br>                        send_synology_chat(webhook_url, msg)<br>                        ns["last_near_alert_at"] = now_str                if triggered and last_alerted_peak &lt; peak_value:<br>                    msg = (<br>                        f"[매도 알림/트레일링 {int(eff_trailing*100)}%]\n"<br>                        f"- {p.name}({p.code})\n"<br>                        f"- 기준선까지 거리: {to_stop:+.2f}% (트리거)\n"<br>                        f"- 피크 대비 하락률: {drop_from_peak:.2f}%\n"<br>                        f"- 최근가(지연 Close): {fmt_money(price_cache[p.code])}원\n"<br>                        f"- 시각: {now_str}"<br>                    )<br>                    send_synology_chat(webhook_url, msg)<br>                    s["last_alerted_peak"] = peak_value<br>                    if auto_disable and pos_map[p.code].active != 0:<br>                        pos_map[p.code].active = 0<br>                        changed_positions = True    # 리스크/리포트용 상세 리스트<br>    positions_for_report = positions_all if include_inactive else positions_active<br>    detail_list = []<br>    for p in positions_for_report:<br>        if p.code not in price_cache:<br>            continue<br>        entry_value = p.qty * p.buy_price<br>        current_value = p.qty * price_cache[p.code]<br>        s = state.get(p.code, {})<br>        peak_value = float(s.get("peak_value", entry_value))<br>        eff_trailing = effective_trailing_pct(cfg, p.trailing_pct, entry_value, peak_value) if peak_value &gt; entry_value else p.trailing_pct<br>        stop_value = peak_value * (1 - eff_trailing) if peak_value else 0.0<br>        to_stop = (current_value - stop_value) / stop_value * 100.0 if stop_value else 0.0        stop_loss_value = entry_value * (1 - p.stop_loss_pct) if p.stop_loss_pct &gt; 0 else 0.0<br>        to_stoploss = (current_value - stop_loss_value) / stop_loss_value * 100.0 if stop_loss_value &gt; 0 else None        profit_now = current_value - entry_value<br>        rate_now = (profit_now / entry_value * 100.0) if entry_value else 0.0        detail_list.append({<br>            "name": p.name, "code": p.code, "active": p.active,<br>            "cur": current_value, "entry": entry_value,<br>            "profit": profit_now, "rate": rate_now,<br>            "peak": peak_value, "eff_trailing": eff_trailing,<br>            "stop": stop_value, "to_stop": to_stop,<br>            "stop_loss_pct": p.stop_loss_pct, "stop_loss_value": stop_loss_value, "to_stoploss": to_stoploss<br>        })    risk = calc_risk_level(detail_list, total_current, cfg, near_dist)    # 장중 1시간 요약<br>    if bool(cfg.get("hourly_summary_enabled", True)):<br>        if should_send_hourly_summary_market_only(state, now, int(cfg.get("hourly_summary_interval_minutes", 60)), market_open):<br>            lines = []<br>            for r in rows:<br>                sign = "+" if r["profit_now"] &gt;= 0 else ""<br>                lines.append(f"- {r['name']}({r['code']}): {r['rate_now']:+.2f}% ({sign}{fmt_money(r['profit_now'])}원)")            risk_box = (<br>                f"[리스크 레벨: {risk['level']}]\n"<br>                f"- Trigger: {risk['trigger_cnt']} / Near: {risk['near_cnt']}\n"<br>                f"- 위험노출: {fmt_money(risk['risk_exposure'])}원 ({risk['exposure_pct']:.1f}%)\n"<br>            )            msg = (<br>                f"[1시간 포트폴리오 요약]\n"<br>                f"- 총 손익: {fmt_money(total_profit_now)}원\n"<br>                f"- 총 수익률: {total_rate_now:+.2f}%\n\n"<br>                + risk_box + "\n"<br>                + "\n".join(lines) +<br>                f"\n\n- 시각: {now_str}"<br>            )<br>            send_synology_chat(webhook_url, msg)<br>            state.setdefault("_hourly_summary", {})["last_sent"] = now_str    # 15:35 일일 요약<br>    if should_send_daily_summary(state, now, daily_summary_t):<br>        total_profit_peak = total_peak - total_entry<br>        total_rate_peak = (total_profit_peak / total_entry * 100.0) if total_entry else 0.0<br>        top3, worst3 = top_worst_lines(rows, n=3)        msg = (<br>            f"[포트폴리오 일일 요약]\n"<br>            f"- 총 매수금액: {fmt_money(total_entry)}원\n"<br>            f"- 총 평가금액(현재): {fmt_money(total_current)}원\n"<br>            f"- 총 손익(현재): {fmt_money(total_profit_now)}원 ({total_rate_now:+.2f}%)\n"<br>            f"- 총 최고평가(피크): {fmt_money(total_peak)}원\n"<br>            f"- 총 손익(피크): {fmt_money(total_profit_peak)}원 ({total_rate_peak:+.2f}%)\n"<br>            f"\n[손익률 TOP3]\n" + "\n".join(top3) +<br>            f"\n\n[손익률 WORST3]\n" + "\n".join(worst3) +<br>            f"\n\n- 시각: {now_str}"<br>        )<br>        send_synology_chat(webhook_url, msg)<br>        state.setdefault("_summary", {})["last_date"] = now.strftime("%Y-%m-%d")    # 16:00 리포트(섹션 분리)<br>    if bool(cfg.get("after_close_summary_enabled", True)) and should_send_after_close_summary(state, now, after_close_time):<br>        trigger = [d for d in detail_list if d["active"] == 1 and d["to_stop"] &lt;= 0]<br>        near = [d for d in detail_list if d["active"] == 1 and 0 &lt; d["to_stop"] &lt;= near_dist]<br>        safe = [d for d in detail_list if d["active"] == 1 and d["to_stop"] &gt; near_dist]        def line(d):<br>            a = "A1" if d["active"] == 1 else "A0"<br>            sl_part = ""<br>            if d["stop_loss_pct"] &gt; 0 and d["to_stoploss"] is not None:<br>                sl_part = f" / to_SL={d['to_stoploss']:+.2f}%(-{int(d['stop_loss_pct']*100)}%)"<br>            sign = "+" if d["profit"] &gt;= 0 else ""<br>            return (<br>                f"- {d['name']}({d['code']})[{a}] to_stop={d['to_stop']:+.2f}%{sl_part}\n"<br>                f"  cur={fmt_money(d['cur'])} stop={fmt_money(d['stop'])} eff_trailing={int(d['eff_trailing']*100)}% "<br>                f"pnl={sign}{fmt_money(d['profit'])}원 ({d['rate']:+.2f}%)"<br>            )        risk_box = (<br>            f"[리스크 레벨: {risk['level']}]\n"<br>            f"- Trigger: {risk['trigger_cnt']} / Near: {risk['near_cnt']}\n"<br>            f"- 위험노출: {fmt_money(risk['risk_exposure'])}원 ({risk['exposure_pct']:.1f}%)\n"<br>        )        msg = (<br>            f"[16:00 리포트/기준선+손절+리스크]\n"<br>            f"- 총 손익(active=1): {fmt_money(total_profit_now)}원\n"<br>            f"- 총 수익률(active=1): {total_rate_now:+.2f}%\n"<br>            f"- 설명: to_stop=+X%는 트레일 기준선까지 남은 비율(0% 이하 트리거)\n"<br>            f"- 설명: to_SL=+X%는 손절선까지 남은 비율(0% 이하 손절)\n\n"<br>            + risk_box + "\n"<br>            + "🚨 TRIGGER\n" + ("\n".join(line(d) for d in trigger) if trigger else "- 없음") + "\n\n"<br>            + f"⚠️ NEAR (&lt;= {near_dist:.1f}%)\n" + ("\n".join(line(d) for d in near) if near else "- 없음") + "\n\n"<br>            + "✅ SAFE\n" + ("\n".join(line(d) for d in safe) if safe else "- 없음") +<br>            f"\n\n- 시각: {now_str}"<br>        )<br>        send_synology_chat(webhook_url, msg)<br>        state.setdefault("_after_close_summary", {})["last_date"] = now.strftime("%Y-%m-%d")    if changed_positions:<br>        save_positions_csv_atomic(POSITIONS_PATH, positions_all)    return changed_positions, risk["level"], market_opendef main():<br>    cfg = load_json_safe(CONFIG_PATH, {})<br>    if not cfg:<br>        raise RuntimeError("config.json이 없습니다.")    default_trailing_pct = float(cfg.get("default_trailing_pct", 0.10))<br>    default_stop_loss_pct = float(cfg.get("default_stop_loss_pct", 0.08))    state = load_json_safe(STATE_PATH, {})    if bool(cfg.get("startup_notify_enabled", True)) and should_send_startup_notify(state):<br>        try:<br>            positions_all = load_positions_csv(POSITIONS_PATH, default_trailing_pct, default_stop_loss_pct)<br>            active_positions = [p for p in positions_all if p.active == 1]<br>            lines = [<br>                f"- {p.name}({p.code}.{p.market}) qty={p.qty:g} buy={fmt_money(p.buy_price)} "<br>                f"trail={int(p.trailing_pct*100)}% sl={int(p.stop_loss_pct*100)}%"<br>                for p in active_positions<br>            ]<br>            msg = "[주식 알림봇 시작]\n" + "\n".join(lines) + f"\n- 시각: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"<br>            send_synology_chat(cfg["synology_chat_webhook_url"], msg)<br>            mark_startup_notify_sent(state)<br>            save_json_atomic(STATE_PATH, state)<br>        except Exception as e:<br>            log("STARTUP", f"시작 안내 실패: {e}", level="WARN")    while True:<br>        now = datetime.now()<br>        try:<br>            positions_all = load_positions_csv(POSITIONS_PATH, default_trailing_pct, default_stop_loss_pct)            if bool(cfg.get("daily_reactivate_enabled", True)):<br>                if should_reactivate_today(state, now, cfg.get("daily_reactivate_time", "09:01")):<br>                    if reactivate_all_positions(positions_all, state):<br>                        save_positions_csv_atomic(POSITIONS_PATH, positions_all)<br>                        save_json_atomic(STATE_PATH, state)            changed, risk_level, market_open = run_once(cfg, positions_all, state)<br>            save_json_atomic(STATE_PATH, state)            sleep_min = int(cfg.get("interval_minutes_market", 30))<br>            if bool(cfg.get("adaptive_interval_enabled", True)):<br>                mkt_min = int(cfg.get("interval_minutes_market", sleep_min))<br>                high_min = int(cfg.get("interval_minutes_high_risk", 10))<br>                off_min = int(cfg.get("interval_minutes_off_market", 120))<br>                sleep_min = (high_min if risk_level == "HIGH" else mkt_min) if market_open else off_min            log("SLEEP", f"{sleep_min}분 후 재실행 (risk={risk_level}, market_open={market_open})")<br>            time.sleep(sleep_min * 60)        except Exception as e:<br>            log("ERROR", f"루프 오류: {e}", level="ERROR")<br>            time.sleep(120)if __name__ == "__main__":<br>    main()</pre>



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



<h1 class="wp-block-heading">8) 실행(백그라운드)</h1>



<pre class="wp-block-preformatted">cd ~/python/jusik_top10<br>nohup python3.9 main.py &gt; jusik.log 2&gt;&amp;1 &amp;<br>tail -f jusik.log</pre>



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



<h1 class="wp-block-heading">9) 운영 팁</h1>



<ul class="wp-block-list">
<li><code>positions.csv</code>에서 <code>active=0</code>으로 수동 비활성화 가능</li>



<li>손절/트레일링 트리거 후 <code>auto_disable_on_alert=true</code>면 자동으로 active=0</li>



<li>다음날 <code>09:01</code>에 자동으로 active=1 복구 (옵션)</li>
</ul>



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



<h1 class="wp-block-heading">10) 트러블슈팅</h1>



<h3 class="wp-block-heading">✅ config.json이 없습니다</h3>



<ul class="wp-block-list">
<li><code>main.py</code>와 같은 폴더에 <code>config.json</code>이 있는지 확인</li>
</ul>



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



<h3 class="wp-block-heading">✅ state.json JSONDecodeError(Extra data)</h3>



<ul class="wp-block-list">
<li>파일이 깨진 것 → <code>{}</code>로 초기화</li>
</ul>



<pre class="wp-block-preformatted">cp state.json state.json.bak<br>echo "{}" &gt; state.json</pre>



<h3 class="wp-block-heading">✅ 알림이 안 오면</h3>



<ul class="wp-block-list">
<li>webhook URL 오타/토큰 확인</li>



<li>방화벽/SSL 문제 여부 확인</li>



<li>logs 확인</li>
</ul>



<pre class="wp-block-preformatted">tail -n 200 jusik.log<br></pre>
<p>게시물 <a href="https://howinfo.kr/orange-pi-5%eb%a1%9c-%ec%a3%bc%ec%8b%9d-etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%86%90%ec%a0%88-%eb%a6%ac%ec%8a%a4%ed%81%ac-%eb%a0%88%eb%b2%a8-%ec%95%8c/">Orange Pi 5로 “주식/ETF 트레일링 스탑 + 손절 + 리스크 레벨” 알림봇 만들기 (Synology Chat 웹훅, 10~30분 자동 주기)_버전 두번째 full 소스</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/orange-pi-5%eb%a1%9c-%ec%a3%bc%ec%8b%9d-etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%86%90%ec%a0%88-%eb%a6%ac%ec%8a%a4%ed%81%ac-%eb%a0%88%eb%b2%a8-%ec%95%8c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>오렌지파이5로 주식·ETF 트레일링 스탑 알림 시스템 만들기</title>
		<link>https://howinfo.kr/%ec%98%a4%eb%a0%8c%ec%a7%80%ed%8c%8c%ec%9d%b45%eb%a1%9c-%ec%a3%bc%ec%8b%9d%c2%b7etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%95%8c%eb%a6%bc-%ec%8b%9c%ec%8a%a4%ed%85%9c-%eb%a7%8c/</link>
					<comments>https://howinfo.kr/%ec%98%a4%eb%a0%8c%ec%a7%80%ed%8c%8c%ec%9d%b45%eb%a1%9c-%ec%a3%bc%ec%8b%9d%c2%b7etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%95%8c%eb%a6%bc-%ec%8b%9c%ec%8a%a4%ed%85%9c-%eb%a7%8c/#respond</comments>
		
		<dc:creator><![CDATA[hong]]></dc:creator>
		<pubDate>Wed, 25 Feb 2026 02:53:59 +0000</pubDate>
				<category><![CDATA[개발·코딩]]></category>
		<category><![CDATA[etf 자동화]]></category>
		<category><![CDATA[Synology chat webhook]]></category>
		<category><![CDATA[Trailing stop]]></category>
		<category><![CDATA[시놀로지 챗 웹훅]]></category>
		<category><![CDATA[알림봇]]></category>
		<category><![CDATA[오렌지파이5]]></category>
		<category><![CDATA[주식 자동화]]></category>
		<category><![CDATA[주식알림시스템]]></category>
		<category><![CDATA[트레일링 스탑]]></category>
		<guid isPermaLink="false">https://howinfo.kr/?p=2098</guid>

					<description><![CDATA[<p>(Synology Chat 웹훅 + 종목별 트레일링% 설정 + 일일 요약 포함) 주식을 하다 보면 이런 생각이 듭니다. “최고 수익에서 10%만...</p>
<p>게시물 <a href="https://howinfo.kr/%ec%98%a4%eb%a0%8c%ec%a7%80%ed%8c%8c%ec%9d%b45%eb%a1%9c-%ec%a3%bc%ec%8b%9d%c2%b7etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%95%8c%eb%a6%bc-%ec%8b%9c%ec%8a%a4%ed%85%9c-%eb%a7%8c/">오렌지파이5로 주식·ETF 트레일링 스탑 알림 시스템 만들기</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">(Synology Chat 웹훅 + 종목별 트레일링% 설정 + 일일 요약 포함)</h3>



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



<h1 class="wp-block-heading">주식을 하다 보면 이런 생각이 듭니다.</h1>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>“최고 수익에서 10%만 빠지면 정리하고 싶은데…<br>내가 계속 보고 있을 수는 없잖아?”</p>
</blockquote>



<p>그래서 오렌지파이5에 <strong>상시 감시용 트레일링 알림 시스템</strong>을 만들었습니다.</p>



<p>✔ 일반주식 + ETF 모두 가능<br>✔ 종목별로 트레일링 % 다르게 설정<br>✔ 장중에만 매도 알림<br>✔ 장마감 후 하루 1번 요약<br>✔ 매도 알림 발생 시 자동 감시 해제</p>



<p>이 글에서는 <strong>실제 운영 가능한 코드 구조</strong>를 정리합니다.</p>



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



<h1 class="wp-block-heading">🧠 시스템 구조</h1>



<pre class="wp-block-preformatted">positions.csv   → 보유 종목 관리<br>config.json     → 시스템 설정<br>state.json      → 종목별 최고 수익(peak) 저장<br>main.py         → 전체 로직 실행</pre>



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



<h1 class="wp-block-heading">📊 핵심 로직 (트레일링 스탑)</h1>



<h3 class="wp-block-heading">1️⃣ 기본 계산</h3>



<pre class="wp-block-preformatted">entry_value   = 매수수량 × 매수가<br>current_value = 매수수량 × 현재가<br>peak_value    = max(기존 peak_value, current_value)</pre>



<h3 class="wp-block-heading">2️⃣ 트레일링 기준선</h3>



<pre class="wp-block-preformatted">stop_value = peak_value × (1 - trailing_pct)</pre>



<h3 class="wp-block-heading">3️⃣ 매도 알림 조건</h3>



<pre class="wp-block-preformatted">수익 구간에서만 적용<br>current_value &lt;= stop_value 이면 알림</pre>



<p>✔ 계속 오르면 peak가 올라감<br>✔ 기준선도 같이 올라감<br>✔ 최고점 대비 n% 하락 시 알림</p>



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



<h1 class="wp-block-heading">🗂 1️⃣ 보유 종목 파일 (positions.csv)</h1>



<pre class="wp-block-preformatted">code,name,market,qty,buy_price,trailing_pct,active<br>005930,삼성전자,KS,10,70000,0.10,1<br>069500,KODEX 200,KS,20,35000,0.08,1<br>035420,NAVER,KS,3,200000,0.12,1</pre>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>컬럼</th><th>설명</th></tr></thead><tbody><tr><td>code</td><td>6자리 종목코드</td></tr><tr><td>market</td><td>KS(코스피/ETF), KQ(코스닥)</td></tr><tr><td>qty</td><td>수량</td></tr><tr><td>buy_price</td><td>매수가</td></tr><tr><td>trailing_pct</td><td>종목별 트레일링 비율</td></tr><tr><td>active</td><td>1=감시, 0=감시중지</td></tr></tbody></table></figure>



<p>✔ 매도 알림 발생 시 active=0 자동 변경</p>



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



<h1 class="wp-block-heading">⚙ 2️⃣ 설정 파일 (config.json)</h1>



<pre class="wp-block-preformatted">{<br>  "interval_minutes": 30,<br>  "default_trailing_pct": 0.10,<br>  "synology_chat_webhook_url": "웹훅URL",  "market_open": "09:00",<br>  "market_close": "15:30",  "daily_summary_time": "15:35",  "auto_disable_on_alert": true<br>}</pre>



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



<h1 class="wp-block-heading">🖥 3️⃣ 오렌지파이5 설치</h1>



<pre class="wp-block-preformatted">python3 -m pip install --upgrade pip<br>python3 -m pip install yfinance requests</pre>



<p>✔ ARM 환경에서 가장 안정적<br>✔ FinanceDataReader 대신 yfinance 사용</p>



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



<h1 class="wp-block-heading">🧾 4️⃣ 전체 실행 코드 (주석 상세 버전)</h1>



<p>아래는 핵심 구조가 잘 보이도록 정리한 “설명형 소스”입니다.</p>



<pre class="wp-block-preformatted">"""<br>OrangePi5 트레일링 스탑 알림 시스템<br>- 주식 + ETF 지원<br>- 종목별 trailing_pct 적용<br>- 장중만 매도 알림<br>- 하루 1회 요약<br>- 매도 발생 시 active=0 자동 변경<br>"""import os<br>import json<br>import time<br>import csv<br>from datetime import datetime, timedelta, time as dtime<br>import requests<br>import yfinance as yf# -------------------------<br># 기본 경로 설정<br># -------------------------<br>BASE = os.path.dirname(os.path.abspath(__file__))<br>CONFIG_PATH = os.path.join(BASE, "config.json")<br>POSITIONS_PATH = os.path.join(BASE, "positions.csv")<br>STATE_PATH = os.path.join(BASE, "state.json")# -------------------------<br># 유틸 함수<br># -------------------------<br>def log(msg):<br>    print(f"[{datetime.now()}] {msg}")def fmt(x):<br>    return f"{x:,.0f}"def parse_hhmm(s):<br>    h, m = s.split(":")<br>    return dtime(int(h), int(m))# -------------------------<br># Synology Chat 알림<br># -------------------------<br>def send_chat(url, text):<br>    payload = json.dumps({"text": text}, ensure_ascii=False)<br>    requests.post(url, data={"payload": payload})# -------------------------<br># 가격 조회 (yfinance)<br># -------------------------<br>def get_price(code, market):<br>    ticker = f"{code}.{market}"<br>    hist = yf.Ticker(ticker).history(period="7d")<br>    return float(hist["Close"].iloc[-1])# -------------------------<br># 메인 실행<br># -------------------------<br>def main():<br>    config = json.load(open(CONFIG_PATH))<br>    state = json.load(open(STATE_PATH)) if os.path.exists(STATE_PATH) else {}    open_t = parse_hhmm(config["market_open"])<br>    close_t = parse_hhmm(config["market_close"])<br>    summary_t = parse_hhmm(config["daily_summary_time"])    while True:<br>        now = datetime.now()        # positions 읽기<br>        positions = list(csv.DictReader(open(POSITIONS_PATH, encoding="utf-8-sig")))<br>        positions = [p for p in positions if p.get("active","1") == "1"]        total_entry = total_current = total_peak = 0<br>        rows = []        for p in positions:<br>            code = p["code"]<br>            market = p.get("market","KS")<br>            qty = float(p["qty"])<br>            buy = float(p["buy_price"])<br>            trailing = float(p.get("trailing_pct") or config["default_trailing_pct"])            price = get_price(code, market)            entry = qty * buy<br>            current = qty * price            peak = state.get(code, {}).get("peak", entry)<br>            peak = max(peak, current)            state.setdefault(code, {})["peak"] = peak            # 트레일링 조건<br>            if open_t &lt;= now.time() &lt;= close_t:<br>                stop = peak * (1 - trailing)<br>                if current &lt;= stop:<br>                    send_chat(config["synology_chat_webhook_url"],<br>                              f"[매도 알림] {p['name']} 최고대비 {int(trailing*100)}% 하락")<br>                    if config["auto_disable_on_alert"]:<br>                        p["active"] = "0"            total_entry += entry<br>            total_current += current<br>            total_peak += peak            rows.append((p["name"], (current-entry)/entry*100))        # 하루 1회 요약<br>        if now.time() &gt;= summary_t:<br>            if state.get("summary_date") != now.strftime("%Y-%m-%d"):<br>                profit = total_current - total_entry<br>                send_chat(config["synology_chat_webhook_url"],<br>                          f"[일일 요약] 총 손익 {fmt(profit)}원")<br>                state["summary_date"] = now.strftime("%Y-%m-%d")        json.dump(state, open(STATE_PATH,"w"), indent=2)        log("루프 완료. 다음 실행 대기...")<br>        time.sleep(config["interval_minutes"]*60)if __name__ == "__main__":<br>    main()</pre>



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



<h1 class="wp-block-heading">📈 실행 중 로그 예시</h1>



<pre class="wp-block-preformatted">[2026-02-25 10:00] 가격 조회 시작<br>[2026-02-25 10:00] 삼성전자 peak 갱신<br>[2026-02-25 10:00] 트레일링 체크 완료<br>[2026-02-25 10:00] 루프 완료. 다음 실행 대기...</pre>



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



<h1 class="wp-block-heading">📌 운영하면서 느낀 점</h1>



<ul class="wp-block-list">
<li>지연 시세 기반이라 실시간 체결가 기반은 아님</li>



<li>그러나 구조 테스트 및 자동 감시 시스템에는 충분</li>



<li>실시간으로 확장하려면 가격 조회 부분만 API로 교체하면 됨</li>
</ul>



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



<h1 class="wp-block-heading">🚀 다음 확장 방향</h1>



<ul class="wp-block-list">
<li>증권사 API 연동</li>



<li>텔레그램/카카오톡 알림 추가</li>



<li>Streamlit 대시보드 추가</li>



<li>매수 전략 자동화</li>
</ul>



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



<h1 class="wp-block-heading">🧩 결론</h1>



<p>이 시스템은</p>



<p>✔ 오렌지파이5 같은 저전력 장비에 적합<br>✔ 구조가 단순해서 유지보수 쉬움<br>✔ 나중에 실시간 API로 확장 가능</p>



<p>입니다.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="855" height="433" src="https://howinfo.kr/wp-content/uploads/2026/02/sychat.png" alt="" class="wp-image-2102" srcset="https://howinfo.kr/wp-content/uploads/2026/02/sychat.png 855w, https://howinfo.kr/wp-content/uploads/2026/02/sychat-300x152.png 300w, https://howinfo.kr/wp-content/uploads/2026/02/sychat-768x389.png 768w" sizes="auto, (max-width: 855px) 100vw, 855px" /></figure>
<p>게시물 <a href="https://howinfo.kr/%ec%98%a4%eb%a0%8c%ec%a7%80%ed%8c%8c%ec%9d%b45%eb%a1%9c-%ec%a3%bc%ec%8b%9d%c2%b7etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%95%8c%eb%a6%bc-%ec%8b%9c%ec%8a%a4%ed%85%9c-%eb%a7%8c/">오렌지파이5로 주식·ETF 트레일링 스탑 알림 시스템 만들기</a>이 <a href="https://howinfo.kr">하우인포-IT·테크</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://howinfo.kr/%ec%98%a4%eb%a0%8c%ec%a7%80%ed%8c%8c%ec%9d%b45%eb%a1%9c-%ec%a3%bc%ec%8b%9d%c2%b7etf-%ed%8a%b8%eb%a0%88%ec%9d%bc%eb%a7%81-%ec%8a%a4%ed%83%91-%ec%95%8c%eb%a6%bc-%ec%8b%9c%ec%8a%a4%ed%85%9c-%eb%a7%8c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
