Ubuntu 24.04에 MinIO 셀프 호스팅 구축하기
Ubuntu 24.04 환경에서 MinIO 객체 스토리지를 직접 설치하고 운영하는 방법을 설명합니다. systemd 설정, mc 명령어 사용법, restic 백업 연동을 포함하며, 2025년 이후 변경된 커뮤니티 에디션 배포 정책과 보안 패치 미지원 현황을 상세히 다룹니다.
MinIO 셀프 호스팅 객체 스토리지가 제공하는 것
MinIO는 Amazon S3 API를 지원하는 셀프 호스팅 객체 스토리지입니다. restic이나 임의의 S3 SDK를 자신의 서버로 가리키고 엔드포인트 설정 하나만 변경하면, 클라이언트는 차이를 구분할 수 없습니다. 이 가이드는 Ubuntu 24.04 환경에서 단일 노드를 구축합니다. 검증된 바이너리, 전용 시스템 사용자, root 자격 증명을 unit 파일에 노출하지 않는 systemd unit, 그리고 restic이 백업을 저장할 버킷을 구성합니다.
S3(Simple Storage Service)는 파일 시스템이 아닌 HTTP API입니다. 버킷 내의 키(key)를 사용하여 객체를 PUT하고 다시 GET하며, 부분 쓰기나 이름 변경은 지원하지 않습니다. 백업 도구는 객체가 온전하게 도착했거나 아예 도착하지 않았음을 보장하는 이러한 모델을 선호합니다.
단일 노드는 데이터의 복사본 하나를 보관합니다. 이것이 여러분이 감수해야 할 트레이드오프입니다. VPS 비용으로 직접 제어 가능한 S3 엔드포인트를 얻는 대신, 고장 난 디스크 교체부터 서버 소프트웨어 패치까지 클라우드 제공업체가 수행하던 모든 작업을 직접 관리해야 합니다. 이 트레이드오프가 언제 적절한 선택인지는 마지막 섹션에서 명확히 설명합니다.
2026년 7월 기준 MinIO 커뮤니티 에디션 현황
이 내용을 기반으로 시스템을 구축하기 전에 반드시 읽어 보아야 합니다. 최근 변경 사항이 있기 때문입니다. 2025년 5월, MinIO는 커뮤니티 에디션의 웹 콘솔에서 관리 기능을 제거했습니다. 브라우저에 남은 기능은 객체 브라우저뿐이므로, 버킷과 액세스 키는 이제 mc 명령줄 클라이언트를 사용하여 관리해야 합니다.
2025년 하반기에 MinIO는 커뮤니티용 사전 컴파일된 바이너리 배포를 중단했습니다. 현재 프로젝트 README에는 커뮤니티 에디션이 소스 코드로만 배포된다고 명시되어 있습니다. 기존 다운로드 URL은 여전히 작동합니다. 2026년 7월 기준으로 해당 URL은 서버 빌드 RELEASE.2025-09-07T16-13-09Z과 클라이언트 빌드 RELEASE.2025-08-13T08-35-41Z을 제공하며, 그 이후로 새로운 커뮤니티 빌드는 출시되지 않았습니다. 따라서 아래에서 사용하는 바이너리는 실제 작동하는 버전이지만, 업데이트가 중단된 상태입니다. 2025년 9월 이후에 발표된 보안 패치는 포함되어 있지 않습니다.
이 사실이 본 가이드의 나머지 내용을 결정합니다. MinIO가 이 가이드에서 127.0.0.1 포트로 수신 대기하고, 사용자가 제어하는 프록시를 통해서만 인터넷에 연결하는 이유가 바로 이것입니다. 보안 패치를 계속 적용하려면 소스 코드에서 직접 빌드해야 합니다. 공급업체의 README는 go install github.com/minio/minio@latest이라는 단일 명령어를 제공합니다. 이 명령어는 Go 툴체인이 필요하며, 빌드된 바이너리를 ~/go/bin/minio 경로에 생성합니다. 해당 바이너리를 /usr/local/bin/minio에 설치하면 이후의 모든 단계는 동일하게 적용됩니다.
MinIO 바이너리 설치 및 다운로드 검증
고정된 릴리스 버전과 게시된 체크섬을 다운로드합니다. -f 플래그를 사용하면 HTTP 오류 발생 시 오류 페이지를 지정한 파일명으로 저장하지 않고 curl가 실패하도록 만듭니다. 이 플래그를 사용하지 않으면 404 페이지를 설치 파일로 저장하게 되어, 나중에 실행되지 않는 이유를 찾느라 시간을 낭비하게 됩니다.
cd /tmp
REL=RELEASE.2025-09-07T16-13-09Z
curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/archive/minio.$REL" -o minio
curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/archive/minio.$REL.sha256sum" -o minio.sha256sum두 해시 값을 비교하십시오. 오직 해시 값만 비교해야 합니다.
published=$(awk '{print $1}' minio.sha256sum)
downloaded=$(sha256sum minio | awk '{print $1}')
[ "$published" = "$downloaded" ] && echo "checksum ok"여기서 sha256sum -c minio.sha256sum를 사용하지 마십시오. 해당 파일 내부의 해시 뒤에 적힌 레이블은 minio.RELEASE.2025-09-07T16-13-09Z이지만, 다운로드한 파일은 minio로 저장했으므로 -c은 존재하지 않는 파일을 찾게 됩니다. 이 경우 No such file or directory가 보고되고 이어 WARNING: 1 listed file could not be read이 출력되는데, 이는 다운로드가 손상된 것처럼 보이지만 실제로는 그렇지 않습니다. 레이블은 단순한 이름일 뿐이며, 보증을 제공하는 것은 해시 값입니다.
이 검사가 무엇을 증명하는지 명확히 이해해야 합니다. 바이너리와 해시 값은 동일한 연결을 통해 동일한 공급자로부터 제공되므로, 일치한다는 것은 다운로드가 완료되었으며 전송 과정에서 손상되거나 변경되지 않았음을 의미합니다. 이것이 공급자가 신뢰할 수 있다는 것을 증명하지는 않습니다. 그것은 별개의 문제이며 어떤 sha256sum 명령으로도 해결할 수 없습니다.
sudo install -o root -g root -m 755 minio /usr/local/bin/minio
minio --versionminio --version는 minio version RELEASE.2025-09-07T16-13-09Z과 몇 줄의 빌드 정보를 출력합니다. 여기서 Permission denied가 발생하면 모드가 잘못된 것이며, command not found가 발생하면 /usr/local/bin이 PATH에 없는 것입니다.
시스템 사용자 및 데이터 디렉터리 생성
MinIO는 네트워크를 통해 업로드를 수신하므로 root 권한으로 실행해서는 안 됩니다. 홈 디렉터리와 로그인 셸이 없는 계정을 할당하십시오.
sudo groupadd -r minio-user
sudo useradd -M -r -g minio-user -s /usr/sbin/nologin minio-user
sudo mkdir -p /var/lib/minio/data
sudo chown -R minio-user:minio-user /var/lib/minio
sudo chmod 750 /var/lib/minio-r은 1000 미만의 UID를 가진 시스템 계정을 생성하며, 이는 일반 사용자 계정 범위와 겹치지 않게 합니다. -M는 홈 디렉터리를 생성하지 않는데, 로그인하지 않는 계정은 홈 디렉터리가 필요 없기 때문입니다. id minio-user으로 결과를 확인하고, stat -c '%U %a' /var/lib/minio을 실행하여 minio-user 750가 출력되는지 확인하십시오.
데이터 디렉터리는 읽기 전용이 아니라 해당 사용자가 쓰기 권한을 가져야 합니다. MinIO는 최초 시작 시 자체 설정을 저장하기 위해 볼륨 내부에 .minio.sys 디렉터리를 생성합니다. 따라서 root 소유의 디렉터리를 사용하면 MinIO는 시작 과정에서 permission denied로 끝나는 메시지를 출력하며 종료됩니다. 동일한 규칙이 이러한 방식으로 실행하는 모든 서비스에 적용되며, VPS에서의 최소 권한 서비스 사용자 문서에서 이를 상세히 다룹니다.
루트 자격 증명을 환경 파일에 저장하기
루트 자격 증명은 모든 버킷에 대한 접근 권한을 가지므로, 누구나 읽을 수 있는 unit 파일에 포함해서는 안 됩니다. 먼저 적절한 권한 모드로 파일을 생성한 뒤 내용을 작성하십시오. 이렇게 하면 비밀번호가 읽기 가능한 상태로 파일에 노출되는 시간을 방지할 수 있습니다.
sudo install -o root -g root -m 600 /dev/null /etc/default/minio
printf 'MINIO_ROOT_USER=minio-root\nMINIO_ROOT_PASSWORD=%s\nMINIO_VOLUMES="/var/lib/minio/data"\nMINIO_OPTS="--address 127.0.0.1:9000 --console-address 127.0.0.1:9001"\n' "$(openssl rand -base64 24)" | sudo tee /etc/default/minio > /dev/null
sudo sed -n 's/^MINIO_ROOT_PASSWORD=//p' /etc/default/miniotee는 파일을 새로 생성하는 대신 기존 파일을 잘라내므로, 파일 모드는 600으로 유지되고 소유자도 root로 유지됩니다. 이는 의도된 동작입니다. systemd는 User=로 권한을 낮추기 전에 root 권한으로 EnvironmentFile을 읽습니다. 따라서 서비스 계정이 자신의 자격 증명을 직접 읽을 필요가 없습니다. 서비스가 실행되면 sudo -u minio-user cat /etc/default/minio을 사용하여 확인하십시오. 해당 명령은 반드시 Permission denied를 출력해야 합니다.
MinIO를 시작하기 전에 알아두어야 할 두 가지 동작이 있습니다. 환경 변수에 MINIO_ROOT_USER과 MINIO_ROOT_PASSWORD이 없더라도 MinIO는 시작을 거부하지 않습니다. MinIO는 문서화된 기본 자격 증명인 minioadmin:minioadmin로 시작하는데, 이는 스캐너가 가장 먼저 시도하는 조합이며 이 상태에서도 서비스는 정상적으로 작동하는 것처럼 보입니다. 반면 8자 미만의 비밀번호는 거부됩니다. MinIO는 시작 시 자격 증명이 유효하지 않다는 오류를 내며 종료되는데, 이는 액세스 키는 최소 3자, 시크릿 키는 최소 8자 이상이어야 하기 때문입니다.
MINIO_VOLUMES은 데이터 경로이며 MINIO_OPTS에는 플래그가 포함됩니다. 127.0.0.1에 바인딩한다는 것은 아직 이 VPS 외부에서 S3 API에 접근할 수 없음을 의미하며, 이는 올바른 기본 설정입니다. 이후 인증서를 보유한 프록시를 통해 의도적으로 접근을 허용하게 됩니다.
systemd 유닛 작성
/etc/systemd/system/minio.service을 생성합니다:
[Unit]
Description=MinIO object storage
Documentation=https://github.com/minio/minio
Wants=network-online.target
After=network-online.target
[Service]
User=minio-user
Group=minio-user
EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS
Restart=always
RestartSec=5
LimitNOFILE=65536
NoNewPrivileges=true
[Install]
WantedBy=multi-user.targetEnvironmentFile에 -이 없는 것은 오타가 아니라 의도적인 결정입니다. 대시(-)를 사용하면 systemd는 파일이 없어도 이를 무시하고 MinIO를 시작하므로, 파일이 삭제되었거나 경로가 잘못되어도 서버가 minioadmin:minioadmin에서 기본값으로 조용히 실행됩니다. 대시가 없으면 파일이 누락될 경우 MinIO가 실행되기 전에 유닛이 실패하며, journalctl -u minio은 Failed to load environment files: No such file or directory을 표시합니다. 서버가 기본 비밀번호를 조용히 수락하는 것보다, 시작을 거부하는 유닛을 확인하는 것이 훨씬 쉽습니다.
$MINIO_VOLUMES와 $MINIO_OPTS에 따옴표를 사용하지 않은 이유는 systemd가 따옴표가 없는 변수를 공백 기준으로 나누어 별도의 인자로 처리하기 때문입니다. 이것이 MINIO_OPTS의 네 단어가 minio server에 네 개의 인자로 전달되는 방식입니다. LimitNOFILE=65536은 파일 디스크립터 제한을 높입니다. 모든 열린 연결과 데이터 파일은 디스크립터를 하나씩 소모하며, 기본값인 1024는 부하가 걸리면 금방 고갈되기 때문입니다.
sudo systemctl daemon-reload
sudo systemctl enable --now minio
systemctl is-active minio
curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:9000/minio/health/liveis-active은 active을 출력해야 하며, 상태 확인 엔드포인트는 200로 응답해야 합니다. journalctl -u minio -n 20 --no-pager은 서버가 수신 대기 중인 API 주소를 보여줍니다. 유닛이 계속 재시작된다면 systemd는 포기하고 Start request repeated too quickly을 기록합니다. 이는 MinIO가 매 시도마다 종료된다는 의미입니다. 원인은 해당 메시지 바로 윗줄에 출력되므로 위쪽을 확인하십시오.
더 높은 격리를 원한다면 [Service] 섹션에 ProtectSystem=full와 ProtectHome=true을 추가하십시오. 두 설정 모두 호스트 커널의 마운트 네임스페이스가 필요합니다. OpenVZ나 LXC처럼 호스트 커널을 공유하는 컨테이너 가상화 환경에서는 이 설정이 실패할 수 있으며, 유닛은 status=226/NAMESPACE를 보고합니다. 이 두 줄을 제거하면 정상적으로 시작됩니다. 유닛 자체는 일반적인 형태이며, VPS에서의 systemd 서비스 및 타이머에서 나머지 지시어들을 다룹니다.
mc 설치 및 왕복 테스트
MinIO 클라이언트는 mc입니다. apt install mc로 설치하지 마십시오. 해당 패키지는 MinIO와 관련 없는 파일 관리자인 Midnight Commander입니다.
cd /tmp
curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc -o mc
curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc.sha256sum -o mc.sha256sum
[ "$(awk '{print $1}' mc.sha256sum)" = "$(sha256sum mc | awk '{print $1}')" ] && echo "checksum ok"
sudo install -o root -g root -m 755 mc /usr/local/bin/mc서버를 별칭(alias)으로 등록한 뒤, 객체를 이동시켜 확인합니다.
MINIO_PASS=$(sudo sed -n 's/^MINIO_ROOT_PASSWORD=//p' /etc/default/minio)
mc alias set local http://127.0.0.1:9000 minio-root "$MINIO_PASS"
mc mb local/backups
echo "hello object storage" > /tmp/hello.txt
mc cp /tmp/hello.txt local/backups/hello.txt
mc ls local/backups
mc cat local/backups/hello.txtmc ls 명령은 hello.txt와 그 크기를 나열해야 하며, mc cat은 hello object storage을 출력해야 합니다. 이 왕복 과정은 다른 모든 클라이언트가 수행하는 것과 동일한 서명된 S3 요청을 생성하므로 서버가 정상 작동함을 증명하는 확실한 방법입니다. 추가 확인이 필요하다면 mc admin info local로 서버 상태를 출력할 수 있습니다.
서버가 비어 있는 지금, 마지막으로 한 가지를 더 확인합니다.
mc alias set defaultcheck http://127.0.0.1:9000 minioadmin minioadmin이 명령은 반드시 실패해야 합니다. 만약 성공한다면 환경 파일이 프로세스에 전달되지 않은 것이며, 서버가 기본 자격 증명으로 실행 중인 상태입니다. 다른 작업이 진행되기 전에 이 문제를 먼저 해결하십시오.
mc은 별칭을 ~/.mc/config.json에 일반 텍스트로 저장하므로, 해당 자격 증명은 명령을 실행한 사용자의 홈 디렉터리에 노출됩니다. sudo 권한으로 mc를 실행하면 루트 자격 증명이 /root/.mc/config.json에 저장됩니다. 루트 별칭은 관리자 계정 하나에만 유지하고, 각 애플리케이션에는 별도의 키를 부여하십시오.
사전 서명된 URL로 객체 하나 공유하기
사전 서명된 URL은 서명과 만료 시간이 포함된 일반적인 HTTPS 링크입니다. 이 링크를 가진 사람은 누구나 계정이나 클라이언트 없이 해당 객체를 가져올 수 있습니다.
mc share download --expire 12h local/backups/hello.txt출력 결과에는 쿼리 문자열에 X-Amz-Signature와 X-Amz-Expires가 포함됩니다. 이와 관련하여 사람들이 놀라는 두 가지 사실이 있습니다. 링크는 사용한 별칭의 엔드포인트로부터 생성되므로, 127.0.0.1에 설정된 별칭은 해당 머신에서만 열 수 있는 링크를 만듭니다. 외부로 보낼 링크라면 공용 호스트 이름으로 별칭을 하나 더 만드십시오. 또한, 취소 버튼이 없습니다. 서명은 만료될 때까지 유효하므로, 짧은 만료 시간을 설정하는 것이 유일한 제어 수단입니다. S3 서명 형식에서 허용하는 최대 기간은 7일입니다.
restic에 전용 키와 버킷 할당하기
root 자격 증명은 모든 버킷을 읽고 삭제할 수 있으므로, 백업 작업에 이를 사용해서는 안 됩니다. 전용 버킷을 생성하고, 해당 버킷으로 범위를 제한한 정책을 설정한 뒤, 다른 권한이 없는 사용자를 생성하십시오.
mc mb local/restic
cat > /tmp/restic-rw.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": ["arn:aws:s3:::restic"]
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::restic/*"]
}
]
}
EOF
RESTIC_KEY=$(openssl rand -base64 24)
mc admin policy create local restic-rw /tmp/restic-rw.json
mc admin user add local restic-backup "$RESTIC_KEY"
mc admin policy attach local restic-rw --user restic-backupMinIO는 내장 readwrite 정책을 제공하며, 이를 사용하면 명령어를 한 줄 줄일 수 있지만, 서버의 모든 버킷에 대한 전체 접근 권한을 부여하게 됩니다. 위 정책에서 버킷 이름을 두 번 명시한 것은 의도적입니다. 한 번은 버킷 목록 조회를 위해 arn:aws:s3:::restic로, 다른 한 번은 내부 객체 접근을 위해 arn:aws:s3:::restic/*으로 지정했습니다. S3에서 버킷과 그 안의 객체는 별개의 리소스이므로, 둘 중 하나만 명시한 정책은 클라이언트가 고장 난 것처럼 보이는 오류를 발생시킵니다.
신뢰하기 전에 제한 사항을 먼저 테스트하십시오.
mc alias set resticuser http://127.0.0.1:9000 restic-backup "$RESTIC_KEY"
mc ls resticuser/restic
mc ls resticuser/backups첫 번째 ls는 성공하지만, 두 번째는 Access Denied 오류와 함께 실패합니다. 테스트하지 않은 정책은 추측에 불과합니다.
이제 restic이 해당 버킷을 바라보도록 설정하십시오. restic은 표준 AWS 환경 변수에서 S3 자격 증명을 읽어오므로, restic 전용 자격 증명 파일은 필요하지 않습니다.
sudo apt install -y restic
export AWS_ACCESS_KEY_ID=restic-backup
export AWS_SECRET_ACCESS_KEY="$RESTIC_KEY"
restic -r s3:http://127.0.0.1:9000/restic init
restic -r s3:http://127.0.0.1:9000/restic backup /etc
restic -r s3:http://127.0.0.1:9000/restic snapshotsrestic init은 저장소 암호를 요구합니다. 이 암호는 저장소를 암호화하므로 MinIO는 암호문만 저장하게 되며, 암호를 분실하면 백업 데이터도 복구할 수 없습니다. systemd 타이머로 실행되는 작업은 암호를 입력할 터미널이 없으므로, 예약 백업을 위해 RESTIC_PASSWORD_FILE을 모드 600 파일로 설정하십시오.
배치 규칙 하나가 위에서 언급한 모든 명령어보다 중요합니다. 데이터를 보호하는 것과 동일한 VPS에 restic 저장소를 두는 것은 실수로 인한 rm 상황에서만 보호해 줄 뿐, 그 외의 상황에서는 아무런 도움이 되지 않습니다. MinIO 노드는 다른 머신에 위치해야 하며, 가급적 다른 리전에 두는 것이 좋습니다. VPS에서의 restic 백업에서 백업 예약 및 보관 정책에 대해 다룹니다.
Nginx에서 TLS 종료하기
MinIO는 localhost에서 실행되므로 Nginx가 외부 공개 인터페이스 역할을 합니다. certbot과 Nginx를 이용한 Let's Encrypt 인증서 발급에서 설명한 대로 먼저 인증서를 발급받은 뒤, 아래의 서버 블록을 사용하십시오.
server {
listen 443 ssl;
server_name s3.example.com;
ignore_invalid_headers off;
client_max_body_size 0;
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 300;
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass http://127.0.0.1:9000;
}
}위 설정 중 일부 행은 매우 중요합니다. client_max_body_size 0는 기본값인 1 MB 본문 크기 제한을 해제합니다. 이 설정을 하지 않으면 MinIO가 요청을 받기도 전에 413 Request Entity Too Large 오류로 인해 대용량 업로드가 거부됩니다. proxy_request_buffering off은 업로드를 즉시 스트리밍합니다. 기본 설정은 전체 요청을 임시 파일에 먼저 저장하므로, 대용량 객체 업로드 시 디스크 공간이 두 배로 필요하기 때문입니다. proxy_set_header Host $http_host는 주의가 필요한 설정입니다. S3 서명은 Host 헤더를 포함하므로, 프록시가 이 헤더를 재작성하면 접근 로그에는 정상적인 요청으로 기록되더라도 모든 요청이 SignatureDoesNotMatch 오류로 실패하게 됩니다.
MinIO가 생성하는 링크가 localhost가 아닌 프록시를 가리키도록, MinIO에게 자신의 공개 도메인 이름을 알려주어야 합니다.
echo 'MINIO_SERVER_URL=https://s3.example.com' | sudo tee -a /etc/default/minio
sudo systemctl restart minio방화벽 설정은 최소화합니다. SSH와 HTTPS만 허용하고, 9000번과 9001번 포트는 규칙을 추가하지 마십시오. 127.0.0.1에 바인딩된 주소는 방화벽 설정과 관계없이 외부 기기에서 직접 접근할 수 없기 때문입니다. VPS에서의 ufw 방화벽 기초에 관련 명령어가 정리되어 있습니다.
단일 노드 MinIO가 충분한 경우와 실제 S3가 필요한 경우
여기서 단일 노드란 패리티가 없는 드라이브 하나를 의미합니다. MinIO 자체 문서에서는 이 구성을 테스트용이나 가용성 요구 사항이 없는 소규모 워크로드에 적합하다고 설명합니다. 배포 내에 두 번째 복사본이 없으므로, 모든 객체의 내구성은 VPS 디스크 하나의 내구성과 같습니다. 분산 이레이저 코딩(erasure-coded) 백엔드를 전제로 하는 기능들(버킷 복제 및 객체 잠금 등)은 다중 드라이브 배포에 속하므로, 이 설정에서 누구에게도 변경 불가능한 보존 정책을 약속해서는 안 됩니다.
이 구성은 다른 지역의 두 번째 VPS에서 restic 대상 저장소로 사용하거나, 버킷을 잃어버려도 재구축만 하면 되는 개발 작업 및 CI 아티팩트용 S3 엔드포인트로 적합합니다. 또한 복구 계획을 직접 수립하고 실제로 복원 테스트를 완료했다면, 소규모 애플리케이션의 사용자 업로드 용도로도 합리적입니다.
계약이나 규제 기관이 객체 잠금 또는 다중 지역 내구성을 요구하거나, 디스크가 꽉 차서 새벽 3시에 호출받는 사람이 되고 싶지 않다면 관리형 S3를 선택하십시오. 고정된 빌드 버전 또한 솔직한 선택 이유가 됩니다. 2026년 7월 기준으로 사전 컴파일된 커뮤니티 바이너리는 2025년 9월 버전이며 수정 사항이 제공되지 않으므로, 이를 실행한다는 것은 해당 상태를 감수하거나 직접 소스에서 빌드하여 프로젝트를 계속 따라가겠다는 의미입니다.
자주 발생하는 문제이므로 한 가지 경계는 명확히 할 필요가 있습니다. 객체 스토리지는 데이터베이스가 아닙니다. 모든 쓰기 작업은 객체 전체를 교체하므로, S3 버킷에서 실시간 SQL 파일을 사용하는 것은 느리고 안전하지 않습니다. 데이터베이스는 로컬 디스크에 유지하고 버킷으로 백업하십시오. VPS에서 SQLite를 운영하는 방법에서 이러한 분리 방식을 설명합니다.
실패 유형과 표시되는 메시지
유닛이 systemctl enable --now 직후에 실패합니다. journalctl -u minio -n 30 --no-pager을 읽어 보십시오. Failed to load environment files: No such file or directory은 /etc/default/minio가 없거나 유닛 파일 내 경로가 잘못되었음을 의미합니다. permission denied으로 끝나는 메시지는 서비스 계정이 데이터 디렉터리에 쓰기 권한이 없다는 뜻이므로, stat -c '%U' /var/lib/minio/data을 실행했을 때 minio-user가 출력되는지 확인하십시오.
minioadmin:minioadmin이 여전히 로그인됩니다. 환경 변수 파일이 프로세스에 전달되지 않았습니다. 유닛 파일에 EnvironmentFile=/etc/default/minio가 포함되어 있는지 확인하고, sudo systemctl daemon-reload를 실행한 뒤 서비스를 재시작하십시오. MinIO는 시작 시점에 루트 자격 증명을 한 번만 읽으므로, 재시작 없이 파일만 수정해서는 아무런 변화가 없습니다.
시작 시 Address already in use이 발생합니다. 다른 프로세스가 9000번 포트를 점유하고 있습니다. MinIO의 포트를 변경하기 전에 sudo ss -ltnp | grep :9000을 사용하여 해당 프로세스를 찾으십시오.
프록시를 통할 때 1 MB 이상의 업로드에 실패합니다. nginx가 413 Request Entity Too Large을 응답했으며 MinIO는 요청을 전달받지 못했습니다. 서버 블록에 client_max_body_size 0를 설정하십시오.
SignatureDoesNotMatch. 비밀 키가 잘못되었거나, 클라이언트와 MinIO 사이의 무언가가 서명에 포함되는 Host 헤더를 재작성했을 가능성이 있습니다.
RequestTimeTooSkewed. 클라이언트나 서버의 시간이 맞지 않습니다. 모든 S3 요청은 타임스탬프를 포함하며, 15분 오차 범위를 벗어나면 거부됩니다. timedatectl을 확인하고 시간 동기화가 활성화되어 있는지 확인하십시오.
존재하는 버킷임에도 Access Denied가 발생합니다. 키가 다른 버킷으로 범위가 제한되어 있습니다. mc admin policy info local restic-rw를 사용하여 정책이 실제로 허용하는 범위를 출력하고, 리소스 라인에 기재된 버킷 이름과 비교하십시오.
FAQ
단일 노드 MinIO는 실제 백업용으로 충분합니까?
보호하려는 데이터가 있는 머신과 별도의 머신에서 restic 대상(target)으로 실행한다면 충분합니다. 하지만 유일한 복사본으로 사용하기에는 부족합니다. 단일 드라이브 배포는 패리티가 없으므로 MinIO 내부에 두 번째 복사본이 존재하지 않으며, 해당 VPS 디스크에서 데이터가 손실되면 객체도 사라집니다. 다른 곳에 두 번째 대상을 유지하고, 복구 절차가 정상적으로 작동하는지 최소 한 번 이상 복구 테스트를 수행하십시오.
왜 sha256sum -c이 MinIO의 체크섬 파일에서 실패합니까?
해당 파일 내부의 해시 뒤에 있는 레이블이 릴리스 버전인 minio.RELEASE.2025-09-07T16-13-09Z을 가리키고 있지만, 다운로드한 파일의 이름은 일반적으로 minio이기 때문입니다. sha256sum -c는 체크섬 파일 내부에 적힌 이름의 파일을 찾으려 시도하지만, 해당 파일을 찾지 못해 No such file or directory 및 WARNING: 1 listed file could not be read 오류를 보고합니다. 다운로드 자체는 정상입니다. 보안상 의미가 없는 레이블은 무시하고 해시 문자열만 직접 비교하십시오.
MinIO 관리자 웹 콘솔은 어디로 갔습니까?
MinIO는 2025년 5월 커뮤니티 에디션 콘솔에서 관리 기능을 제거하고 웹 인터페이스에 객체 브라우저만 남겼습니다. 이제 버킷과 사용자는 mc 클라이언트를 사용하여 관리하며, mc admin user add 및 mc admin policy attach와 같은 명령어를 사용합니다. 이것이 커뮤니티 에디션에서 지원하는 정식 경로이며 우회 방법이 아니므로, 이 가이드에서는 모든 작업을 명령줄에서 수행합니다.
restic에서 MinIO를 S3 백엔드로 지정하려면 어떻게 합니까?
AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY을 MinIO 액세스 키와 시크릿 키로 설정한 다음, s3:https://s3.example.com/restic 형식의 리포지토리 문자열을 사용하십시오. 여기서 마지막 경로 요소는 버킷 이름입니다. 특정 버킷으로 권한이 제한된 키는 버킷을 생성할 권한이 없으므로, mc mb을 사용하여 먼저 버킷을 생성하십시오. restic은 업로드 전 자체 리포지토리 암호로 모든 데이터를 암호화하므로, MinIO는 암호문만 저장하며 사용자의 원본 파일을 볼 수 없습니다.
MinIO를 반드시 nginx 뒤에서 실행해야 합니까?
클라이언트가 동일한 머신에 있지 않은 경우 S3 자격 증명과 객체 데이터가 모두 요청 내부에 포함되어 전송되므로 TLS(전송 계층 보안)가 필요합니다. certbot에서 발급받은 인증서를 사용하여 443 포트에서 프록시를 구성하는 것이 가장 간단한 방법이며, 이렇게 하면 인증서 갱신 작업을 MinIO와 분리할 수 있습니다. MinIO가 직접 TLS를 종료하게 하려면 --certs-dir를 public.crt 및 private.key이 포함된 디렉터리로 지정하면 되지만, 이 경우 서비스 계정에 갱신된 개인 키에 대한 읽기 권한을 부여해야 하므로 동일한 결과를 얻기 위해 추가 작업이 필요합니다.