Celoteh Angga https://angga.win Pengembang web(?) dengan debuff permanen skill issue yang menulis tanpa arah dan tujuan. Tue, 04 Feb 2025 16:46:52 +0700 Implementasi Content Security Policy https://angga.win/implementasi-content-security-policy https://angga.win/bl-content/uploads/pages/174640dfc3ad621853f7f2ee77d8ee3d/csp-bannerv2.webp <p>Apa itu <em>content security policy</em>? Kurang lebihnya adalah standar keamanan yang diimplementasikan via <em>header</em> dengan sistem <em>whitelist</em> untuk menghindari XSS, <em>clickjacking</em>, dan <em>code injection</em> di situs. Di antara semua proses pengamanan via manipulasi <em>header</em>, ini yang paling ampun <em>riweuh</em> implementasinya, dan dalam kasus-kasus tertentu, sama sekali tidak bisa diimplementasikan, atau jika beruntung, bisa dengan beberapa kompromi.</p> <p>Jadi misalnya dengan implementasi <em>header</em> CSP dengan konfigurasi yang benar, maka hanya <em>script-script</em> dan <em>style</em> dari situs yang sudah di-<em>whitelist</em> yang hanya akan dimuat oleh peramban. Kekurangannya adalah <em>inline script</em> dan <em>inline style</em> yang tidak bisa dan sudah pasti ditolak oleh peramban kecuali menggunakan tuas '<em>unsafe-inline</em>' yang membuat implementasinya menjadi tidak terlalu "aman".</p> <p>Untuk mengatasi hal tersebut, maka dibutuhkan salah satu faktor terpenting dalam implementasi CSP: nonce, atau <em>token</em> sekali pakai yang digunakan oleh peramban untuk verifikasi keaslian "data", jadi untuk <em>script-script inline</em> tersebut bisa dimuat oleh peramban dan tidak diblok.</p> <h2><em>Generate</em> dan Implementasi Nonce</h2> <p>Agar sistem bisa untuk <em>generate</em> nonce sendiri bisa via mod untuk Apache dengan nama <a href="proxy.php?url=https://github.com/wyday/mod_cspnonce">mod_cspnonce</a>. Namun, seperti yang pernah saya sebutkan sebelumnya, mualas, pak. Karena kebetulan menggunakan Cloudflare, kenapa tidak generate saja noncenya via <em>worker</em>-nya Cloudflare? Gratis hingga 100.000 requests/bulan.</p> <p>Lagipula karena pakai Cloudflare ada beberapa script yang di-<em>inject</em> Cloudflare yang perlu di-<em>whitelist</em> dengan nonce juga (atau tambahin via URL <em>whitelist</em> di <em>header</em>, tapi mualaaaas).</p> <p>Untuk itu saya hanya tinggal masuk ke Cloudflare saja, lalu buat <em>worker</em> baru yang saya isi dengan perintah seperti di bawah ini yang merupakan modifikasi ringan dari <a href="proxy.php?url=https://gist.github.com/richie5um/b2999177b27095af13ec619e44742116" target="_blank" rel="noopener">script ini</a>:</p> <pre class="language-javascript"><code>const cspConfig = { "default-src": [ "'strict-dynamic'", "https:", ], "script-src": [ "'unsafe-inline'", "{{cspNonce}}", ], "style-src": [ "'self'", "https://fonts.googleapis.com/", "https://fonts.gstatic.com", "https://cdnjs.cloudflare.com", "https://cdn.jsdelivr.net", "{{cspNonce}}", ], "font-src": [ "'self'", "https://fonts.googleapis.com/", "https://fonts.gstatic.com", "https://cdnjs.cloudflare.com", "https://cdn.jsdelivr.net", "data:", ], "img-src": [ "'self'", "https://cdn.jsdelivr.net", "data:", ], "connect-src": [ "https://fonts.googleapis.com/", "https://fonts.gstatic.com", ], "media-src": [ "'none'", ], "manifest-src": [ "'self'", ], "object-src": [ "'none'", ], "base-uri": [ "'self'", ], "script-src-elem": [ "'self'", "{{cspNonce}}" ] }; function generateCspString(cspConfig, cspNonce) { let cspSections = []; Object.keys(cspConfig).map(function (key, index) { let values = cspConfig[key].map(function (value) { if (value === "{{cspNonce}}") { return value = `'nonce-${cspNonce}'`; } return value; }) let cspSection = `${key} ${values.join(" ")}`; cspSections.push(cspSection); }); return cspSections.join("; "); } function generateCspHeaders(cspConfig, cspNonce) { return { "Content-Security-Policy": generateCspString(cspConfig, cspNonce), "Cache-control": "public" }; } let sanitiseHeaders = { "Server": "Worker", }; let removeHeaders = [ "Public-Key-Pins", "X-Powered-By", "X-AspNet-Version", ]; class AttributeRewriter { constructor(attributeName, oldValue, newValue) { this.attributeName = attributeName this.oldValue = oldValue; this.newValue = newValue; } element(element) { const attribute = element.getAttribute(this.attributeName) if (!(attribute === undefined || attribute === null)) { console.log("AutoNoncing"); if (this.oldValue) { element.setAttribute( this.attributeName, attribute.replace(this.oldValue, this.newValue)); } else { element.setAttribute( this.attributeName, this.newValue); } } } } addEventListener('fetch', event =&gt; { return event.respondWith(addHeaders(event.request)); }); async function addHeaders(req) { let response = await fetch(req) let headers = new Headers(response.headers) if (headers.has("Content-Type") &amp;&amp; !headers.get("Content-Type").includes("text/html")) { return new Response(response.body, { status: response.status, statusText: response.statusText, headers: headers }); } let cspNonce = btoa(crypto.getRandomValues(new Uint32Array(2))); let cspHeaders = generateCspHeaders(cspConfig, cspNonce); Object.keys(cspHeaders).map(function (name, index) { headers.set(name, cspHeaders[name]); }); Object.keys(sanitiseHeaders).map(function (name, index) { headers.set(name, sanitiseHeaders[name]); }); removeHeaders.forEach(function (name) { headers.delete(name); }); // Angular 404 routing handler let status = response.status; let statusText = response.statusText; if (headers.has("Content-Type") &amp;&amp; headers.get("Content-Type").includes("text/html") &amp;&amp; status === 404) { status = 200; statusText = "OK"; } // Auto-Nonce creation const rewriter = new HTMLRewriter() .on("script", new AttributeRewriter("nonce", "", cspNonce)) .on("link", new AttributeRewriter("nonce", "", cspNonce)) .on("style", new AttributeRewriter("nonce", "", cspNonce)); return rewriter.transform( new Response(response.body, { status: status, statusText: statusText, headers: headers }) ); }</code></pre> <p>Simpan <em>worker</em>nya, dan <em>assign</em> untuk <code>https://angga.win/*</code></p> <p></p> <p>Dengan menggunakan perintah yang di atas, maka seluruh <em>script-script</em> yang di-<em>inject</em> oleh Cloudflare, seperti untuk <em>email obfuscation</em>, juga sudah ikut dapat noncenya, jadi sekali jalan, praktis, tinggal implementasi dengan mengikuti tutorial yang ada di halaman Github yang ada di atas dengan menambahkan <code>nonce</code> ke <em>inline script</em>, <em>inline style</em>, <em>3rd party script</em>, atau <em>3rd party style</em> yang nantinya akan langsung diubah oleh <em>worker</em> ke token nonce yang sebenarnya.</p> <p>Contoh:</p> <pre class="language-css"><code>link rel="stylesheet" href="proxy.php?url=situsketiga.ext/styles.css" nonce</code></pre> <p>Yang akan diubah otomatis oleh <em>worker</em> dengan <em>token</em> sekali pakai nantinya, misal akan menjadi: </p> <pre class="language-css"><code>link rel="stylesheet" href="proxy.php?url=situsketiga.ext/styles.css" nonce="MTA5NTM3Mzk1NiwzMTY0MjAwOTA3"</code></pre> <h2>Atur <em>Asynchronous</em> CSS</h2> <p>Kelemahan terbesar CSP adalah belum adanya dukungan untuk <em>inline handler</em> tanpa lagi-lagi menambahkan 'unsafe-inline' di implementasi CSP-nya, dengan kata lain, implementasi terbaik <em>asynchronous</em> CSS dengan <em>inline handler</em> <code>onload</code> tidak lagi berjalan sempurna tanpa tuas 'unsafe-inline'.</p> <p>Jadi satu-satunya cara agar <em>asynchronous</em> CSS dapat tetap diimplementasikan adalah dengan pertama-tama menyatakannya sebagai <code>media="print"</code> agar peramban tidak memuatnya, lalu mengubahnya menjadi <code>media="all"</code> dengan kait <em>class </em>saat situs terpanggil utuh, via Javascript.</p> <p>Jadi, pertama-tama panggil dahulu CSS-nya, misal:</p> <pre class="language-markup"><code>&lt;link rel="stylesheet" href="proxy.php?url=https://cdnjs.cloudflare.com/ajax/libs/picnic/7.1.0/picnic.min.css" integrity="sha512-HZgZOfcUw1rxWuEBlzDis5U4HlbzR0wcWmb3FrLSKV6uhZiZpT9JSTzPJplHDmJZJFNfAReW+iDELJ1kADYHtA==" crossorigin="anonymous" referrerpolicy="no-referrer" media="print" class="asyncCSP" nonce /&gt;</code></pre> <p>Lalu buat <em>script</em>nya di akhir dokumen untuk mengubah <code>media="print"</code> menjadi <code>media="all"</code> via kait <em>class</em> asyncCSP saat situs sudah selesai dimuat penuh.</p> <pre class="language-javascript"><code>&lt;script nonce&gt; document.addEventListener("DOMContentLoaded", () =&gt; { document.querySelectorAll(".asyncCSP").forEach(el =&gt; { el.media = "all" console.log(`Loaded: ${el.href}`) }) }); &lt;/script&gt;</code></pre> <p>Silakan hapus yang baris console.log-nya apabila sudah selesai <em>develop</em>. Saya pribadi tidak menghapusnya karena perasaan cemas yang berlebihan, jadi kadang suka meriksa ke konsol apakah seluruh <em>library-library</em>-nya sudah berhasil termuat, padahal tahu sudah pasti termuat, wk.</p> <h3>Perhatian!</h3> <p>Cara pemanggilan <em>asynchronous</em> CSS seperti di atas akan mengakibatkan <em>content shift</em> yang cukup lumayan saat web dipanggil. Disarankan untuk menggunakan <em>inline critical</em> CSS untuk menghindari <em>content shift</em> yang signifikan.</p> <p>Saya sendiri pakai, tapi masih ada <em>content shift </em>yang cukup signifikan selama beberapa saat web dipanggil pertama kali, namun akan kembali normal untuk pemanggilan berikutnya sampai <em>cache</em> di disk dihapus untuk waktu berkala berikutnya.</p> <p>Solusi? Debug manual <em>inline critical</em> CSS-nya sampai hilang <em>content shift</em>-nya saat pertama kali memuat situs, tapi yawda deh mualas, pak.</p> <h2>Implementasi CSP</h2> <p>Ada beberapa cara implementasi CSP dengan implementasi via <em>header</em> webserver sebagai salah satu solusi terbaik, misalnya apabila menggunakan Apache bisa via dengan menambahkan <em>header</em> di .htaccess-nya. Namun karena saat ini menggunakan Bludit dan di halaman admin Bludit sendiri <em>inline script</em> dan <em>inline style</em>-nya cukup banyak, tentu implementasi via header webserver ini yang bersifat global akan menjadi masalah sendiri.</p> <p>Kecuali misalnya rela ngedit fail-fail di halaman adminnya satu-satu buat nambahin nonce-nya setiap update versi Bludit sih yaaa, silakan ya, wk.</p> <p>Sebelumnya cara yang untuk saya pribadi paling cocok adalah dengan menambahkan header via php, satu untuk yang di <em>front-end</em>, dan satu lain untuk yang <em>back-end</em>-nya Bludit.</p> <p>Contoh yang saya pakai di <em>front-end</em> situs saya via fail header theme-nya:</p> <pre class="language-php"><code>&lt;?php header("Content-Security-Policy: default-src 'strict-dynamic' 'unsafe-inline' https: 'nonce'; font-src 'self' https://fonts.googleapis.com/ https://fonts.gstatic.com https://cdnjs.cloudflare.com 'nonce-DhcnhD3khTMePgXw'; img-src 'self' data:; connect-src 'self' https://fonts.googleapis.com/ https://fonts.gstatic.com 'nonce'; style-src 'self' https://fonts.googleapis.com/ https://fonts.gstatic.com https://cdnjs.cloudflare.com 'nonce'; base-uri 'self'; object-src 'none'; script-src-elem 'self' 'nonce"); ?&gt;</code></pre> <p>'unsafe-inline' di situ hanya untuk <em>backward compatibility</em> saja ya untuk peramban yang lama, karena sudah pakai 'strict-dynamic' untuk default-src-nya, jadi kalau ada nonce misalnya, 'unsafe-inline'-nya di-<em>bypass </em>di peramban baru. Sementara untuk <em>source-source</em> yang di-<em>whitelist</em>-nya itu saya main salin tempel aja dari satu ke yang lainnya karena malas ya, jangan ditiru, wakakaka.</p> <p>Misal, di font-src itu ga perlu ada dua-duanya fonts.googleapis sama fonts.gstatic, cuma butuh yang gstatic, tapi males ah, kopas-aeeee biar seragam semua.</p> <p>Pengecualian untuk <code>img-src</code> karena saya ada menggunakan inline svg, jadi harus ditambah <code>data:</code>.</p> <p>Kemudian untuk yang di <em>back-end</em> bluditnya bisa diedit di fail login.php dan index.php yang ada di folder themes untuk admin, saat ini hanya theme "booty." Isinya hampir mirip dengan yang di atas, tapi cuma 'self' dan 'unsafe-inline' saja <em>toggle-</em>nya sama ada beberapa <code>data:</code> untuk <em>inline</em> font dan svg.</p> <p>Contohnya:</p> <pre class="language-php"><code>&lt;?php header("Content-Security-Policy: default-src 'self'; font-src 'self' data: 'unsafe-inline'; img-src 'self' data:; connect-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'self'; object-src 'none'; script-src 'self' 'unsafe-inline';"); ?&gt;</code></pre> <p>Tapi kemudian saya memutuskan untuk langsung inject saja semuanya via worker Cloudflare seperti yang sudah saya tempel di konfigurasi worker di atas. Jadi saya tidak perlu lagi membuat konfigurasi php header terpisah:</p> <pre class="language-javascript"><code>const cspConfig = { "default-src": [ "'strict-dynamic'", "https:", ], "script-src": [ "'unsafe-inline'", "{{cspNonce}}", ], "style-src": [ "'self'", "https://fonts.googleapis.com/", "https://fonts.gstatic.com", "https://cdnjs.cloudflare.com", "https://cdn.jsdelivr.net", "{{cspNonce}}", ], "font-src": [ "'self'", "https://fonts.googleapis.com/", "https://fonts.gstatic.com", "https://cdnjs.cloudflare.com", "https://cdn.jsdelivr.net", "data:", ], "img-src": [ "'self'", "https://cdn.jsdelivr.net", "data:", ], "connect-src": [ "https://fonts.googleapis.com/", "https://fonts.gstatic.com", ], "media-src": [ "'none'", ], "manifest-src": [ "'self'", ], "object-src": [ "'none'", ], "base-uri": [ "'self'", ], "script-src-elem": [ "'self'", "{{cspNonce}}" ] };</code></pre> <p>Masalahnya adalah <em>backend</em>-nya yang harus dikonfigurasi secara terpisah seperti yang sudah tertulis di atas. Dan karena saya injeksi langsung via Cloudflare, maka konfigurasi header php pun sudah tidak ada pengaruhnya sama sekali. Solusinya adalah dengan melakukan rute <em>bypass </em>untuk URL untuk halaman admin.</p> <p>Masuk ke Cloudflare, ke bagian manajemen domain yang ingin di-<em>bypass</em>, pilih bagian untuk <em>Routes</em>, lalu buat <em>route</em> URL admin dengan <em>worker</em> NONE.</p> <p><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/174640dfc3ad621853f7f2ee77d8ee3d/firefox_2025-02-04_15-59-22.png" alt=""></p> <p>Saya sarankan untuk tetap memasang contoh php header yang sudah saya contohkan di atas khusus untuk halaman admin tersebut.</p> <pre class="language-php"><code>&lt;?php header("Content-Security-Policy: default-src 'self'; font-src 'self' data: 'unsafe-inline'; img-src 'self' data:; connect-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'self'; object-src 'none'; script-src 'self' 'unsafe-inline';"); ?&gt;</code></pre> <h3>Perhatian!</h3> <p>Jangan salin dan tempel saja contoh implementasi CSP via injeksi Cloudflare di atas ya, karena tiap orang, tiap situs, kebutuhan untuk <em>whitelist-</em>nya beda-beda, jadi harus benar-benar dicek satu per-satu via konsol di perambannya apakah semua <em>resources</em> sudah terload dengan sempurna. Emang repot sih, tapi ya begitu lah implementasi CSP.</p> <p>Oiya, yang https: doang untuk default-src seperti yang saya buat di atas untuk <em>backward compatibility</em>nya itu ga aman ya. Itu karena mualas aja satu-satu masukin lagi <em>sources</em>-nya, alias saya goblo, jangan ditiru.</p> <h2>Tes!</h2> <p>Jangan lupa untuk selalu cek konsol perambannya untuk melihat apakah ada <em>script</em> atau <em>styles</em>, atau <em>resource</em> apapun yang terblok oleh <em>Content Security Policy</em>-nya dan edit kembali <em>header</em>nya sesuai dengan kebutuhan. Berikut adalah hasil tes untuk implementasi saya untuk <em>content security policy</em> di angga.win via <a href="proxy.php?url=https://csp-evaluator.withgoogle.com/">CSP Evaluator</a>.</p> <p><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/174640dfc3ad621853f7f2ee77d8ee3d/hasil-csp-evaluator.webp" alt="Gambar adalah tangkapan layar hasil test website saya di csp evaluator dengan hasil semua centang hijau dan lambang perisai csp berubah menjadi hijau" width="893" height="827"></p> <p>Hijau-hijau mas broooo, wakakaka!</p> <p>Dan tentu saja karena CSP yang paling ribet sudah teratasi, nilai di <a href="proxy.php?url=https://securityheaders.com/?q=https%3A%2F%2Fangga.win&amp;hide=on&amp;followRedirects=on">securityheaders.com</a> juga sudah A+.</p> <p><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/174640dfc3ad621853f7f2ee77d8ee3d/hasil-probely.webp" alt="Hasil testing di Security Headers Probely mendapatkan nilai A+" width="893" height="453"></p> <p>Untuk <em>backend</em>-nya ya yang jelas di CSP Evaluator dapat perisai merah, wakakaka!</p> <h2>Kesimpulan</h2> <p>Ribet dan ngeselin parah sih, wk. Menurut saya pribadi, karena saya orangnya mungkin terlalu konservatif kali ya (atau memang terlalu nubi...), saya rasa lebih baik menghabiskan waktu pertama kali untuk keamanan yang paling dasar dulu sih, seperti konfigurasi SSH agar bisa masuk hanya bisa dengan <em>keypair</em> saja, ubah port SSH, lalu setup mod_security/WAF dengan <em>rules</em>, terserah mau rules yang mana aja, boleh Comodo, boleh OWASP, boleh yang lain, dan ya testing <em>rules</em> mod_security-nya dan <em>whitelist</em> seperlunya sesuai kebutuhan.</p> <p>Menurut saya itu yang paling dasar, bisa dilanjut dengan <em>setup firewall</em> dan lain-lain selanjutnya.</p> <p>Kalau misalnya masih ada energi untuk setup <em>security header</em> seperti CSP lagi berikutnya yaa lebih bagus dan mantap.</p> <p>Saya sendiri bukan ahli keamanan atau gimana-gimana juga sih, jadi kayanya juga ga ada <em>authority</em> kalau ngomongin masalah <em>security</em>, jadi maaf apabila blog-nya malah menyesatkan, wk. Cuma ya, seneng aja gitu ngeliat hijau-hijau setelah sebelumnya gagal implementasi CSP di situs klien karena konfigurasi-nya tabrakan, wakakaka.</p> Wed, 04 Oct 2023 12:16:07 +0700 174640dfc3ad621853f7f2ee77d8ee3d Tema Simpel dan Cerah untuk Bludit: Solen https://angga.win/tema-simpel-dan-cerah-untuk-bludit-solen https://angga.win/bl-content/uploads/pages/4cac47cc27fe532bb9f080c2a2b49cb4/solen.webp <p>Akhirnya selesai juga tema yang akan digunakan untuk blog pribadi ini. Memutuskan untuk menggunakan Picnic CSS yang ternyata tidak terlalu bersahabat dengan pembaca layar di struktur menunya, bisa diakalin jadi tidak masalah.</p> <p>Bercita-cita untuk menyajikan tiga bahasa untuk teks-teks yang nantinya akan sangat berguna bagi screen reader dan sedikit tersandung di pengetahuan Bahasa Jepang saya yang masih N3 tidak lulus-lulus. Terima kasih untuk <a href="proxy.php?url=https://twitter.com/schiko_" title="Twitter Chiko">Chiko</a> yang sudah membantu untuk terminologi-terminologi yang saya tidak ketahui!</p> <h2 id="unduh">Tautan Unduh</h2> <p><a href="proxy.php?url=https://github.com/anggackt/solen-bludit/releases/latest/download/solen.zip">Unduh di GitHub</a></p> <h2>Tangkapan Layar</h2> <p><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/4cac47cc27fe532bb9f080c2a2b49cb4/solen-screenshot.webp" alt="Tangkapan layar dari tema Bludit yang saya buat, Solen." width="893" height="818"></p> <p>Berikut detil dari theme Solen untuk Bludit yang dirilis dengan lisensi MIT! Semoga ada yang memakai dan suka atau bahkan semakin mengembangkannya karena saya yakin pasti masih banyak kurang dan salahnya lol.</p> <h2>Bahasa Indonesia</h2> <h3>Tema Solen untuk Bludit</h3> <p>Sebuah tema blogging yang sederhana dan cerah yang dibuat dengan menggunakan Picnic CSS dengan dukungan untuk pengguna pembaca layar (<em>screen reader</em>).</p> <h3>Fitur</h3> <ul> <li>Sangat ringan digunakan di desktop dan peramban web <em>mobile </em>dengan desain responsif</li> <li>Dukungan untuk pembaca layar (<em>screen reader</em>)</li> <li>Dukungan untuk tiga bahasa: Bahasa Indonesia, Inggris, dan Jepang</li> <li>Rasio kontras yang baik (Sesuai standar WCAG 2.1 AA)</li> <li><em>Critical inline </em>CSS dan juga memuat CSS dengan cara <em>asynchronous</em></li> <li>Penggunaan Javascript yang minimal dan tidak intrusif</li> </ul> <h3>Kompatibilitas</h3> <p>Bludit 3.15.0</p> <h3>Lisensi</h3> <p>MIT</p> <h2 id="english">English</h2> <h3>Solen for Bludit Theme</h3> <p>A bright and simple Bludit blogging theme made with Picnic CSS with support for screen reader users.</p> <h3>Features</h3> <ul> <li>Very light on various desktop and mobile browser with responsive design</li> <li>Support for screen reader users</li> <li>Three languages support: Indonesian, English, and Japanese</li> <li>Good contrast ratio (WCAG 2.1 AA Compliant)</li> <li>Critical inline CSS and asynchronous CSS load</li> <li>Made with Picnic CSS</li> <li>Minimal and non-intrusive use of Javascript</li> </ul> <h3>Compatibility</h3> <p>Bludit 3.15.0</p> <h3>License</h3> <p>MIT</p> <h3>How to Install</h3> <ul> <li>Download the compressed file from the link <a href="proxy.php?url=#unduh">above</a></li> <li>Upload the compressed file to bl-themes folder on your bludit installation</li> <li>Unzip the compressed file</li> <li>Activate the theme from your bludit admin panel</li> </ul> <h3>How to Change the Logo and Welcome Message</h3> <ul> <li>You can change the logo by uploading your logo to the img folder and then altering the header.php file inside the php folder. Change <code>img/logo.svg</code> to <code>img/YOUR_LOGO_HERE.EXT</code></li> <li>You can also change the welcome message by altering your language file inside the languages folder. Example from <code>"welcome": "Welcome!",</code> to <code>"welcome": "Welkom!",</code></li> </ul> Tue, 03 Oct 2023 14:59:17 +0700 4cac47cc27fe532bb9f080c2a2b49cb4 Portfolio https://angga.win/portfolio <p>Portfolio alias beberapa proyek yang sudah atau sedang saya kerjakan. Diambil dari beberapa tahun lalu, setidaknya 2018, yang mungkin masih sedikit relevan dengan perkembangan teknologi yang semakin pesat di beberapa tahun belakangan ini.</p> <h2>Pembuatan Situs Web</h2> <h3>Bumi Kepanasan (April 2023)</h3> <p>Membuat situs disertai dengan form CRUD <em>custom</em> untuk mendata pengunjung yang ingin berpartisipasi dalam kampanye yang meningkatkan kesadaran untuk pemanasan global.</p> <p>Dibuat dengan menggunakan HTML disertai dengan basic Aria tag, CSS (<em>framework</em> Bootstrap), serta <em>custom white-label</em> CMS dan PHP.</p> <p><a href="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/bumikepanasan.webp"><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/bumikepanasan.webp" alt="Tangkapan layar bumikepanasan.com" width="893" height="655"></a></p> <p><a href="proxy.php?url=https://bumikepanasan.com/">Tautan langsung</a> | <a href="proxy.php?url=https://web.archive.org/web/20230724062735/https://bumikepanasan.com/">Tautan di Archive.org</a></p> <hr> <h3>Cek Suaramu (Mei 2022)</h3> <p>Implementasi desain klien menjadi sebuah situs dinamis dengan menggunakan HTML, CSS (<em>framework</em> Bootstrap), Javascript, dan <em>custom white-label</em> CMS.</p> <p><a href="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/ceksuaramu.webp"><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/ceksuaramu.webp" alt="Gambar adalah tangkapan layar situs web semuatercatat" width="893" height="419"></a></p> <p><a href="proxy.php?url=https://ceksuaramu.com/">Tautan langsung</a> | <a href="proxy.php?url=https://web.archive.org/web/20220712060002/https://ceksuaramu.com/">Tautan di Archive.org</a></p> <hr> <h3>Semua Tercatat (Desember 2021)</h3> <p>Implementasi desain klien ke HelpJuice, sebuah SaaS untuk sistem <em>knowledge base</em>. Dikerjakan dengan menggunakan HTML, CSS, dan <em>templating language</em> internal dari HelpJuice.</p> <p><a href="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/semuatercatat.webp"><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/semuatercatat.webp" alt="Tangkapan layar Semua Tercatat dari archive.org" width="893" height="549"></a></p> <p><a href="proxy.php?url=https://web.archive.org/web/20220309111546/http://semuatercatat.id/">Tautan di archive.org</a></p> <hr> <h3>Amarylis Hotel &amp; Resort (Agustus 2018)</h3> <p>Mengubah konsep desain dari klien menjadi situs web dinamis. Dikerjakan dengan menggunakan HTML, CSS, dan <em>custom white-label</em> CMS.</p> <p><a href="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/amarylis.webp"><img src="proxy.php?url=https://angga.win/bl-content/uploads/pages/6b9848f465aeeb9dc7fcb5ef6df3a98a/amarylis.webp" alt="Tangkapan layar halaman web Amaryllis Hotel &amp; Resort" width="893" height="445"></a></p> <p><a href="proxy.php?url=https://www.theamaryllisresort.com/">Tautan langsung </a>| <a href="proxy.php?url=https://web.archive.org/web/20230609055129/https://www.theamaryllisresort.com/">tautan di Archive.org</a></p> <h2>Administrasi Sistem</h2> <p>Menjadi administrator sistem beberapa peladen untuk beberapa pelanggan menggunakan sistem operasi turunan Centos seperti AlmaLinux dan beberapa jenis panel kontrol seperti WHM dan CyberPanel, yang dikarenakan sifat pekerjaannya tidak dapat diberitahukan secara detil.</p> Sun, 01 Oct 2023 15:26:35 +0700 6b9848f465aeeb9dc7fcb5ef6df3a98a Membangun Rumah Baru Bagian 2: Apache https://angga.win/membangun-rumah-baru-bagian-2-apache https://angga.win/bl-content/uploads/pages/aad1bcc53870a2f26f72faacb5de66a5/apache-banner.webp <p>Masalah CMS sudah diputuskan untuk menggunakan Bludit karena simpel dan menggunakan flat file. Sekarang masuk ke masalah baru, perangkat lunak yang akan dipasangkan di VPS NAT-nya. Karena jelas ini <em>oversell</em> dan <em>burstable</em>, jadi harus ada beberapa pertimbangan untuk <em>webserver</em>.</p> <p>Pertama mikirnya ya pakai Caddy atau Nginx, karena sangat ringan, tapi kok ya ngerasanya rada <em>riweuh</em> karena harus atur konfigurasi sana-sini lagi, ngubah <em>rules</em> .htaccess ke <em>rules</em> yang dipakai oleh Caddy atau Nginx, dan lain sebagainya. Bisa tapi mualas pak, jujur.</p> <p>Pilihan kedua tentu saja menggunakan <em>reverse proxy </em>Nginx dengan Apache, Nginx bisa meladeni konten statis dan Apache untuk konten dinamisnya. Nah, ini lebih-lebih <em>riweuh</em> lagi kecuali pakai <em>batch installer </em>dan tentu saja ngatur gini-gononya bakalan pusing lagi secara ini pakai NAT-only VPS, atau emang <em>skill issue</em> aja wakakakak, nubi kak.</p> <p>Pilihan ketiga adalah yang paling gampang dan <em>user-friendly</em>, dengan memasang CyberPanel dan memanfaatkan antara OpenLiteSpeed yang sekarang bisa membaca rules .htaccess walaupun masih hanya untuk <em>rewrite </em>atau LiteSpeed Enterprise, cuma 1 web ini, gratis.</p> <p>Masalahnya adalah NAT-only VPS yang hanya menyediakan IPv6 untuk akses publiknya, wakakaka, jadi mau akses admin panelnya yang terikat dengan IP shell-nya yang IPv4 ga bisa . Saya yakin pasti ada caranya sih, cuma ya itu kak, <em>skill issue </em>dan mualas dari orok, ehehe.</p> <p>Akhirnya diputuskan untuk pakai standar Apache saja, toh ini juga karena NAT-only harus dilapis lagi pakai CloudFlare biar publik yang belum bisa akses IPv6 (alias hampir semua orang umum), bisa akses situsnya.</p> <p>Lagian instalasi Apache sekarang standarnya udah bagus kok, <em>usage memory</em>-nya <em>default</em>nya udah engga gila-gilaan lagi, jadi saya rasa sudah cocok lah dengan tujuan saya yang ingin semalas-malasnya mengurus <em>backend</em>nya.</p> <p>Jadilah! Selamat datang di Celoteh Angga!</p> Fri, 29 Sep 2023 08:30:00 +0700 aad1bcc53870a2f26f72faacb5de66a5 Membangun Rumah Baru Bagian 1: Bludit https://angga.win/membangun-rumah-baru-bagian-1-bludit https://angga.win/bl-content/uploads/pages/46bca0b9c2623c94cda533b9a3a4d4ab/cerita-bludit.webp <p>Akhirnya memutuskan membuat rumah baru sekalian untuk portfolio setelah sebelumnya menggunakan <a href="proxy.php?url=https://www.tumblr.com/anggablog">Tumblr</a> yang cukup simpel digunakan dan tidak perlu desain sana-sini lagi. Namun banyak sekali pertimbangan yang dilakukan sebelumnya kerena tidak ingin terlalu <em>riweuh </em>di urusan CMS yang digunakan dan segala macam <em>tetek-bengek</em>-nya<em>.</em></p> <p>Untuk CMS ini tentu saja harus menggunakan yang ringan, karena VPS yang dimiliki dan digunakan saat ini adalah NAT VPS di Norwegia yang memiliki RAM dan CPU super terbatas dalam kontainer OpenVZ yang tentu saja <em>burstable</em>, alias sudah dapat dipastikan <em>oversell</em> la ya secara cuma bayar Rp.150.000 saja untuk setahun, hahaha!</p> <p>Karena hal tersebut akhirnya diputuskanlah untuk menggunakan <em>flat file </em>CMS agar VPS tidak lagi diperberat dengan proses untuk database konvensional seperti MySQL misalnya. Beberapa pilihan yang akhirnya masuk pertimbangan antara lain:</p> <ul> <li>Pico CMS</li> <li>Grav</li> <li>Bludit</li> </ul> <p>Setelah mempertimbangkan banyak hal termasuk kemudahan pengoperasian serta <em>theme-ing</em>, karena ingin membuat <em>theme</em> sendiri sekalian untuk portfolio, akhirnya pilihan jatuh ke Bludit, yay! Walaupun jujur sebenarnya memilih Bludit karena dasbor adminnya simpel, wk.</p> <p>Pertimbangan secara teknis lainnya kayanya ga ada ya, secara emang kurang ngerti juga selain ngeliat, "Oh! Di Github mayan aktif kok," dan ngecek sejarah laporan <em>vuln</em>-nya di NVD via Stack Watch walaupun ga ngerti-ngerti amat.</p> <p>Adapun kekurangan Bludit yang paling terasa saat ini adalah dukungan yang kurang baik untuk format .webp, seperti misalnya unggah foto profil yang otomatis diubah menjadi PNG dengan kualitas tinggi sehingga gambar menjadi terlalu besar untuk fungsi web.</p> <p>Bisa diakalin sih, jadi <em>no problemo, </em>kok.</p> <p>Sama mungkin kalau sudah terbiasa menggunakan Wordpress akan terasa sangat sederhana sekali. Tapi ini yang saya cari, ga mau <em>riweuh</em> pokoknya lah, mau fokus ke produktif bikin theme sama bangun portfolio lagi dari nol (?).</p> <p>Berikutnya adalah pertimbangan <em>theme</em> seperti apa yang ingin dibuat, bisa dilihat di <em>theme</em> yang dipakai sekarang, dan juga menggunakan <em>software</em> apa-apa saja di VPSnya, dan tentu saja menambah portfolio desainnya, biar ada yang mau ngekomis buat <em>job</em> desain, hiks.</p> <p></p> Thu, 28 Sep 2023 17:55:57 +0700 46bca0b9c2623c94cda533b9a3a4d4ab