Archiv autora: Tomáš Jacík

Jak inkrementovat IPv6 adresu v PHP

PHP nativně nepodporuje dostatečně velká (128 bit) čísla, aby bylo inkrementování decimální reprezentace IPv6 adresy (jednoduše) možné. Pro zjednodušení tedy budeme potřebovat GMP extension.

Nejdříve je potřeba převést IP adresu do binární podoby a instanciovat GMP číslo:

Poté můžeme IP inkrementovat tak, jak jsme zvyklí:

Nakonec IP převedeme zpět do klasického formátu:

Nebo pokud preferuje dlouhý formát adresy:

Jak přesunout SmartOS image z jednoho serveru na druhý

Nedávno se mi stalo, že jsem potřeboval přesouvat SmartOS zónu z jednoho serveru na druhý. Zóna ale byla vyrobená z obrazu base-64-lts ve verzi 16.4.0. Tuhle verzi kvůli fatální chybě při upgradu stáhli z veřejného repozitáře.

Řešením by bylo dataset zóny povýšit pomocí zfs promote. Co když ale raději chceme origin zóny zachovat a přenést jej na nový server? Nástroj imgadm bohužel nic jako export neposkytuje. Naštěstí si ale můžeme poradit ručně.

Nejprve přeneseme dataset:

Poté přesuneme konfiguraci pro imgadm:

Nesmíme zapomenout na lock soubor, který imgadm používá, aby určil, zda je již daný image naimportovaný:

A to je vše 🙂

Vlastní certifikační autorita pro přihlašování k SSH

Při přihlašování k SSH jste jistě již mockrát viděli hlášku, jako je tato:

Většinou ji napoprvé bezmyšlenkovitě potvrdíme a všímáme si jí pouze v případě, že se objeví znovu. Značí to, že je něco špatně. Jak se ale této hlášce vyhnout úplně? Ověřování fingerprintu jistě nechceme vypnout, to by nebylo moc bezpečné 🙂 Jak tedy na to jinak? Založíme si pro SSH vlastní CA!

Nejprve si musíme vygenerovat podepisovací klíč.

Příkaz nám vygeneroval dva soubory ca.ed25519 a ca.ed25519.pub. Ukážu zde pouze generování pro algoritmus ED25519, pro jiné algoritmy je postup obdobný.

Nyní potřebujeme veřejný klíč serveru, ke kterému se budeme přihlašovat. Ten pak podepíšeme a podepsaný klíč nahrajeme zpět na server.

Nyní bude potřeba říct o novém certifikátu SSH serveru. Přidáme do /etc/ssh/sshd_config jeden řádek a restartujeme SSH.

Nyní můžeme na všech počítačích, které se potřebují k serveru přihlašovat, přidat do ~/.ssh/known_hosts veřejný klíč naší nové CA.

SSH se již nebude ptát na potvrzení fingerprintu. Pokud soubor přidáváe na počítač, ze kterého jste certifikáty kopírovali, máte již cílový server v known_hosts přidaný. Musíme jej tedy ještě vymazat.

Jak zrychlit PrestaShop 1.6 s minimem úprav

Dlouhé roky pro zákazníky dělám rychlostní optimalizace webových aplikací. Nejčastěji se přitom jedná o různý Open Source software. V případě eshopu je to o to horší, že dlouhé načítání snadno odradí zákazníky od nákupu.

PrestaShop je v dnešní době asi nejlepším Open Source eshopem vůbec. To nic nemění na tom, že pokud to myslíte s online prodejem vážně, měli byste se mu obloukem vyhnout. Nebudu se tu dnes zabývat tím, proč tomu tak je. To je téma na jiný článek. Dnes si řekneme, jak s dobou jeho načítání jednoduše něco udělat pár úpravami, pokud jej již nasazen máte.

Často zákazníkům radím, že levnější než sahat do kódu je jít na to „hrubou silou™“. Tedy pořídit výkonnější server nebo VPS. V tomto případě ale ani přesun na výkonný server dobu načítání příliš nezkrátil. Chtěl jsem tedy zkusit, co se s tím dá udělat v rámci zákazníkova malého rozpočtu.

Tento návod je pro verzi PrestaShop 1.6.1.6, ale pravděpodobně bude fungovat i na ostatní verze PrestaShop 1.6. Vliv úprav jsem měřil pomocí nástroje Blackfire.io, který byl v odhalování nejhorších prohřešků velmi nápomocen. Veškeré testy byly prováděny s vypnutou cache, abych dostal relevantní výsledky. Také jsem se primárně zaměřil jen na výpis kategorie, který trval nejdéle. Provedené úpravy však často pomůžou i v jiné části shopu.

Něco málo o množství dat v databázi eshopu:

  • 95 900 produktů
  • 3 700 kategorií
  • 129 000 obrázků
  • Jen minimum variant
  • Jen minimum vlastností produktů
  • Bez příslušenství
  • 3 základní uživatelské skupiny
  • 4 jazyky
  • Aktivovaný modul „Blok Filtrování zboží dle parametrů“ (blocklayered)

VPS server, na kterém shop běžel:

  • 8 virtuálních jader
  • 16 GB paměti RAM
  • 240 GB místa na disku (RAID10, SATA 7200rpm)

Počáteční stav načítání kategorie před úpravami vypadal takto:

Jak zrychlit PrestShop 1.6 s minimem úprav 1

Problém 1

Modul blockcategories volá v metodě getTree() pro každou jednotlivou kategorii metodu Link::getCategoryLink() (soubor classes/Link.php). Nepředává jí ovšem instanci kategorie, ale jen její id a link_rewrite. V metodě Link::getCategoryLink() pak najdeme takovýto kód:

Tedy pro každou z 3700 kategorií se vytvoří instance třídy Category a její data se načtou z databáze! Také máte pocit, že se páni vývojáři PrestaShopu někde museli upsat? Jak by tedy metoda měla vypadat?

Co jsme upravili?

  • Zakomentovali jsme načtení kategorie do objektu a tím snížili nápor na databázi o 3700 SQL dotazů. Samotné instanciování třídy Category nám také dost času ušetří.
  • Upravili jsme řádek 13, aby se do pole $params správně nastavilo id kategorie v závislosti na tom, zda nám do metody přijde objekt, nebo jen id.
  • Zakomentovali jsme přiřazení parametrů meta_keywords a meta_title do pole $params. Dalším zkoumáním kódu jsem zjistil, že jsou potřeba jen v případě, že si je nastavíte do pole „Cesta ke kategoriím“ v nastavení eshopu. Vůbec mě nenapadá, proč by někdo něco takového chtěl dělat, když má k dispozici parametr rewrite 🙂

Poslední bod by samozřejmě šel řešit mnohem elegantněji, podobně jako řádek 13. Museli bychom však zajistit, že nám tyto parametry přijdou už na vstupu. To by znamenalo upravit veškeré SQL dotazy, jejichž výsledky vstupují do metody Link::getCategoryLink() napříč celým shopem. To by ovšem bylo na delší dobu a nebylo to tím pádem předmětem zakázky.

Jak tato jednoduchá úprava pomohla? Zkrátili jsme načítání kategorie o 4,6 vteřiny!

Jak zrychlit PrestShop 1.6 s minimem úprav 2

Problém 2

Modul blocktopmenu volá v metodě generateCategoriesMenu() (soubor modules/blocktopmenu/blocktopmenu.php) opět naši známou Link::getCategoryLink(), jen schovanou do metody Category::getLink(). Tentokrát ale nenechává instanciování třídy Category na metodě getCategoryLink(), ale vytváří ji sám. Zkrácený kód metody vypadá takto:

Přitom potřebný link_rewrite ve výsledku SQL dotazu již máme. Můžeme tedy jednoduše instanciování třídy Category opět vynechat a předat metodě Link::getCategoryLink() pouze potřebné údaje:

Jak nám tato úprava pomohla? Zkrátili jsme načítání kategorie o dalších 700 ms! Není to již tolik jako předtím, ale dostáváme se už na vcelku přijatelné 2 vteřiny dvěma jednoduchými úpravami.

Jak zrychlit PrestShop 1.6 s minimem úprav 3

Problém 3

Modul blockcategories vybírá z databáze v metodě hookFooter() (soubor modules/blockcategories/blockcategories.php) celý strom kategorií. Přitom v šabloně, kterou zákazník použil, jsou v patičce stránky vypsány jen top-level kategorie. Je tedy trochu zbytečné vybírat kategorie všechny. Co myslíte? Můžeme tedy řádek:

snadno upravit takto:

Pokud máte v patičce stránky i podkategorie, upravte hodnotu $maxdepth dle vlastního uvážení a potřebné hloubky.

Jak nám tato úprava pomohla? Snížili jsme načítání kategorie o dalších 600 ms!

Jak zrychlit PrestShop 1.6 s minimem úprav 4

Nyní už se výpis kategorie načítá vcelku přijatelných 1,39 vteřin. Moje práce pro zákazníka tedy po 2,5 hodině ladění končí. Dalo by se jistě pokračovat mnohem dál. A nejen na výpisu kategorie, ale i jiných stránkách, které mají zase svoje vlastní specifika.

Pro zajímavost ještě ukážu, jak rychle se kategorie načte po zapnutí cache:

Jak zrychlit PrestShop 1.6 s minimem úprav 5

Výkonovému ladění zdar!

Jak na vybírání pošty z jiných schránek do Seznamu

Často se setkávám s tím, že lidé, kterým píšu, mají nastaveno přesměrování z mailu na vlastní doméně do mailu na seznamu. Je to jistě nejjednodušší způsob, jak mít všechny maily v Seznam schránce, pokud jste na ni zvyklí. Mám to ale jedno úskalí. Pokud má člověk, který vám píše nastaveno zabezpečení své domény pomocí SPF, vrátí se mu chybová zpráva a mail, který vám psal, nebude doručen.

K čemu je SPF dobré a proč by vás to mělo zajímat? V dnešní době všichni bojujeme se spamem. SPF a další technologie, jako je např. DKIM přispívají k tomu, aby nám do schránek chodilo spamu méně. SPF funguje tak, že řekne cílovému serveru (v našem případě Seznamu), z jakých serverů smí přijímat emaily od daného odesílatele. Díky tomu spamer, který by chtěl poslat email vaším jménem (podvrhnout jako odesílatele vaši emailovou adresu), nepochodí, protože jeho server není povolený odesílatel pro danou emailovou adresu.

Proč tedy vadí, že si necháte přeposílat maily ze své domény na Seznam? Pokud vám pošlu mail, řekněme z adresy mujmail@mojedomena.cz na vaši adresu vasmail@vasedomena.cz a ten je přesměrován do schránky Seznamu, pochopitelně zůstane jako odesílatel mailu nastaven mujmail@mojedomena.cz. Pokud mám však svoji doménu zabezpečenou pomocí SPF, váš server není oprávněn odesílat maily z mojedmena.cz a Seznam tedy mail vyhodnotí jako spam. Vám mail nepřijde a mě přijde jen chybová zpráva.

Jak to napravit? Na Seznamu si můžete nastavit vybírání pošty z jiných schránek. Seznam pak přímo stahuje maily z vaší domény a nedochází k nežádoucímu přesměrování. Jak toto vybírání pošty nastavit?

Nejprve se přihlaste do své schránky na Seznamu. Nahoře vpravo pak klikněte na Nastavení.

Seznam_vyber_posty_1

V nově otevřeném okně klikněte v levém menu na položku Účty a import. Poté na tlačítko Přidat další účet pod nadpisem Propojení schránek.

Seznam_vyber_posty_2

V select boxech vyberete v prvním Doručené (do této složky vám budou maily z vaší domény chodit) a v druhém Jiný. Doplníte váš email, heslo ke schránce a adresu POP3 serveru. Tuto adresu by vám měl sdělit váš poskytovatel, nebo ji najdete v administraci vaší domény (tam kde si zakládáte schránky), pokud takovou od poskytovatele máte. Port by v závislosti na tom, zda mailový server na vaší doméně podporuje šifrovanou komunikaci, měl být 995. Pokud ji nepodporuje, port bude 110. Tuto informaci by vám opět měl sdělit váš poskytovatel. Je samozřejmě vždy bezpečnější používat šifrovanou komunikaci.

Seznam_vyber_posty_3

Po kliknutí na Uložit účet by mělo být vybírání schránky nastaveno.

Seznam_vyber_posty_4

Jak rozdělit GIT repozitář na více menších a zachovat/promazat historii

Semtam se stane, že se aplikace rozroste, moduly přibývají a jejich doménový model se začně čím dál více lišit. Nastal čas aplikaci rozdělit. Prvním krokem, ještě před úpravami kódu by mělo být rozdělení GIT repozitáře. Můžeme na to jít více způsoby:

1. Zkopírovat repozitář a vymazat z něj nepotřebné soubory

Je to rychlé a vcelku bezpečné. V repozitáři nám ale zůstane kompletní historie souborů ostatních aplikací a klonování každého repozitáře bude kvůli tomu trvat zbytečně dlouho.

2. Založit nový, čistý repozitář a commitnout do něj jen potřebné soubory

Je to opět rychlé a vcelku bezpečné. V repozitáři nám ale nezůstane ani historie souboru oddělované aplikace. Budeme sice mít zálohu v podobě originálního repozitáře před rozdělením, nebude se s tím ale moc pohodlně pracovat.

3. Použít git filter-branch a upravit historii zkopírovaného repozitáře

Moje oblíbená varianta. Je sice náročnější na čas a snadno se při ní udělá nějaká chyba. Odměnou je ale čistý repozitář, který obsahuje jen soubory oddělované části aplikace včetně jejich historie. Nyní si ukážeme jak na to.

Naklonujeme si originální repozitář

Přepneme se do složky repozitáře a projistotu odstraníme jeho remote.

Získáme seznam všech souborů v historii včetně smazaných

Tento krok není nutný, pokud nejste puntičkáři jako já 🙂 Můžeme snadno odstranit jen soubory, které aktuálně v repozitáře nechceme. Nebo si můžeme dát trochu více práce a odstranit i soubory, které jsme už dávno smazali nebo přejmenovali. K tomu ale potřebujeme zjistit, které to byly. Pro začátek si tedy vypíšeme všechny soubory, které kdy byly do repozitáře přidány. Výstup nasměrujeme do nějakého souboru, aby se nám s ním lépe pracovalo.

Nyní přišel čas otevřít si výstupní soubor v editoru a nechat v něm jen souboru, které chceme smazat. Musíme dát pozor, abychom si nesmazali soubory, které už sice v repozitáři nejsou, ale jejich přejmenované verze chceme. V případě odstraňování celých složek můžeme ponechat jen složku místo kompletního výpisu jejich souborů.

Jakmile budeme hotovi, použijeme připravený soubor v příkazu git filter-branch k promazání historie.

Nyní je načase aplikaci otestovat (v nejlepším případě spustit testy), zda jsme neodmazali něco důležitého. Nejspíše bude nutné kvůli odmazaným souborům trochu kódu upravit. Poté si můžeme přidat nový remote a udělat první push.

V této fázi jsou ještě stále staré revize zálohovány pod refs/original. Pokud je chcete z repozitáře úplně odstranit, musíme to udělat ručně.

Eventuelně můžeme místo toho udělat čerstvý clone našeho již vyfiltrovaného remotu.

Jak dostat ze SmartOS data o prostředcích VM

Na SmartOS nám spoustu věcí o VM prozradí příkaz vmadm. Např. základní limity zjistíme takto:

Je ale docela otrava to pokaždé zadávat. Můžeme si na to samozřejmě udělat bash alias, což jsem také měl. Další užitečný alias mám např. na výpis VM:

Na výpis prostředků už mi ale pouhý alias nestačil. Sepsal jsem tedy jednoduchý skript. Ten krom toho, co vrací vmadm, zobrazí i kolik VM žere místa na disku v přehledné formě. Navíc je to pěkná ukázka, jak se můžete podobné užitečné skripty sepsat sami.

Rozhodl jsem se nejen skript vmusage, ale celý repozitář s pár dalšími užitečnými věcmi zveřejnit. Stahovat nebo forkovat repozitář solaris-scripts můžete na BitBucketu.

Jak bezpečně distribuovat hesla v gitu

Pokud už jste někdy rozcházeli deployment aplikace pomocí gitu, asi jste narazili na problém, jak na produkční server bezpečně dostat hesla. Mít je v plaintextu v GITu moc bezpečné není 🙂 Přesto ale je způsob, jak je v gitu mít bezpečně – zašifrovat je. Jak to udělat a jak je při deploymentu do produkce rozšifrovat?

Pokud nemáte, nainstalujte si na produkčním server GPG. Na Unbuntu/Debian se to dělá takto:

Pro generování klíčů budeme potřebovat hodně entropy, doporučuji tedy nainstalovat i Haveged, viz. můj minulý článek.

Nyní se potřebujeme přepnout pod uživatele, pod kterým probíhá deployment. V mém případě je to uživatel web. Pod tímto uživatelem vygenerujeme základní keypair. Důležité: nezadávejte při generování klíčů žádné heslo, jen volbu potvrďte entrem.

Teď když máme vygenerovaný keypair, vyexportujeme veřejný klíč, nejlépe do souboru:

To by bylo pro produkční server zatím vše. Nyní si na našem vývojovém stroji vygenerujeme keypair stejně jako na produkčním serveru. Tentokrát ale doporučuji zadat heslo, na které se se vás GPG při šifrování a dalších operacích bude ptát. Poté importujeme veřejný klíč produkčního serveru.

Importovaný klíč podepíšeme, tím řekneme GPG, že důvěřujeme jeho původu:

Teď přijde ta hlavní část. Zašifrujeme veřejným klíčem produkčního serveru konfigurační soubor s hesly:

Zašifrovaný soubor .gpg pak můžeme bez problémů commitnout do gitu. Bez privátního klíče produkčního serveru jeho obsah nikdo nepřečte. Na produkčním serveru pak v deployment procesu nastavíme rozšifrování tohoto souboru pomocí privátního klíče, který už na serveru máme.

Jak zrychlit generování certifikátů v linuxu

Při generování certifikátů systém potřebuje tzv. entropy. Kolik jej systém aktuálně má můžete zjistit tímto příkazem:

Protože se entropy získává především z uživatelského vstupu, je s ním na serveru trochu problém. Tenhle problém řeší Haveged. Jak to celé pracuje je hezky vysvětleno v článku How to Setup Additional Entropy for Cloud Servers Using Haveged.