Bagaimana Anda menyetel objek root default untuk subdirektori untuk situs web yang dihosting secara statis di Cloudfront?

100

Bagaimana Anda menyetel objek root default untuk subdirektori di situs web yang dihosting secara statis di Cloudfront? Secara khusus, saya ingin www.example.com/subdir/index.htmldilayani setiap kali pengguna meminta www.example.com/subdir. Catatan, ini untuk mengirimkan situs web statis yang disimpan dalam keranjang S3. Selain itu, saya ingin menggunakan identitas akses asal untuk membatasi akses ke bucket S3 hanya di Cloudfront.

Sekarang, saya menyadari bahwa Cloudfront bekerja secara berbeda dari S3 dan negara bagian amazon secara khusus :

Perilaku objek root default CloudFront berbeda dari perilaku dokumen indeks Amazon S3. Saat Anda mengonfigurasi bucket Amazon S3 sebagai situs web dan menentukan dokumen indeks, Amazon S3 mengembalikan dokumen indeks meskipun pengguna meminta subdirektori di bucket. (Salinan dokumen indeks harus muncul di setiap subdirektori.) Untuk informasi selengkapnya tentang mengonfigurasi bucket Amazon S3 sebagai situs web dan tentang dokumen indeks, lihat bab Situs Web Hosting di Amazon S3 di Panduan Pengembang Amazon Simple Storage Service.

Dengan demikian, meskipun Cloudfront memungkinkan kita menentukan objek root default, ini hanya berfungsi untuk www.example.comdan bukan untuk www.example.com/subdir. Untuk mengatasi kesulitan ini, kita dapat mengubah nama domain asal menjadi titik akhir situs web yang diberikan oleh S3. Ini berfungsi dengan baik dan memungkinkan objek root ditentukan secara seragam. Sayangnya, ini tampaknya tidak sesuai dengan identitas akses asal . Secara khusus, tautan di atas menyatakan:

Ubah ke mode edit:

Distribusi web - Klik tab Origins, klik origin yang ingin Anda edit, dan klik Edit. Anda hanya dapat membuat identitas akses asal untuk asal yang Jenis Asal adalah S3 Origin.

Pada dasarnya, untuk menyetel objek root default yang benar, kami menggunakan titik akhir situs web S3 dan bukan keranjang situs web itu sendiri. Ini tidak kompatibel dengan menggunakan identitas akses asal. Karena itu, pertanyaan saya bermuara pada keduanya

  1. Apakah mungkin untuk menentukan objek root default untuk semua subdirektori untuk situs web yang dihosting secara statis di Cloudfront?

  2. Apakah mungkin untuk menyiapkan identitas akses asal untuk konten yang disajikan dari Cloudfront yang asalnya adalah titik akhir situs web S3 dan bukan bucket S3?

wyer33
sumber
1
Saya pikir ini sekarang dapat dilakukan dengan Lambda @ edge, menggunakan fungsi yang mengarahkan semua URL yang diakhiri dengan / ke /index.html Saya akan mencobanya di situs web saya dan melaporkan kembali hasilnya dan memposting konfigurasi terperinci sebagai jawaban.
Cristian Măgherușan-Stanciu

Jawaban:

2

UPDATE: Sepertinya saya salah! Lihat jawaban JBaczuk, yang seharusnya menjadi jawaban yang diterima di utas ini.

Sayangnya, jawaban untuk kedua pertanyaan Anda adalah tidak.

1. Apakah mungkin untuk menentukan objek root default untuk semua subdirektori untuk situs web yang dihosting secara statis di Cloudfront?

Tidak. Seperti yang dinyatakan dalam dokumen AWS CloudFront ...

... Jika Anda mendefinisikan objek root default, permintaan pengguna akhir untuk subdirektori distribusi Anda tidak mengembalikan objek root default. Misalnya, anggaplah index.htmlobjek root default Anda dan CloudFront menerima permintaan pengguna akhir untuk direktori instal di bawah distribusi CloudFront Anda:

http://d111111abcdef8.cloudfront.net/install/

CloudFront tidak akan mengembalikan objek root default meskipun salinannya index.htmlmuncul di direktori instal.

...

Perilaku objek root default CloudFront berbeda dari perilaku dokumen indeks Amazon S3. Saat Anda mengonfigurasi bucket Amazon S3 sebagai situs web dan menentukan dokumen indeks, Amazon S3 mengembalikan dokumen indeks bahkan jika pengguna meminta subdirektori di bucket. (Salinan dokumen indeks harus muncul di setiap subdirektori.)

2. Apakah mungkin untuk menyiapkan identitas akses asal untuk konten yang disajikan dari Cloudfront yang asalnya adalah titik akhir situs web S3 dan bukan bucket S3?

Tidak secara langsung. Pilihan Anda untuk asal dengan CloudFront adalah bucket S3 atau server Anda sendiri.

Namun, opsi kedua itulah yang membuka beberapa kemungkinan menarik. Ini mungkin mengalahkan tujuan dari apa yang Anda coba lakukan, tetapi Anda dapat mengatur server Anda sendiri yang tugas satu-satunya adalah menjadi server asal CloudFront.

Saat permintaan masuk untuk http://d111111abcdef8.cloudfront.net/install/ , CloudFront akan meneruskan permintaan ini ke server asal Anda, meminta /install. Anda dapat mengonfigurasi server asal Anda sesuka Anda, termasuk untuk melayani index.htmldalam kasus ini.

Atau Anda dapat menulis aplikasi web kecil yang hanya menerima panggilan ini dan tetap mendapatkannya langsung dari S3.

Tetapi saya menyadari bahwa menyiapkan server Anda sendiri dan mengkhawatirkan penskalaannya dapat menggagalkan tujuan dari apa yang Anda coba lakukan di tempat pertama.

Josh Padnick
sumber
Satu masalah yang saya miliki dengan ini adalah bahwa membuat ini berfungsi berarti Anda akan memiliki dua (2) URL yang mampu mengakses situs web Anda di s3. URL depan cloud Anda dan url s3 Anda (bucket_name.s3-website-us-east-1.amazonaws.com)
Hayden
223

Ada IS cara untuk melakukan hal ini. Alih-alih mengarahkannya ke keranjang Anda dengan memilihnya di tarik-turun (www.example.com.s3.amazonaws.com), arahkan ke domain statis keranjang Anda (mis. Www.example.com.s3-website-us -west-2.amazonaws.com):

masukkan deskripsi gambar di sini

Berkat utas Forum AWS ini

JBaczuk
sumber
6
Adakah yang tahu jika biaya ini berbeda ketika memiliki asal s3 vs asal web?
fideloper
3
Apakah ini berfungsi dengan baik jika saya hanya ingin menyajikan seluruh situs web dan file saya HTTPS?
Manjit Kumar
3
Apakah ini berarti S3 harus diaktifkan sebagai server web?
Anthony Kong
6
OP secara eksplisit menyatakan bahwa pendekatan ini tidak akan berhasil untuknya: "Untuk mengatasi kesulitan ini, kami dapat mengubah nama domain asal untuk menunjuk ke titik akhir situs web yang diberikan oleh S3. Ini berfungsi dengan baik dan memungkinkan objek root ditentukan secara seragam. Sayangnya , ini tampaknya tidak sesuai dengan identitas akses asal ". AWS sendiri tampaknya merekomendasikan lamda @ edge untuk ini - aws.amazon.com/blogs/compute/…
icyitscold
3
Ini tidak kompatibel dengan Cloud Front - Origin Access Identity. Anda tidak akan dapat membatasi akses ke bucket S3 Anda dengan cara ini.
rocketspacer
15

Mengaktifkan hosting S3 berarti Anda harus membuka bucket ke dunia. Dalam kasus saya, saya perlu merahasiakan bucket dan menggunakan fungsionalitas identitas akses asal untuk membatasi akses ke Cloudfront saja. Seperti yang disarankan @Juissi, fungsi Lambda dapat memperbaiki pengalihan:

'use strict';

/**
 * Redirects URLs to default document. Examples:
 *
 * /blog            -> /blog/index.html
 * /blog/july/      -> /blog/july/index.html
 * /blog/header.png -> /blog/header.png
 *
 */

let defaultDocument = 'index.html';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    if(request.uri != "/") {
        let paths = request.uri.split('/');
        let lastPath = paths[paths.length - 1];
        let isFile = lastPath.split('.').length > 1;

        if(!isFile) {
            if(lastPath != "") {
                request.uri += "/";
            }

            request.uri += defaultDocument;
        }

        console.log(request.uri);
    }

    callback(null, request);
};

Setelah Anda memublikasikan fungsi Anda, buka distribusi cloudfront Anda di konsol AWS. Pergi ke Behaviors, lalu pilih di Origin Requestbawah Lambda Function Associations, dan terakhir tempelkan ARN ke fungsi baru Anda.

kenske
sumber
5
Ada siap untuk menyebarkan lambda fungsi yang mirip dengan salah satu yang: serverlessrepo.aws.amazon.com/applications/...
marcanuy
Masalahnya di sini adalah bahwa fungsi ini perlu diterapkan ke us-east-1, jadi jika Anda memiliki perusahaan di bawah peraturan GDPR yang ketat yang tidak mengizinkan satu bit pun di luar Jerman maka ini bukan untuk Anda.
Renato Gama
5

Ada satu cara lain untuk mendapatkan file default yang disajikan di subdirektori, seperti example.com/subdir/. Anda sebenarnya (secara terprogram) dapat menyimpan file dengan kunci subdir/di keranjang. File ini tidak akan muncul di konsol manajemen S3, tetapi sebenarnya ada, dan CloudFront akan menyajikannya.

Johan Gorter
sumber
S3 percakapan subdir / ke subdirektori; saat Anda mencoba mengunggah HTML. Selain itu, saat Anda mencoba mengakses example.com/subdir/, gagal, dan jika Anda mencoba mengakses example.com/subdir; itu mengunduh file HTML alih-alih merendernya.
jacobfogg
4

Solusi untuk masalah ini adalah dengan memanfaatkan lambda @ edge untuk menulis ulang permintaan. Anda hanya perlu menyiapkan lambda untuk acara permintaan penampil distribusi CloudFront dan menulis ulang semua yang diakhiri dengan '/' AND tidak sama dengan '/' dengan dokumen root default misalnya index.html.

Juissi
sumber
Detail lebih lanjut mengenai pendekatan ini di sini: aws.amazon.com/blogs/compute/…
Henrik Aasted Sørensen
sayangnya Lambda @ Edge hanya berfungsi di wilayah us-east-1, sumber: github.com/awslabs/serverless-application-model/issues/635
mruanova
4

Ada panduan "resmi" yang diterbitkan di blog AWS yang merekomendasikan pengaturan fungsi Lambda @ Edge yang dipicu oleh distribusi CloudFront Anda:

Tentu saja, merupakan pengalaman pengguna yang buruk mengharapkan pengguna untuk selalu mengetik index.html di akhir setiap URL (atau bahkan tahu bahwa itu harus ada). Hingga saat ini, belum ada cara yang mudah untuk menyediakan URL yang lebih sederhana ini (setara dengan DirectoryIndex Directive dalam konfigurasi Apache Web Server) kepada pengguna melalui CloudFront. Tidak jika Anda masih ingin dapat membatasi akses ke asal S3 menggunakan OAI. Namun, dengan rilis Lambda @ Edge, Anda dapat menggunakan fungsi JavaScript yang berjalan pada node edge CloudFront untuk mencari pola ini dan meminta kunci objek yang sesuai dari asal S3.

Larutan

Dalam contoh ini, Anda menggunakan daya komputasi di tepi CloudFront untuk memeriksa permintaan saat masuk dari klien. Kemudian tulis ulang permintaan tersebut sehingga CloudFront meminta objek indeks default (index.html dalam kasus ini) untuk setiap URI permintaan yang diakhiri dengan '/'.

Saat permintaan dibuat terhadap server web, klien menentukan objek yang akan diperoleh dalam permintaan tersebut. Anda bisa menggunakan URI ini dan menerapkan ekspresi reguler padanya sehingga URI ini diselesaikan ke objek indeks default sebelum CloudFront meminta objek dari asalnya. Gunakan kode berikut:

'use strict';
exports.handler = (event, context, callback) => {

    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');

    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);

};

Ikuti panduan yang ditautkan di atas untuk melihat semua langkah yang diperlukan untuk menyiapkannya, termasuk bucket S3, distribusi CloudFront, dan pembuatan fungsi Lambda @ Edge .

Max Desiatov
sumber
2

Alternatif lain untuk menggunakan lambda @ edge adalah dengan menggunakan halaman kesalahan CloudFront. Siapkan Respons Kesalahan Kustom untuk mengirim semua 403 ke file tertentu. Kemudian tambahkan javascript ke file itu untuk menambahkan index.html ke url yang diakhiri dengan /. Kode sampel:

if ((window.location.href.endsWith("/") && !window.location.href.endsWith(".com/"))) {
    window.location.href = window.location.href + "index.html";
}
else {
    document.write("<Your 403 error message here>");
}
pengguna1333371
sumber
1

Saya tahu ini adalah pertanyaan lama, tetapi saya sendiri berjuang melalui ini sendiri. Pada akhirnya, tujuan saya bukanlah untuk menetapkan file default dalam direktori, dan lebih untuk mendapatkan hasil akhir dari file yang disajikan tanpa.html di akhir.

Saya akhirnya menghapus .htmldari nama file dan secara terprogram / manual mengatur jenis mime ke text/html. Ini bukan cara tradisional, tetapi tampaknya berhasil, dan memenuhi persyaratan saya untuk url cantik tanpa mengorbankan manfaat cloudformation. Mengatur jenis pantomim memang menjengkelkan, tetapi harga yang kecil untuk membayar keuntungan menurut saya

whtevn
sumber