<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>randommagic 님의 블로그</title>
    <link>https://randommagic.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 31 May 2026 09:56:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>randommagic</managingEditor>
    <image>
      <title>randommagic 님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/7194507/attach/3864fa08dd754cdba49a997727e895f4</url>
      <link>https://randommagic.tistory.com</link>
    </image>
    <item>
      <title>Rclone - CloudFlare R2에서 AWS S3로 파일 이전</title>
      <link>https://randommagic.tistory.com/11</link>
      <description>&lt;p data-end=&quot;285&quot; data-start=&quot;49&quot; data-ke-size=&quot;size16&quot;&gt;기존에는 파일을 AWS S3에 저장하고 있었지만, Egress 요금 부담을 줄이기 위해 Cloudflare R2를 도입해 보기로 했다.&lt;br /&gt;S3에 저장되어 있던 파일들을 R2로 이전하는 과정에서는 Cloudflare에서 제공하는 &lt;b&gt;&lt;a href=&quot;https://developers.cloudflare.com/r2/data-migration/sippy/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;On Demand Migration&lt;/a&gt; (Sippy)&lt;/b&gt; 기능을 활용했다. (참고로, Cloudflare의 Data Migration 서비스도 고려했지만, 계속 오류가 발생해서 사용하지 못했다.)&lt;/p&gt;
&lt;p data-end=&quot;373&quot; data-start=&quot;287&quot; data-ke-size=&quot;size16&quot;&gt;그런데 내부적인 사정으로 인해 다시 파일 저장소를 R2에서 S3로 되돌려야 하는 상황이 발생했고, 결국 R2에 저장된 파일들을 다시 S3로 옮기게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 R2 공식 문서를 읽어봐도 S3-&amp;gt; R2 파일 이전 방법 또는 S3 API에 대해 사용 방법에 대해서는 나와 있었지만, 다시 이 파일들을 S3로 옮기는 방법에 대해서는 찾지 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 수백수천개 쌓인 파일들을 직접 하나하나 다운받아서 S3에 올릴수는 없는 노릇이라 웹을 더 뒤진 결과.. &lt;b&gt;RClone&lt;/b&gt; 이라는 오픈소스 툴을 찾게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qfl71/btsNSaUrrK9/L5KOKp4HlKXKgGiRdoQoAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qfl71/btsNSaUrrK9/L5KOKp4HlKXKgGiRdoQoAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qfl71/btsNSaUrrK9/L5KOKp4HlKXKgGiRdoQoAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqfl71%2FbtsNSaUrrK9%2FL5KOKp4HlKXKgGiRdoQoAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;285&quot; height=&quot;80&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;https://rclone.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RClone&lt;/a&gt;&lt;/b&gt; 은 다양한 클라우드 저장소 간의 파일 이동, 복사, 동기화 등을 지원하는 명령줄 기반의 툴로, S3, R2, Google Drive 등 70가지가 넘는 스토리지 서비스를 지원하고, 특히 대용량 데이터 이전이나 자동화된 작업에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.. 고 하니 써보기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. R2 준비&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FSEPm/btsNRFG8vN8/PZmjJLepW1H04Wvxjt90rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FSEPm/btsNRFG8vN8/PZmjJLepW1H04Wvxjt90rk/img.png&quot; data-alt=&quot;R2 버킷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FSEPm/btsNRFG8vN8/PZmjJLepW1H04Wvxjt90rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFSEPm%2FbtsNRFG8vN8%2FPZmjJLepW1H04Wvxjt90rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;495&quot; height=&quot;194&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;R2 버킷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 R2 버킷을 준비하였고, 4개의 파일들이 들어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버킷의 설정 - General 메뉴에 들어가자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7jOX/btsNQOrvowb/3taQ3ioezkqUrzT0zbWLNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7jOX/btsNQOrvowb/3taQ3ioezkqUrzT0zbWLNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7jOX/btsNQOrvowb/3taQ3ioezkqUrzT0zbWLNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7jOX%2FbtsNQOrvowb%2F3taQ3ioezkqUrzT0zbWLNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;687&quot; height=&quot;186&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 API&lt;/b&gt;가 &lt;a href=&quot;https://~~~~.r2.cloudflarestorage.com/버킷명&quot;&gt;https://~~~~.r2.cloudflarestorage.com/버킷명&lt;/a&gt; 되어 있을 텐데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤의 /버킷명&amp;nbsp; 을 제거하고&amp;nbsp; &amp;nbsp;https://~~~.r2.cloudflarestorage.com&amp;nbsp; &amp;nbsp;부분만 따로 메모장 등에 복사해 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xCvAR/btsNSk3l26z/6S4ORb2hbCzYbVXHLAs78K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xCvAR/btsNSk3l26z/6S4ORb2hbCzYbVXHLAs78K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xCvAR/btsNSk3l26z/6S4ORb2hbCzYbVXHLAs78K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxCvAR%2FbtsNSk3l26z%2F6S4ORb2hbCzYbVXHLAs78K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;714&quot; height=&quot;235&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;R2 API Key&lt;/b&gt;를 생성해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;R2 메뉴에서 API -&amp;gt; API 토큰 관리 -&amp;gt; Account API 토큰 생성 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;1147&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvTa67/btsNQXuyGnr/I69YVKNQxjik0BazwmFxj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvTa67/btsNQXuyGnr/I69YVKNQxjik0BazwmFxj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvTa67/btsNQXuyGnr/I69YVKNQxjik0BazwmFxj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvTa67%2FbtsNQXuyGnr%2FI69YVKNQxjik0BazwmFxj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;607&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;1147&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;적당한 이름으로 설정하고, 권한은 개체 읽기 전용으로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(만약 R2 버킷이 source가 아닌 target 일 경우 개체 읽기 및 쓰기로 해야 하겠다. 하지만 나는 R2에서 파일을 가져오기만 할 것이기 때문에 읽기 전용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;버킷도 옮길 대상이 되는 버킷을 설정하거나, 혹은 그냥 모든 버킷에 적용을 선택해도 무방하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm6zN7/btsNSBDJVz9/KOIer35iMKlHPocGK9RZC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm6zN7/btsNSBDJVz9/KOIer35iMKlHPocGK9RZC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm6zN7/btsNSBDJVz9/KOIer35iMKlHPocGK9RZC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm6zN7%2FbtsNSBDJVz9%2FKOIer35iMKlHPocGK9RZC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;367&quot; height=&quot;167&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그러면 &lt;b&gt;Access Key ID&lt;/b&gt; 와 &lt;b&gt;Secret Access Key &lt;/b&gt;가 나오는데&lt;b&gt;,&amp;nbsp;&lt;/b&gt;다시 보여주지 않으므로 안전한 곳에 따로 저장해 둘것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. S3 준비&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3도 파일이 복사될 버킷을 미리 생성해 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;R2에서 API Key를 생성했던것 처럼, S3도 그에 접근 권한이 있는 &lt;b&gt;Key&lt;/b&gt;를 생성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 IAM &lt;b&gt;정책 생성&lt;/b&gt; 부터.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 콘솔에 접속 후 IAM -&amp;gt; 정책 -&amp;gt; 정책 생성 메뉴로 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정책 편집기 우상단의 (시각적|JSON)&amp;nbsp; 중 JSON 버튼을 눌러 다음과 같이 설정해 주자.&lt;/p&gt;
&lt;pre id=&quot;code_1746774435837&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;s3:PutObject&quot;,
                &quot;s3:GetObject&quot;,
                &quot;s3:DeleteObject&quot;,
                &quot;s3:ListBucket&quot;
            ],
            &quot;Resource&quot;: [
                &quot;arn:aws:s3:::버킷이름/*&quot;,
                &quot;arn:aws:s3:::버킷이름&quot;
            ]
        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 이름은 식별할수 있는 이름으로 정한 후 정책 생성 버튼을 눌러 완료.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정책을 생성했으니 이제 이 정책을 사용할 &lt;b&gt;사용자&lt;/b&gt;를 생성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 콘솔 에서&amp;nbsp; IAM -&amp;gt; 사용자 -&amp;gt; 사용자 생성 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eu0lzE/btsNRDP6Tkq/ChUa99uFlWt5NosCHrTO81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eu0lzE/btsNRDP6Tkq/ChUa99uFlWt5NosCHrTO81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eu0lzE/btsNRDP6Tkq/ChUa99uFlWt5NosCHrTO81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feu0lzE%2FbtsNRDP6Tkq%2FChUa99uFlWt5NosCHrTO81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;455&quot; height=&quot;108&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 이름 정도에 적당한 이름을 넣어주고 다음으로 넘어가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TpnxS/btsNQybbYV4/UyY7sVw8RfsbcFcwkEYci0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TpnxS/btsNQybbYV4/UyY7sVw8RfsbcFcwkEYci0/img.png&quot; data-alt=&quot;물론 여기 설명대로 사용자를 그룹에 넣고 그룹&amp;amp;lt;-&amp;amp;gt;권한 연결 해도 될 것 같다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TpnxS/btsNQybbYV4/UyY7sVw8RfsbcFcwkEYci0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTpnxS%2FbtsNQybbYV4%2FUyY7sVw8RfsbcFcwkEYci0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1356&quot; height=&quot;648&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;물론 여기 설명대로 사용자를 그룹에 넣고 그룹&amp;lt;-&amp;gt;권한 연결 해도 될 것 같다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 정책 연결을 누르고, 위에서 생성했던 권한 이름을 검색하고 체크한 후 다음을 눌러 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1297&quot; data-origin-height=&quot;553&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8ZVEc/btsNQMG3cH1/XNjsW2VRACw1Dh5rNGGD3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8ZVEc/btsNQMG3cH1/XNjsW2VRACw1Dh5rNGGD3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8ZVEc/btsNQMG3cH1/XNjsW2VRACw1Dh5rNGGD3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8ZVEc%2FbtsNQMG3cH1%2FXNjsW2VRACw1Dh5rNGGD3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1297&quot; height=&quot;553&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1297&quot; data-origin-height=&quot;553&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 잘 만들어 졌다면, 액세스 키 만들기 버튼을 누르고, 사용 사례 - 기타 를 선택 후 액세스 키를 생성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5uPle/btsNRhGx0Ag/fzNLTvHORaKawSLPhdage1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5uPle/btsNRhGx0Ag/fzNLTvHORaKawSLPhdage1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5uPle/btsNRhGx0Ag/fzNLTvHORaKawSLPhdage1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5uPle%2FbtsNRhGx0Ag%2FfzNLTvHORaKawSLPhdage1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;761&quot; height=&quot;210&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서도 &lt;b&gt;Access Key ID&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Secret Access Key&lt;/b&gt;를 따로 잘 저장해 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. RClone 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우에서 사용할 거라, &lt;a href=&quot;https://rclone.org/downloads/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Download&lt;/a&gt; 페이지에서 Intel/AMD 64비트용 Windows 버전을 다운로드했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치형 프로그램이 아닌 압축 파일로 되어 있어 직접 C:\ 에 rclone이라는 폴더를 만들고 압축을 해제해 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eMGVoo/btsNRfhnRUl/myP3Od0ikBhAMfobG8DWkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eMGVoo/btsNRfhnRUl/myP3Od0ikBhAMfobG8DWkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eMGVoo/btsNRfhnRUl/myP3Od0ikBhAMfobG8DWkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeMGVoo%2FbtsNRfhnRUl%2FmyP3Od0ikBhAMfobG8DWkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;316&quot; height=&quot;219&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 cmd창을 열어서 압축 해제한 rclone 폴더로 이동, rclone 명령어가 실행되는 것을 확인하면 일차적인 준비가 완료되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/obbG6/btsNRhzJKmP/KDzS6ZC9BuxnXmPm85KQj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/obbG6/btsNRhzJKmP/KDzS6ZC9BuxnXmPm85KQj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/obbG6/btsNRhzJKmP/KDzS6ZC9BuxnXmPm85KQj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FobbG6%2FbtsNRhzJKmP%2FKDzS6ZC9BuxnXmPm85KQj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;115&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;config 설정&lt;/b&gt;을 통해서 R2와 S3 remote를 추가해 주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvPSd5/btsNR92blzX/m1jhs99kvwwelZFvwjwVZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvPSd5/btsNR92blzX/m1jhs99kvwwelZFvwjwVZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvPSd5/btsNR92blzX/m1jhs99kvwwelZFvwjwVZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvPSd5%2FbtsNR92blzX%2Fm1jhs99kvwwelZFvwjwVZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;458&quot; height=&quot;455&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 명령어를 입력하고 요구하는 정보들을 차례대로 넣어 주자..&lt;/p&gt;
&lt;pre id=&quot;code_1746776835380&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rclone config&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;R2 remote 추가&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n 입력 &amp;rarr; 새 remote 추가&lt;/li&gt;
&lt;li&gt;이름 입력 : r2 (알아 볼 수 있는 이름이면 아무거나 가능)&lt;/li&gt;
&lt;li&gt;storage : 4&amp;nbsp;&lt;/li&gt;
&lt;li&gt;provider : 6 (Cloudflare)&lt;/li&gt;
&lt;li&gt;env_auth : false ( enter 눌러서 패스)&lt;/li&gt;
&lt;li&gt;access_key_id : 위에서 준비했던 &lt;b&gt;R2의 Access Key ID&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;secret_access_key : 위에서 준비했던 &lt;b&gt;R2의 Secret Access Key&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;region : 1 (auto)&lt;/li&gt;
&lt;li&gt;endpoint : 위에서 준비했던 &lt;b&gt;Cloudflare R2 S3 API&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdyqMU/btsNSv4KIdi/pRxWNcVokXiRCXhha0LKs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdyqMU/btsNSv4KIdi/pRxWNcVokXiRCXhha0LKs0/img.png&quot; data-alt=&quot;r2 config&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdyqMU/btsNSv4KIdi/pRxWNcVokXiRCXhha0LKs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdyqMU%2FbtsNSv4KIdi%2FpRxWNcVokXiRCXhha0LKs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;255&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;r2 config&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위 처럼 나오면 성공. y 또는 그냥 엔터를 눌러서 완료하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이서어 나오는 config 메뉴에서 다시 n을 눌러서 새로운 remote를 추가하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 remote 추가&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n 입력 &amp;rarr; 새 remote 추가&lt;/li&gt;
&lt;li&gt;이름 입력 : r2 (알아 볼 수 있는 이름이면 아무거나 가능)&lt;/li&gt;
&lt;li&gt;storage : 4&amp;nbsp;&lt;/li&gt;
&lt;li&gt;provider : 1 (AWS)&lt;/li&gt;
&lt;li&gt;env_auth : false ( enter 눌러서 패스)&lt;/li&gt;
&lt;li&gt;access_key_id : 위에서 준비했던&lt;b&gt; S3의 Access Key ID&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;secret_access_key : 위에서 준비했던 &lt;b&gt;S3의 Secret Access Key&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;region : ap-northeast-2 (혹은 자신의 버킷의 region)&lt;/li&gt;
&lt;li&gt;endpoint : 없음 (enter 눌러서 패스)&lt;/li&gt;
&lt;li&gt;이후 자잘한 옵션도 enter 눌러서 패스 해 준다,.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/46Mp1/btsNRJv0hvB/jJNPywkwV4GQPpVH4lS1e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/46Mp1/btsNRJv0hvB/jJNPywkwV4GQPpVH4lS1e0/img.png&quot; data-alt=&quot;s3 config&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/46Mp1/btsNRJv0hvB/jJNPywkwV4GQPpVH4lS1e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F46Mp1%2FbtsNRJv0hvB%2FjJNPywkwV4GQPpVH4lS1e0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;589&quot; height=&quot;138&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;s3 config&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 두개의 remote config 설정이 완료되었으면, q를 눌러 configuration 메뉴를 나오자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 명령어로 버킷 내부의 파일 목록을 확인해봄으로써 잘 연결되었는지 확인할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1746778223056&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rclone ls r2:버킷이름&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;103&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XAd1g/btsNQ2iLM02/XNcAcu1FE4iORYzof8JCy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XAd1g/btsNQ2iLM02/XNcAcu1FE4iORYzof8JCy0/img.png&quot; data-alt=&quot;4개의 파일이 잘 나온다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XAd1g/btsNQ2iLM02/XNcAcu1FE4iORYzof8JCy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXAd1g%2FbtsNQ2iLM02%2FXNcAcu1FE4iORYzof8JCy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;320&quot; height=&quot;103&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4개의 파일이 잘 나온다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Rclone 파일 복사&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 복사를 위해 사용할 수 있는 명령어는 copy 와 sync 두가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;copy&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 source 버킷에 있는 파일을 복사하고, 이미 있는 파일은 덮어쓰기&lt;/li&gt;
&lt;li&gt;source버킷에는 없는데 target버킷에 이미 있는 파일에 대해서는 아무 작업도 하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1746778136274&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rclone copy source:버킷이름 target:버킷이름 --progress&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;sync&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 source 버킷에 있는 파일을 target에 복사하되, source에는 없는데 target에 있는 파일들은 삭제한다&lt;/li&gt;
&lt;li&gt;말 그대로 완전한 '동기화' 시킴으로써, 두개의 버킷에 있는 파일을 완전히 동기화 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1746778703438&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rclone sync source:버킷이름 target:버킷이름 --progress&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 나는 무엇을 해도 상관 없지만, 파일 삭제를 위한 권한은 위에서 주지 않았으므로 copy를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;source에는 config 설정때의 &lt;b&gt;r2&lt;/b&gt; remote를 사용하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;target에는 &lt;b&gt;s3&lt;/b&gt; remote를 사용하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n8SRZ/btsNRkcuu4f/gZnk1cLpm714Hp3YPFwa6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n8SRZ/btsNRkcuu4f/gZnk1cLpm714Hp3YPFwa6k/img.png&quot; data-alt=&quot;파일들이 잘 복사가 되는 것을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n8SRZ/btsNRkcuu4f/gZnk1cLpm714Hp3YPFwa6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn8SRZ%2FbtsNRkcuu4f%2FgZnk1cLpm714Hp3YPFwa6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;192&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파일들이 잘 복사가 되는 것을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;543&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRyxg/btsNRhfI07P/xc6JqJt0iMh0hvJxteQygk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRyxg/btsNRhfI07P/xc6JqJt0iMh0hvJxteQygk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRyxg/btsNRhfI07P/xc6JqJt0iMh0hvJxteQygk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRyxg%2FbtsNRhfI07P%2Fxc6JqJt0iMh0hvJxteQygk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;328&quot; height=&quot;447&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;543&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 R2-&amp;gt; S3 파일 복사 완료!&lt;/p&gt;</description>
      <category>rclone</category>
      <author>randommagic</author>
      <guid isPermaLink="true">https://randommagic.tistory.com/11</guid>
      <comments>https://randommagic.tistory.com/11#entry11comment</comments>
      <pubDate>Fri, 9 May 2025 17:20:36 +0900</pubDate>
    </item>
    <item>
      <title>stage 서버의 도입과 git 전략에 대해</title>
      <link>https://randommagic.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;현재 상황&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 릴리즈 서버쪽으로 가기 전 stage 나 qa서버가 없이 운영하였음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 릴리즈 이후에 조그마한 버그가 생기면, 다시 릴리즈를 해야 하는 주먹구구식 운영을 하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그와는 별개로 릴리즈는 아니지만, 실제로 서비스를 릴리즈 전 테스트를 해야 할 상황이 있었고, 별다른 서버가 없었기 때문에 개발서버에 연결시켜서 테스트를 진행하고 있었음,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 개발서버에서는 계속 신규기능을들 개발하고 추가하다 보니, 빈번하게 CICD를 통해 배포되었고, 기존 테스트 버전으로 나간 기기쪽에서 문제가 나는 상황이 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 문제점을 정리하자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 개발서버를 QA로 사용하다 보니, 서버 다운 등의 이슈로 인해 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;테스트 시연 등이 필요한 상황에서&lt;span&gt; 안정적인 테스트를 할 수 없는 상황이 있었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;2. 릴리즈 전 일정 기간동안 안정적으로 테스트를 할 서버가 없어서, 개발 도중 잡지 못한 사소한 오류등이 릴리즈 서버에서 발견되어서 재 배포를 빈번하게 해야 했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;말이 되지 않는 상황이었고, 이에 대해 개선이 필요하다 느낌.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>randommagic</author>
      <guid isPermaLink="true">https://randommagic.tistory.com/8</guid>
      <comments>https://randommagic.tistory.com/8#entry8comment</comments>
      <pubDate>Thu, 20 Mar 2025 16:06:10 +0900</pubDate>
    </item>
    <item>
      <title>[NestJs] useGlobalFilter 내부 filter들의 순서</title>
      <link>https://randommagic.tistory.com/1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;새 프로젝트에서 api 구성 중 요청에 대해서 400대 응답과 500대 응답에 대해서 다른 방식으로 리턴해야 할 필요가 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 custom filter를 만들어 error 또는 exception을 상황에 맞게 처리하려고 했음.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 모든 exception 을 잡는 filter와, httpexception만을 잡는 filter 2개를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746611566311&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// all-exception.filter
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const request = ctx.getRequest&amp;lt;Request&amp;gt;();
    const response = ctx.getResponse&amp;lt;Response&amp;gt;();
    const status = HttpStatus.INTERNAL_SERVER_ERROR;

    response.status(status).json({
      statusCode: status,
      message: 'all exception',
      path: request.url,
    });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746611639290&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// http-exception.filter
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const request = ctx.getRequest&amp;lt;Request&amp;gt;();
    const response = ctx.getResponse&amp;lt;Response&amp;gt;();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      message: 'http exception',
      path: request.url,
    });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 두개를 &lt;b&gt;useGlobalFilters&lt;/b&gt;를 이용해 전역으로 달아주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746611741053&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter(), new AllExceptionsFilter());
  await app.listen(8000);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 내 생각은, HttpExceptionFilter -&amp;gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;AllExceptionFilter&lt;span&gt; 순으로 달았으니, httpexception은 먼저 등록되있는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;HttpExceptionFilter&lt;span&gt; 에서 잡힐 것이고, 그 외의 것들은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;HttpExceptionFilter&lt;span&gt; 를 지나쳐서 AllExceptionFilter&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 에서 잡히겠지?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요청&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GET /&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746611944183&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller()
export class AppController {
  @Get()
  getHello(): string {
    throw new BadRequestException();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{&quot;statusCode&quot;:500,&quot;message&quot;:&quot;all exception&quot;,&quot;path&quot;:&quot;/&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도적으로 HttpException을 상속받는 BadRequestException을 냈는데, 왜 HttpExceptionFilter에서 걸러지지 못하고 AllExceptionFilter에서 걸리는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서도 읽었고, 여러 블로그 글들도 찾다, 겨우 찾은 stackoverflow의 글.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/54727103/nestjs-how-to-pass-the-error-from-one-error-filter-to-another&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/54727103/nestjs-how-to-pass-the-error-from-one-error-filter-to-another&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHwsym/btsNOjDgf27/4HZh2Zkk1yKtOaLhRKKD21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHwsym/btsNOjDgf27/4HZh2Zkk1yKtOaLhRKKD21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHwsym/btsNOjDgf27/4HZh2Zkk1yKtOaLhRKKD21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHwsym%2FbtsNOjDgf27%2F4HZh2Zkk1yKtOaLhRKKD21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;568&quot; height=&quot;257&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt; &lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; text-align: start;&quot;&gt;나중에 등록된 필터가 가장 높은 우선순위를 가지므로, 가장 구체적인 필터는 마지막에 등록하는 것이 좋다.&lt;/span&gt; &lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746614262882&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new AllExceptionsFilter(), new HttpExceptionFilter());
  await app.listen(8000);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이전과는 다르게 더 구체적인 필터인 HttpExceptionFilter를 뒤에 등록하고 나서, 요청을 다시 시도한 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;{&quot;statusCode&quot;:400,&quot;message&quot;:&quot;http exception&quot;,&quot;path&quot;:&quot;/&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도했던 대로 AllExceptionFilter에서 잡히기 이전에 먼저 HttpExceptionFilter에서 제대로 잡히는 것을 확인할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useGlobalFilters의 구현 코드를 살펴 보았으나, 역순에 관한 내용을 찾을 수는 없었음..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색이 부족한가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>randommagic</author>
      <guid isPermaLink="true">https://randommagic.tistory.com/1</guid>
      <comments>https://randommagic.tistory.com/1#entry1comment</comments>
      <pubDate>Mon, 22 Jul 2024 15:59:08 +0900</pubDate>
    </item>
  </channel>
</rss>