공유 호스팅에 Laravel 배포 (SSH 필요 없음)
Source: Dev.to

공유 호스팅에서 Laravel 배포가 다른 이유
1. 프로젝트 파일 구조
일반적인 Laravel 프로젝트는 다음과 같습니다:
project/
├── app/
├── bootstrap/
├── config/
├── public/
├── storage/
├── vendor/
└── artisan
하지만 공유 호스팅에서는 일반적으로 하나의 public 디렉터리만 노출됩니다:
├── public_html/
2. SSH 없음, 명령어 사용 불가
SSH 접근이 없다면, 다음을 할 수 없습니다:
- Composer 의존성 설치
- 자산 빌드 (
npm run …) - 마이그레이션 실행
- 캐시 정리 또는 최적화
상황 해결 방법 – 단계별 가이드
단계 1: 로컬에서 애플리케이션 준비하기
Laravel 프로젝트를 프로덕션용 복사본으로 클론하여 개발 환경에 영향을 주지 않도록 합니다:
├── laravel_app/
├── laravel_app_prod/
laravel_app_prod 내부에서 프로덕션용으로 애플리케이션을 준비합니다:
# 캐시 정리
php artisan config:clear
php artisan cache:clear
php artisan route:clear
php artisan view:clear
# 프로덕션 의존성 설치 및 최적화
composer install --no-dev --optimize-autoloader
# 프론트엔드 에셋 빌드
npm run build
단계 2 – 프로젝트 파일 구조 재구성
공유 호스팅 레이아웃에 맞추기 위해 public/ 폴더의 내용만 새 public_html/ 폴더로 이동합니다:
public_html/
handleRequest(Illuminate\Http\Request::capture());
중요: 경로가 잘못되면 500 오류가 발생합니다.
단계 4 – cPanel을 이용한 데이터베이스 설정
- cPanel에서 MySQL Database Wizard를 엽니다.
- 데이터베이스를 생성합니다.
- 데이터베이스 사용자를 만들고 ALL PRIVILEGES를 부여합니다.
그런 다음 laravel_app_prod 내부의 .env 파일을 업데이트합니다:
APP_NAME=MyApp
APP_ENV=production
APP_DEBUG=false # 매우 중요 (보안)
APP_URL=https://your-app-domain
DB_DATABASE=database_name
DB_USERNAME=database_user
DB_PASSWORD=database_password
⚠️ 프로덕션에서는 절대
APP_DEBUG=true를 활성화하지 마세요.
단계 5 – 임시 배포 라우트 (토큰 보호)
SSH가 없으므로 보호된 웹 라우트를 통해 Artisan 명령을 임시로 실행할 수 있습니다. 배포 후 이 라우트를 즉시 삭제하세요.
-
.env에 비밀 토큰을 추가합니다:DEPLOY_TOKEN=verySecretRandomToken123 -
routes/web.php에 라우트를 추가합니다:use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Route; Route::get('/deploy/{token}', function ($token) { abort_unless($token === env('DEPLOY_TOKEN'), 403); // 1. 마이그레이션 실행 및 캐시 정리 Artisan::call('migrate', ['--force' => true]); Artisan::call('optimize:clear'); // 2. 스토리지 링크 수정 (맞춤형 fix) // $_SERVER['DOCUMENT_ROOT']를 사용해 'public_html' 폴더를 가리킵니다 $targetFolder = storage_path('app/public'); $linkFolder = $_SERVER['DOCUMENT_ROOT'] . '/storage'; if (!file_exists($linkFolder)) { symlink($targetFolder, $linkFolder); $storageStatus = 'Storage link created successfully.'; } else { $storageStatus = 'Storage link already exists.'; } return "Deployment completed.\nMigrations run.\nCache cleared.\n" . $storageStatus; });
단계 6 – 서버에 파일 업로드
cPanel File Manager를 사용합니다:
laravel_app_prod/를 압축합니다.public/의 내용을 압축합니다.- 두 압축 파일을 모두 업로드합니다:
laravel_app_prod는 public_html 외부에 압축을 풉니다.- public 파일은 public_html 내부에 압축을 풉니다.
왜 laravel_app_prod를 public_html 밖에 두나요?
핵심 애플리케이션 코드를 웹에서 직접 접근 가능한 디렉터리 밖에 두어 중요한 보안 레이어를 제공합니다.
단계 7 — 필수 권한 설정
Laravel은 몇몇 폴더에 쓰기 권한이 필요합니다. 권한이 올바르게 설정되지 않으면 로그가 기록되지 않으며 세션도 저장되지 않습니다.
- cPanel File Manager에서
laravel_app_prod/storage폴더로 이동합니다. - 오른쪽 클릭 → Change Permissions 선택.
- 권한을 775(User: Read/Write/Execute, Group: Read/Write/Execute, World: Read/Execute) 로 설정합니다.
laravel_app_prod/bootstrap/cache폴더에 대해서도 동일한 절차를 반복합니다.
⚠️ 참고: 이 폴더들을
777로 설정하지 마세요. 공유 호스팅 환경에서는 큰 보안 위험이 됩니다.
단계 8 — 마이그레이션 실행 및 배포 라우트 삭제
브라우저에서 다음 URL을 엽니다 ( your-domain.com 을 실제 도메인으로 교체):
https://your-domain.com/deploy/verySecretRandomToken123
모든 것이 정상이라면 다음과 같은 메시지가 표시됩니다:
Deployment completed successfully
Immediately after that:
- ❗ 배포 라우트를 삭제하세요.
- ❗
.env에서DEPLOY_TOKEN을 제거하세요.
이 단계들은 보안에 매우 중요합니다.
흔히 겪는 문제
500 내부 서버 오류
index.php의 파일 경로가 올바르지 않음.- 잘못된 PHP 버전 (cPanel MultiPHP Manager 사용).
- 폴더 권한이 올바르지 않음 (
storage775,bootstrap/cache775).
403 인증되지 않음
DEPLOY_TOKEN과 일치하지 않는 라우트 토큰.
Final Thoughts
Shared hosting isn’t ideal for Laravel, but it’s still common for:
- Client projects
- MVPs
- Budget‑constrained deployments
With proper preparation and a secure workflow, Laravel applications can run reliably without SSH access.
💡 Pro Tip – Safer Database Alternative
If you’re uncomfortable running migrations via a web route (which carries security risks), use the Export/Import method:
- Run migrations on your local machine.
- Export the local database as an
.sqlfile. - In cPanel → phpMyAdmin on the server, import the
.sqlfile directly.
This avoids executable logic in production routes.
🔗 연결하기
Laravel 튜토리얼, 개발 팁, 배포 워크플로우, 실제 프로덕션 솔루션을 더 받아보세요:
- LinkedIn:
- Medium: (그리고 메일링 리스트에 가입하세요: )
이 글이 도움이 되었나요?
🙏 박수 👏, 구독 🔔, 그리고 소셜 네트워크에 공유해 주시면 감사드립니다.