넥스트클라우드 자동설치 스크립트
1. 넥스트클라우드 자동설치 스크립트 생성
1) 아래 스크립트를 복사해서 우분투 터미널에 그대로 복사 붙여넣기 후 엔터
cat > setup-nextcloud.sh <<'__SCRIPT__'
#!/usr/bin/env bash
set -euo pipefail
# ==========================================
# Nextcloud 올인원 (OCC 미사용 · 권한 안전판)
# - 자동 포트(8080→8081→8088→8888)
# - Docker/Compose + MariaDB + Redis + Cron
# - PHP/MariaDB 튜닝 (파일 쓰기는 sudo tee로 권한 문제 방지)
# - systemd 등록/자동시작
# - INSTALL_INFO 생성 + 콘솔 출력 (최적화 명령어는 '주석' 안내)
# - 관리자 계정은 웹 UI에서 생성
# - --update-site <domain> : SITE_URL/ TRUSTED_DOMAINS 갱신 + 재기동
# ==========================================
PORT="${PORT:-}"
TZ="${TZ:-Asia/Seoul}"
BASE_DIR="${BASE_DIR:-$HOME/nextcloud}"
SITE_URL="${SITE_URL:-}"
PROXY_NET="${PROXY_NET:-proxy}"
NC_IMAGE="${NC_IMAGE:-nextcloud:apache}"
DB_IMAGE="${DB_IMAGE:-mariadb:11}"
REDIS_IMAGE="${REDIS_IMAGE:-redis:7-alpine}"
PHP_MEMORY_LIMIT="${PHP_MEMORY_LIMIT:-1024M}"
PHP_UPLOAD_LIMIT="${PHP_UPLOAD_LIMIT:-8G}"
banner(){ echo; echo "==[ $* ]=="; }
have(){ command -v "$1" >/dev/null 2>&1; }
rand(){ openssl rand -base64 24 | tr -d '\n=' | cut -c1-32; }
# -------- update-site (도메인 갱신 전용, 견고판) --------
if [[ "${1:-}" == "--update-site" ]]; then
NEW_DOMAIN="${2:-}"
[[ -z "$NEW_DOMAIN" ]] && { echo "예) --update-site cloud.example.com"; exit 1; }
: "${BASE_DIR:=$HOME/nextcloud}" # 혹시 비어 있으면 보정
ENV_FILE="${BASE_DIR}/.env"
COMPOSE_FILE="${BASE_DIR}/docker-compose.yml"
[[ -f "$ENV_FILE" ]] || { echo "오류: .env 없음 -> $ENV_FILE"; exit 1; }
[[ -f "$COMPOSE_FILE" ]] || { echo "오류: docker-compose.yml 없음 -> $COMPOSE_FILE"; exit 1; }
# 키가 없으면 생성 후 덮어쓰기
grep -q '^SITE_URL=' "$ENV_FILE" || echo 'SITE_URL=""' >> "$ENV_FILE"
grep -q '^TRUSTED_DOMAINS=' "$ENV_FILE" || echo 'TRUSTED_DOMAINS=""' >> "$ENV_FILE"
sed -i "s|^SITE_URL=.*|SITE_URL=${NEW_DOMAIN}|" "$ENV_FILE"
sed -i "s|^TRUSTED_DOMAINS=.*|TRUSTED_DOMAINS=${NEW_DOMAIN}|" "$ENV_FILE"
echo "✅ .env 갱신 완료:"
grep -E '^(SITE_URL|TRUSTED_DOMAINS)=' "$ENV_FILE" || true
echo "🔁 컨테이너 재기동..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d
echo "✅ 재기동 완료"
exit 0
fi
# ---- 자동 포트 선택 ----
pick_port() {
local preferred="${1:-}"
local cands=()
[[ -n "$preferred" ]] && cands+=("$preferred")
cands+=(8080 8081 8088 8888)
local seen="" ; local uniq=()
for p in "${cands[@]}"; do [[ " $seen " =~ " $p " ]] || { uniq+=("$p"); seen="$seen $p"; }; done
for p in "${uniq[@]}"; do
if have ss && ss -ltn | grep -qE "LISTEN.*[:.]${p}[[:space:]]"; then continue; fi
echo "$p"; return 0
done
echo "사용 가능한 포트 없음: ${uniq[*]}" >&2; exit 1
}
PORT="$(pick_port "${PORT:-}")"
# ---- 패키지/도커 ----
banner "필수 패키지 설치"
sudo apt-get update -y
sudo apt-get install -y ca-certificates curl gnupg lsb-release openssl
if ! have docker; then
banner "Docker 설치"; curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker "${SUDO_USER:-$USER}" || true
fi
if ! docker compose version >/dev/null 2>&1; then
sudo apt-get install -y docker-compose-plugin
fi
# ---- 디렉토리 & 권한 ----
banner "디렉토리 준비: ${BASE_DIR}"
sudo mkdir -p "${BASE_DIR}"/{db/conf.d,app,redis,data,php,backups}
sudo chown -R "${USER}:${USER}" "${BASE_DIR}"
# ---- .env ----
DB_ROOT_PASS="$(rand)"
DB_PASS="$(rand)"
NC_DB="nextcloud"
NC_DB_USER="nextcloud"
TRUSTED_DOMAINS="${SITE_URL}"
cat > "${BASE_DIR}/.env" <<EOF
PORT="${PORT}"
TZ="${TZ}"
SITE_URL="${SITE_URL}"
TRUSTED_DOMAINS="${TRUSTED_DOMAINS}"
NC_IMAGE="${NC_IMAGE}"
DB_IMAGE="${DB_IMAGE}"
REDIS_IMAGE="${REDIS_IMAGE}"
NC_DB="${NC_DB}"
NC_DB_USER="${NC_DB_USER}"
DB_PASS="${DB_PASS}"
DB_ROOT_PASS="${DB_ROOT_PASS}"
PHP_MEMORY_LIMIT="${PHP_MEMORY_LIMIT}"
PHP_UPLOAD_LIMIT="${PHP_UPLOAD_LIMIT}"
BASE_DIR="${BASE_DIR}"
PROXY_NET="${PROXY_NET}"
EOF
# ---- MariaDB 튜닝 (sudo tee 사용) ----
banner "MariaDB 튜닝"
sudo tee "${BASE_DIR}/db/conf.d/nextcloud.cnf" >/dev/null <<'CNF'
[mysqld]
innodb_buffer_pool_size=512M
innodb_log_file_size=128M
innodb_flush_method=O_DIRECT
innodb_flush_log_at_trx_commit=2
query_cache_type=0
query_cache_size=0
CNF
sudo chown "${USER}:${USER}" "${BASE_DIR}/db/conf.d/nextcloud.cnf"
# ---- PHP(opcache) 튜닝 ----
banner "PHP(opcache) 튜닝"
tee "${BASE_DIR}/php/zz-nextcloud.ini" >/dev/null <<'INI'
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.jit=1255
opcache.jit_buffer_size=64M
INI
# ---- docker-compose.yml ----
banner "docker-compose.yml 생성"
tee "${BASE_DIR}/docker-compose.yml" >/dev/null <<'YAML'
name: nextcloud-stack
services:
db:
image: ${DB_IMAGE}
container_name: nextcloud-db
restart: unless-stopped
environment:
- MARIADB_DATABASE=${NC_DB}
- MARIADB_USER=${NC_DB_USER}
- MARIADB_PASSWORD=${DB_PASS}
- MARIADB_ROOT_PASSWORD=${DB_ROOT_PASS}
volumes:
- ${BASE_DIR}/db:/var/lib/mysql
- ${BASE_DIR}/db/conf.d/nextcloud.cnf:/etc/mysql/conf.d/nextcloud.cnf:ro
redis:
image: ${REDIS_IMAGE}
container_name: nextcloud-redis
restart: unless-stopped
command: ["redis-server","--save","","--appendonly","no"]
volumes:
- ${BASE_DIR}/redis:/data
app:
image: ${NC_IMAGE}
container_name: nextcloud-app
restart: unless-stopped
depends_on:
- db
- redis
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=${NC_DB}
- MYSQL_USER=${NC_DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- REDIS_HOST=redis
- TZ=${TZ}
- PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT}
- PHP_UPLOAD_LIMIT=${PHP_UPLOAD_LIMIT}
- NEXTCLOUD_TRUSTED_DOMAINS=${TRUSTED_DOMAINS}
volumes:
- ${BASE_DIR}/app:/var/www/html
- ${BASE_DIR}/data:/var/www/html/data
- ${BASE_DIR}/php/zz-nextcloud.ini:/usr/local/etc/php/conf.d/zz-nextcloud.ini:ro
ports:
- "${PORT}:80"
networks:
- default
- proxynet
cron:
image: ${NC_IMAGE}
container_name: nextcloud-cron
restart: unless-stopped
entrypoint: /cron.sh
volumes:
- ${BASE_DIR}/app:/var/www/html
- ${BASE_DIR}/data:/var/www/html/data
depends_on:
- app
networks:
default:
driver: bridge
proxynet:
name: ${PROXY_NET}
external: true
YAML
# 외부 프록시 네트워크 없으면 compose에서 제거
if ! docker network inspect "${PROXY_NET}" >/dev/null 2>&1; then
banner "외부 프록시 네트워크(${PROXY_NET}) 없음 → compose에서 제거"
sed -i '/^ proxynet:/,/^$/d' "${BASE_DIR}/docker-compose.yml"
sed -i '/- proxynet/d' "${BASE_DIR}/docker-compose.yml"
fi
# ---- systemd 등록 ----
banner "systemd 유닛 등록"
SERVICE_FILE="/etc/systemd/system/nextcloud-compose.service"
sudo bash -s <<EOF
cat > "$SERVICE_FILE" <<UNIT
[Unit]
Description=Nextcloud (Docker Compose)
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=${BASE_DIR}
ExecStart=/usr/bin/docker compose --env-file ${BASE_DIR}/.env up -d
ExecStop=/usr/bin/docker compose --env-file ${BASE_DIR}/.env down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable nextcloud-compose
EOF
# ---- 기동 ----
banner "컨테이너 기동 (포트: ${PORT})"
docker compose -f "${BASE_DIR}/docker-compose.yml" --env-file "${BASE_DIR}/.env" up -d
# ---- INSTALL_INFO (최적화 명령어는 '주석' 안내) ----
set -a; . "${BASE_DIR}/.env"; set +a
tee "${BASE_DIR}/INSTALL_INFO" >/dev/null << INFO
[Nextcloud 설치 요약]
- 접속: http://서버IP:${PORT}
- 폴더: ${BASE_DIR}
- 도메인(SITE_URL): ${SITE_URL:-"(미지정)"} / 신뢰 도메인: ${TRUSTED_DOMAINS:-"(미지정)"}
[DB]
- DB: ${NC_DB}
- USER: ${NC_DB_USER}
- PASS: ${DB_PASS}
- ROOT_PASS: ${DB_ROOT_PASS}
[안내]
- 관리자 계정은 브라우저로 접속한 뒤 초기 설치 화면에서 직접 생성하세요.
- 아래 '수동 최적화(추천)'는 필요할 때 복사/붙여넣기해서 실행하면 됩니다.
(주의: occ는 컨테이너 웹루트에서 실행해야 함 → -w /var/www/html)
# ===== 수동 최적화(추천) =====
# 1) 캐시/락(권장: APCu + Redis)
# docker exec -u www-data -w /var/www/html nextcloud-app php occ config:system:set memcache.local --value='\OC\Memcache\APCu'
# docker exec -u www-data -w /var/www/html nextcloud-app php occ config:system:set memcache.locking --value='\OC\Memcache\Redis'
# docker exec -u www-data -w /var/www/html nextcloud-app php occ config:system:set redis host --value='redis'
# 2) DB 최적화(인덱스/BigInt 변환)
# docker exec -u www-data -w /var/www/html nextcloud-app php occ db:add-missing-indices
# docker exec -u www-data -w /var/www/html nextcloud-app php occ db:convert-filecache-bigint --no-interaction
# 3) 백그라운드 작업을 cron으로
# docker exec -u www-data -w /var/www/html nextcloud-app php occ background:cron
# 4) 기타 유용한 설정
# - 한국 전화/지역 포맷:
# docker exec -u www-data -w /var/www/html nextcloud-app php occ config:system:set default_phone_region --value='KR'
# - 로깅 레벨(1=ERROR, 2=WARNING, 3=INFO):
# docker exec -u www-data -w /var/www/html nextcloud-app php occ config:system:set loglevel --value='2'
INFO
chmod 600 "${BASE_DIR}/INSTALL_INFO"
cat "${BASE_DIR}/INSTALL_INFO"
banner "설치 완료!"
echo "접속: http://서버IP:${PORT}"
echo "요약 파일: ${BASE_DIR}/INSTALL_INFO"
__SCRIPT__
chmod +x setup-nextcloud.sh
echo "생성 완료: ./setup-nextcloud.sh (OCC 미사용 · 권한 안전판)"
2) 스크립트 실행 ( 넥스트클라우드 설치)
① 기본 설치(자동포트 선택)
▶ bash setup-nextcloud.sh
② 도메인 있을 경우 도메인 자동설정 설치
▶ SITE_URL="cloud.example.com 도메인정보" bash setup-nextcloud.sh
③ 설치 완료된 상태에서 도메인 적용 업데이트
▶bash setup-nextcloud.sh --update-site cloud.newdomain.com도메인정보
2. 넥스트 클라우드 완벽 제거 및 삭제 스크립트 생성
1) 아래 스크립트를 복사해서 우분투 터미널에 그대로 복사 붙여넣기 후 엔터
cat > uninstall-nextcloud.sh <<'__UNINSTALL__'
#!/usr/bin/env bash
set -euo pipefail
# =========================
# Nextcloud Docker 스택 완전 제거기
# - docker compose down -v (볼륨 포함)
# - 남은 컨테이너/네트워크/볼륨/파일 정리
# - systemd 유닛 삭제 및 데몬 리로드
# - 기본 경로: ~/nextcloud ( .env 있으면 그 값을 우선 사용 )
# 옵션:
# --dry-run : 실제 삭제 대신 수행할 작업만 출력
# --force : 확인 질문 없이 바로 진행
# --keep-data : 데이터 디렉터리/파일은 보존 (도커 리소스만 제거)
# --purge-images : 관련 이미지까지 삭제(nextcloud/mariadb/redis)
# --base-dir DIR : 기본 경로 지정(기본: ~/nextcloud)
# =========================
DRYRUN=0
FORCE=0
KEEP_DATA=0
PURGE_IMAGES=0
BASE_DIR="${HOME}/nextcloud"
log(){ echo "[*] $*"; }
run(){ if [[ "$DRYRUN" -eq 1 ]]; then echo " ↳ (dry-run) $*"; else eval "$@"; fi; }
# ---- parse args ----
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRYRUN=1 ;;
--force) FORCE=1 ;;
--keep-data) KEEP_DATA=1 ;;
--purge-images) PURGE_IMAGES=1 ;;
--base-dir) BASE_DIR="${2:-}"; shift ;;
-h|--help)
cat <<USAGE
사용법: bash uninstall-nextcloud.sh [옵션]
--dry-run 실제 삭제 없이 계획만 출력
--force 확인 없이 진행
--keep-data 데이터/설치 폴더 보존
--purge-images 도커 이미지까지 삭제(nextcloud/mariadb/redis)
--base-dir DIR 기본 경로 지정 (기본: ~/nextcloud)
USAGE
exit 0;;
*) echo "알 수 없는 옵션: $1" ; exit 1 ;;
esac
shift
done
# ---- sanity ----
command -v docker >/dev/null 2>&1 || { echo "docker 명령을 찾을 수 없습니다."; exit 1; }
# ---- .env 탐색 ----
ENV_FILE=""
if [[ -f "${BASE_DIR}/.env" ]]; then
ENV_FILE="${BASE_DIR}/.env"
else
# 흔한 위치 추가 탐색
for p in "./.env" "/opt/nextcloud/.env"; do
[[ -f "$p" ]] && ENV_FILE="$p" && break
done
fi
if [[ -n "$ENV_FILE" ]]; then
log ".env 찾음: $ENV_FILE"
# shellcheck disable=SC2046
set -a && . "$ENV_FILE" && set +a
# .env에 BASE_DIR 정의가 있으면 덮어쓰기
if [[ -n "${BASE_DIR:-}" && -n "${BASE_DIR## }" ]]; then
:
else
BASE_DIR="${BASE_DIR:-$HOME/nextcloud}"
fi
else
log ".env 를 찾지 못함. 기본 경로로 진행: ${BASE_DIR}"
fi
# 리소스명(우리 설치 스크립트와 일치)
STACK_NAME="nextcloud-stack"
SERVICE_NAME="nextcloud-compose"
C_APP="nextcloud-app"
C_DB="nextcloud-db"
C_REDIS="nextcloud-redis"
C_CRON="nextcloud-cron"
C_PV="nextcloud-previewgen"
# 확인
if [[ "$FORCE" -eq 0 ]]; then
echo "다음 리소스를 제거합니다:"
echo " - 컨테이너/네트워크/볼륨(docker compose down -v)"
echo " - 남은 컨테이너(${C_APP}, ${C_DB}, ${C_REDIS}, ${C_CRON}, ${C_PV}) 및 익명 볼륨"
echo " - systemd 유닛: ${SERVICE_NAME}"
if [[ "$KEEP_DATA" -eq 0 ]]; then
echo " - 설치/데이터 폴더: ${BASE_DIR}"
else
echo " - 설치/데이터 폴더는 보존 (--keep-data)"
fi
[[ "$PURGE_IMAGES" -eq 1 ]] && echo " - 도커 이미지(nextcloud, mariadb, redis) 삭제 (--purge-images)"
read -r -p "정말 진행할까요? (YES 입력 시 진행): " ANS
[[ "$ANS" == "YES" ]] || { echo "중단."; exit 0; }
fi
# ---- compose down -v ----
if [[ -f "${BASE_DIR}/docker-compose.yml" ]]; then
log "docker compose down -v 실행"
if [[ -n "$ENV_FILE" ]]; then
run "docker compose -f '${BASE_DIR}/docker-compose.yml' --env-file '${ENV_FILE}' down -v || true"
else
run "docker compose -f '${BASE_DIR}/docker-compose.yml' down -v || true"
fi
else
log "compose 파일을 찾지 못함: ${BASE_DIR}/docker-compose.yml (개별 자원 기준으로 정리)"
fi
# ---- 개별 컨테이너 강제 정리 ----
for c in "$C_PV" "$C_CRON" "$C_APP" "$C_DB" "$C_REDIS"; do
if docker ps -a --format '{{.Names}}' | grep -qx "$c"; then
log "컨테이너 제거: $c"
run "docker rm -f '$c' || true"
fi
done
# ---- 네트워크 정리(내부 브리지만) ----
# 설치시 기본 'nextcloud-stack_default' 가 생김. 외부 PROXY_NET은 건드리지 않음.
if docker network ls --format '{{.Name}}' | grep -qx "${STACK_NAME}_default"; then
log "네트워크 제거: ${STACK_NAME}_default"
run "docker network rm '${STACK_NAME}_default' || true"
fi
# ---- 볼륨/익명 볼륨 추가 정리 ----
# compose down -v 로 대부분 제거되지만 혹시 모를 익명 볼륨 청소
log "dangling 볼륨 정리"
run "docker volume prune -f || true"
# ---- 이미지 제거(옵션) ----
if [[ "$PURGE_IMAGES" -eq 1 ]]; then
log "관련 이미지 제거(nextcloud, mariadb, redis)"
run "docker images --format '{{.Repository}}:{{.Tag}} {{.ID}}' | awk '/^(nextcloud|mariadb|redis)(:|$)/{print \$2}' | xargs -r docker rmi -f || true"
fi
# ---- systemd 유닛 제거 ----
if [[ -f "/etc/systemd/system/${SERVICE_NAME}.service" ]]; then
log "systemd 유닛 중지/비활성화/삭제: ${SERVICE_NAME}"
run "sudo systemctl stop '${SERVICE_NAME}' || true"
run "sudo systemctl disable '${SERVICE_NAME}' || true"
run "sudo rm -f '/etc/systemd/system/${SERVICE_NAME}.service'"
run "sudo systemctl daemon-reload"
fi
# ---- 파일/폴더 삭제 ----
if [[ "$KEEP_DATA" -eq 0 ]]; then
if [[ -d "$BASE_DIR" ]]; then
log "설치 폴더 삭제: ${BASE_DIR}"
run "sudo rm -rf '${BASE_DIR}'"
fi
else
log "설치 폴더 보존 (--keep-data)"
fi
log "정리 완료!"
echo "Tip:"
echo " - 완전 초기화를 원하면 --purge-images 추가"
echo " - 데이터 보존하고 스택만 지우려면 --keep-data 사용"
__UNINSTALL__
chmod +x uninstall-nextcloud.sh
echo "생성 완료: ./uninstall-nextcloud.sh (도움말: -h 또는 --help)"
2) 스크립트 실행 ( 넥스트클라우드 완벽삭제 )
① 질문 없이 강제 제거
▶ bash uninstall-nextcloud.sh --force
② 데이터는 남기고 도커 리소스만 제거
▶ bash uninstall-nextcloud.sh --keep-data
③ 모든 데이터 완벽 제거
▶ bash uninstall-nextcloud.sh --force --purge-images
공개 마지막 업데이트: 2025-09-28 09:46:40 AM