# Amazon S3 정적 웹사이트에 문의 폼 추가하기

> S3 웹사이트 엔드포인트는 일반 HTTP로 GET과 HEAD만 받으므로, 문의 폼은 폼 백엔드로 POST하고 CloudFront로 리디렉션을 올바르게 설정하세요.

2026-10-25 게시 · https://ikiform.com/ko/guides/contact-form-static-site/aws-s3

S3 웹사이트 엔드포인트는 폼 `POST`에 `405 MethodNotAllowed`로 응답하므로, 대신 폼의 `action`을 Ikiform 엔드포인트로 지정하세요. 엔드포인트가 일반 `http:`이므로 그곳으로 돌아가는 `_redirect`는 따르지 않습니다. 폼 설정에서 **Redirect after submit**을 설정하거나, `https:`를 위해 앞단에 CloudFront를 두세요. 버킷의 REST 엔드포인트 앞에 CloudFront를 두는 경우, 기본 루트 객체는 루트에만 적용되므로 `thanks.html` 같은 전체 파일 이름으로 리디렉션하세요.

## S3에서 다른 점

정적 웹사이트 호스팅으로 구성한 버킷에는 `http://www.example.com.s3-website-us-east-1.amazonaws.com` 같은 자체 웹사이트 엔드포인트가 생깁니다. AWS 문서에 따르면 객체에 대한 `GET`과 `HEAD` 요청만 지원합니다. 폼 POST는 HTML 오류 페이지를 받습니다.

`POST에 대한 응답`:

```html
<html>
<head><title>405 Method Not Allowed</title></head>
<body>
<h1>405 Method Not Allowed</h1>
<ul>
<li>Code: MethodNotAllowed</li>
<li>Message: The specified method is not allowed against this resource.</li>
<li>Method: POST</li>
<li>ResourceType: OBJECT</li>
```

S3의 특성 세 가지가 더 문의 폼에 영향을 줍니다.

| S3의 특성 | 폼에 미치는 영향 |
| --- | --- |
| 웹사이트 엔드포인트는 HTTPS를 지원하지 않습니다 | Ikiform은 `https:` URL로의 `_redirect`만 따르므로, 맨 엔드포인트로 돌아가는 리디렉션은 무시됩니다 |
| 응답 헤더는 버킷이 아니라 CloudFront에서 옵니다 | Content-Security-Policy는 CloudFront 응답 헤더 정책에서 설정합니다 |
| CloudFront의 기본 루트 객체는 루트에만 적용됩니다 | REST 오리진에서는 `https://example.com/thanks/`가 `thanks/index.html`을 불러오지 않으므로 `thanks.html`로 리디렉션하세요 |

`https:` 사이트라면 AWS는 CloudFront 위에서 실행되는 Amplify Hosting이나, 버킷 앞에 CloudFront를 두는 방식을 권합니다. 폼은 어느 쪽이든 작동합니다. 달라지는 것은 방문자가 전송 후 도착하는 곳입니다.

다이어그램: CloudFront 유무에 따라 방문자가 전송 후 도착하는 곳

1. 맨 웹사이트 엔드포인트에서는 페이지가 http로 제공되고 Ikiform으로 POST합니다.
2. Ikiform은 메시지를 저장하지만 http 주소로의 _redirect는 무시하고 호스팅 감사 페이지를 보여 줍니다.
3. 대시보드에서 Redirect after submit을 설정하면 이를 피할 수 있습니다. 이 설정은 http URL도 받기 때문입니다.
4. 자체 도메인과 CloudFront를 쓰면 페이지는 https입니다.
5. 도메인이 Allowed domains에 있는 한 Ikiform은 _redirect를 따라 여러분의 thanks.html로 보냅니다.

메시지는 어느 쪽이든 저장됩니다. 브라우저가 어디로 가는지, 마지막 단계만 https에 달려 있습니다.

## 어떤 CloudFront 오리진을 쓸까

CloudFront는 두 가지 방식으로 버킷을 읽을 수 있으며, 무엇을 고르느냐에 따라 감사 URL의 형태가 정해집니다.

| 오리진 | 버킷 | 폴더 인덱스 페이지 | 감사 URL |
| --- | --- | --- | --- |
| 커스텀 오리진으로 쓰는 S3 웹사이트 엔드포인트 | 공개적으로 읽을 수 있어야 함 | 작동함: `/thanks/`가 `thanks/index.html`을 불러옴 | `/thanks/` 또는 `/thanks.html` |
| 오리진 액세스 제어를 쓰는 REST 엔드포인트 | 비공개로 유지되며 CloudFront만 읽음 | 기본 루트 객체를 통해 루트만 | 전체 파일 이름인 `/thanks.html` |

전체 파일 이름은 두 방식 모두에서 작동하므로 예제에서는 이를 씁니다. CloudFront를 직접 운영하고 싶지 않다면 Amplify Hosting이 `https:`와 관리형 CDN으로 버킷에서 배포할 수 있으며, 이 경우에도 폼은 바꿀 필요가 없습니다.

## 폼

S3 사이트는 회사 사이트인 경우가 많으므로, 이 폼은 업무용 이메일과 회사 이름을 묻습니다. `thanks.html` 옆에 `contact.html`로 업로드하세요.

`contact.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />

  <label for="email">Work email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="company">Company</label>
  <input id="company" name="company" autocomplete="organization" />

  <label for="message">How can we help?</label>
  <textarea id="message" name="message" rows="6" minlength="10" required></textarea>

  <input type="hidden" name="_redirect" value="https://www.example.com/thanks.html" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button type="submit">Send</button>
</form>
```

- `_redirect`는 파일 이름과 함께 CloudFront 도메인을 가리킵니다. `www.example.com` 또는 `example.com`이 **Allowed domains**에 있을 때만 따릅니다.
- 맨 `http:` 엔드포인트에서는 `_redirect` 입력을 지우고 대신 **Redirect after submit**을 감사 페이지로 설정하세요. 이 설정은 여러분의 팀만 바꿀 수 있으므로 `http:` URL도 받습니다.
- 필드 이름은 `email`로 유지하세요. 알림 이메일이 이를 회신 주소로 사용합니다.

회사 사이트에서는 보통 여러 사람이 문의 받은편지함을 읽습니다. 폼에 확인된 알림 수신자를 최대 10명까지 추가하세요. 각자 메시지를 받고, **Reply**를 누른 사람이 보낸 사람에게 바로 답합니다. 메시지가 공유 채널이나 티켓 대기열에도 가야 한다면 서명된 웹훅을 추가하고 [Zapier](https://ikiform.com/blog/form-submissions-to-zapier.md)나 여러분의 코드로 라우팅하세요. `company` 필드는 일반 텍스트로 도착하므로 어느 곳에서든 바로 필터링할 수 있습니다.

업로드하기 전에 **Allowed domains**에 `localhost`를 넣고 로컬 서버에서 페이지를 테스트하세요. `localhost`에서 보낸 POST는 테스트로 집계되므로, 버킷이 폼을 제공하기 전에 폼을 완성할 수 있습니다.

폴더를 버킷에 동기화하고, 새 폼이 바로 제공되도록 CloudFront에서 페이지를 무효화하세요.

`터미널`:

```bash
aws s3 sync ./site s3://www.example.com --delete

aws cloudfront create-invalidation --distribution-id E1EXAMPLE --paths "/contact.html" "/thanks.html"
```

## AWS 호스트의 허용 도메인

| 페이지가 제공되는 곳 | 추가할 것 |
| --- | --- |
| 맨 웹사이트 엔드포인트 | `www.example.com.s3-website-us-east-1.amazonaws.com` 같은 버킷의 전체 엔드포인트 호스트 |
| CloudFront 기본 도메인 | 테스트하는 동안 정확한 `d111111abcdef8.cloudfront.net` 호스트 |
| 자체 도메인 | `www.example.com`도 포함하는 `example.com` |

`amazonaws.com`, 리전별 `s3-website` 접미사, `cloudfront.net`만 단독으로 추가하지 마세요. 전 세계의 모든 버킷이나 배포가 일치하게 됩니다. AWS가 S3 웹사이트 엔드포인트 도메인을 Public Suffix List에 등록한 것도 같은 이유입니다. 버킷 하나하나가 별개의 사이트입니다.

## CloudFront를 통한 헤더

S3 객체 메타데이터로는 Content-Security-Policy를 설정할 수 없으므로, CloudFront 응답 헤더 정책에서 설정하고 배포의 기본 캐시 동작에 연결하세요. 헤더 값은 1,783자로 제한됩니다.

`csp-policy.json`:

```json
{
  "Name": "site-csp",
  "SecurityHeadersConfig": {
    "ContentSecurityPolicy": {
      "Override": true,
      "ContentSecurityPolicy": "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
    }
  }
}
```

`터미널`:

```bash
aws cloudfront create-response-headers-policy --response-headers-policy-config file://csp-policy.json
```

> `Override: true`는 오리진이 보내는 CSP를 대체합니다. 맨 S3 오리진에는 CSP가 없지만, 나중에 오리진을 바꿔도 이 정책이 적용되게 해 줍니다.

## 작동 확인하기

1. 위 표의 도메인을 추가하고, 테스트하는 동안에는 `localhost`도 추가하세요.
2. CloudFront 도메인에서 제출하세요. 여러분의 도메인에 있는 `thanks.html`에 도착해야 합니다.
3. 맨 웹사이트 엔드포인트도 공개해 둔다면, 거기서도 제출해 **Redirect after submit**에 설정한 페이지로 가는지 확인하세요.
4. 대시보드에서 **Submissions**를 여세요. 보낸 모든 필드가 담긴 새 제출이 있습니다.
5. 알림 수신자마다 받은편지함을 확인하세요. 각자 필드가 담긴 이메일을 받고, 폼에 `email` 필드가 있으면 **Reply**가 제출한 사람에게 갑니다.
6. 아무것도 오지 않았나요? 대시보드의 상태 필터를 **Spam**으로 바꿔 보세요. 스팸은 실제 제출과 같은 성공 응답을 받습니다.

## 주의할 점

| 문제 | 해결 방법 |
| --- | --- |
| `Code: MethodNotAllowed`와 함께 `405 Method Not Allowed` | 폼이 버킷으로 POST했습니다. CloudFront가 아직 이전 `contact.html`을 제공하고 있을 수 있으니 무효화하세요. |
| 리디렉션 후 `AccessDenied` 또는 `403` | REST 오리진을 쓰는 CloudFront 배포에서 리디렉션이 `/thanks/` 같은 폴더를 가리킵니다. `thanks.html`을 가리키게 하세요. |
| 브라우저가 여러분의 페이지 대신 Ikiform의 감사 페이지로 이동함 | `_redirect`는 도메인이 **Allowed domains**에 있고 `https:` URL일 때만 따릅니다. 도메인을 추가하거나, 대신 폼 설정에서 **Redirect after submit**을 설정하세요. |
| `403 origin_not_allowed`, 또는 모든 POST가 스팸으로 분류됨 | 페이지의 도메인이 폼의 **Allowed domains**에 없습니다. 도메인을 추가하고, 로컬 테스트용으로 `localhost`도 추가하세요. 등록한 도메인의 하위 도메인은 허용됩니다. |

## 질문

### S3 정적 웹사이트가 폼 제출을 처리할 수 있나요?

아니요. S3 웹사이트 엔드포인트는 GET과 HEAD 요청만 지원하므로 POST는 405 MethodNotAllowed를 받습니다. 폼을 폼 백엔드로 지정하거나, Lambda로 API를 만드세요.

### 문의 폼이 작동하려면 CloudFront가 필요한가요?

아니요. 폼은 http 페이지에서도 Ikiform으로 POST합니다. CloudFront는 https를 제공하므로, Ikiform이 _redirect를 따라 여러분의 감사 페이지로 돌려보낼 수 있습니다.

### API Gateway, Lambda, SES를 쓰면 안 되나요?

그 방법도 되고 모든 것을 AWS 안에 둘 수 있지만, 검증, 스팸 필터링, 저장, 재시도를 직접 만들어야 하고 SES에는 인증된 발신자가 필요합니다. 문의 폼이라면 폼 백엔드가 유지 관리할 것이 적습니다.

### 폼을 바꾼 뒤 CloudFront가 이전 폼을 캐시하나요?

캐시된 사본이 만료될 때까지는 그럴 수 있습니다. 바꿀 때마다 contact.html을 무효화하거나, 짧은 Cache-Control max-age로 HTML을 업로드해 새 폼이 빨리 반영되게 하세요.

### Ikiform은 무료인가요?

아니요, 무료 플랜은 없습니다. 테스트는 무료입니다. 결제하기 전에 localhost에서 한 달에 50건의 테스트 제출을 보낼 수 있습니다. 실제로 운영하려면 Pro가 제출 500건에 월 $6부터이며, 한 번만 결제해 제출 10,000건을 $49에, 50,000건을 $149에 살 수도 있습니다. 크레딧은 만료되지 않습니다.

## 가이드 더 보기

- [정적 사이트의 문의 폼](https://ikiform.com/ko/guides/contact-form-static-site.md): 서버 없이 정적 사이트에 작동하는 문의 폼을 추가하세요. POST가 가는 곳, 스팸, 이메일 답장, 호스트와 프레임워크별 코드까지 다룹니다.
- [Cloudflare Pages](https://ikiform.com/ko/guides/contact-form-static-site/cloudflare-pages.md): Function을 작성하지 않고 Cloudflare Pages에 문의 폼을 추가하세요. 폼 백엔드로 POST하고, _headers에서 헤더를 설정하고, 직접 가진 Turnstile 키를 씁니다.
- [GitHub Pages](https://ikiform.com/ko/guides/contact-form-static-site/github-pages.md): GitHub Pages는 서버 코드를 실행할 수 없어 폼 POST가 405 Not Allowed를 받습니다. 대신 폼 백엔드로 POST하고 프로젝트 사이트의 리디렉션을 올바르게 설정하세요.
- [Vercel](https://ikiform.com/ko/guides/contact-form-static-site/vercel.md): Vercel의 정적 페이지는 폼 POST에 405 Method Not Allowed로 응답합니다. 그 이유와 폼을 백엔드로 보내는 방법을 알아보세요.
- [Netlify](https://ikiform.com/ko/guides/contact-form-static-site/netlify.md): Netlify Forms 없이 Netlify 사이트에서 문의 폼을 운영하세요. 빌드 시점 감지 없이 React에서 JSON을 POST하고, 배포 프리뷰용 폼을 따로 둡니다.
- [포트폴리오 웹사이트](https://ikiform.com/ko/guides/contact-form-static-site/portfolio-website.md): 첫 통화에서 물어볼 프로젝트, 예산, 일정, 링크를 미리 묻는 포트폴리오 문의 폼입니다. 서버가 필요 없고 받은편지함에서 답장합니다.
