JFIFXX    $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222"4 ,PG"Z_4˷kjزZ,F+_z,© zh6٨icfu#ډb_N?wQ5-~I8TK<5oIv-k_U_~bMdӜUHh?]EwQk{_}qFW7HTՑYF?_'ϔ_Ջt=||I 6έ"D/[k9Y8ds|\Ҿp6Ҵ].6znopM[mei$[soᘨ˸ nɜG-ĨUycP3.DBli;hjx7Z^NhN3u{:jx힞#M&jL P@_ P&o89@Sz6t7#Oߋ s}YfTlmrZ)'Nk۞pw\Tȯ?8`Oi{wﭹW[r Q4F׊3m&L=h3z~#\l :F,j@ ʱwQT8"kJO6֚l}R>ډK]y&p}b;N1mr$|7>e@BTM*-iHgD) Em|ؘbҗaҾt4oG*oCNrPQ@z,|?W[0:n,jWiEW$~/hp\?{(0+Y8rΟ+>S-SVN;}s?. w9˟<Mq4Wv'{)01mBVW[8/< %wT^5b)iM pgN&ݝVO~qu9 !J27$O-! :%H ـyΠM=t{!S oK8txA& j0 vF Y|y ~6@c1vOpIg4lODL Rcj_uX63?nkWyf;^*B @~a`Eu+6L.ü>}y}_O6͐:YrGXkGl^w~㒶syIu! W XN7BVO!X2wvGRfT#t/?%8^WaTGcLMI(J1~8?aT ]ASE(*E} 2#I/׍qz^t̔bYz4xt){ OH+(EA&NXTo"XC')}Jzp ~5}^+6wcQ|LpdH}(.|kc4^"Z?ȕ a<L!039C EuCFEwç ;n?*oB8bʝ'#RqfM}7]s2tcS{\icTx;\7KPʇ Z O-~c>"?PEO8@8GQgaՎ󁶠䧘_%#r>1zaebqcPѵn#L =׀t L7`VA{C:ge@w1 Xp3c3ġpM"'-@n4fGB3DJ8[JoߐgK)ƛ$ 83+ 6ʻ SkI*KZlT _`?KQKdB`s}>`*>,*@JdoF*弝O}ks]yߘc1GV<=776qPTtXԀ!9*44Tހ3XΛex46YD  BdemDa\_l,G/֌7Y](xTt^%GE4}bTڹ;Y)BQu>J/J ⮶.XԄjݳ+Ed r5_D1 o Bx΢#<W8R6@gM. drD>(otU@x=~v2 ӣdoBd3eO6㣷ݜ66YQz`S{\P~z m5{J/L1xO\ZFu>ck#&:`$ai>2ΔloF[hlEܺΠk:)` $[69kOw\|8}ބ:񶐕IA1/=2[,!.}gN#ub ~݊}34qdELc$"[qU硬g^%B zrpJru%v\h1Yne`ǥ:gpQM~^Xi `S:V29.PV?Bk AEvw%_9CQwKekPؠ\;Io d{ ߞoc1eP\ `E=@KIRYK2NPlLɀ)&eB+ь( JTx_?EZ }@ 6U뙢طzdWIn` D噥[uV"G&Ú2g}&m?ċ"Om# {ON"SXNeysQ@FnVgdX~nj]J58up~.`r\O,ư0oS _Ml4kv\JSdxSW<AeIX$Iw:Sy›R9Q[,5;@]%u@ *rolbI  +%m:͇ZVủθau,RW33 dJeTYE.Mϧ-oj3+yy^cVO9NV\nd1 !͕_)av;թMlWR1)ElP;yوÏu 3k5Pr6<⒲l!˞*u־n!l:UNW %Chx8vL'X@*)̮ˍ D-M+JUkvK+x8cY?Ԡ~3mo|u@[XeYC\Kpx8oCC&N~3-H MXsu<`~"WL$8ξ3a)|:@m\^`@ҷ)5p+6p%i)P Mngc#0AruzRL+xSS?ʮ}()#tmˇ!0}}y$6Lt;$ʳ{^6{v6ķܰgVcnn ~zx«,2u?cE+ȘH؎%Za)X>uWTzNyosFQƤ$*&LLXL)1" LeOɟ9=:tZcŽY?ӭVwv~,Yrۗ|yGaFC.+ v1fήJ]STBn5sW}y$~z'c 8  ,! pVNSNNqy8z˱A4*'2n<s^ǧ˭PJޮɏUGLJ*#i}K%,)[z21z ?Nin1?TIR#m-1lA`fT5+ܐcq՝ʐ,3f2Uեmab#ŠdQy>\)SLYw#.ʑf ,"+w~N'cO3FN<)j&,- љ֊_zSTǦw>?nU仆Ve0$CdrP m׈eXmVu L.bֹ [Դaզ*\y8Է:Ez\0KqC b̘cөQ=0YsNS.3.Oo:#v7[#߫ 5܎LEr49nCOWlG^0k%;YߝZǓ:S#|}y,/kLd TA(AI$+I3;Y*Z}|ӧOdv..#:nf>>ȶITX 8y"dR|)0=n46ⲑ+ra ~]R̲c?6(q;5% |uj~z8R=XIV=|{vGj\gcqz؋%Mߍ1y#@f^^>N#x#۹6Y~?dfPO{P4Vu1E1J *|%JN`eWuzk M6q t[ gGvWIGu_ft5j"Y:Tɐ*; e54q$C2d} _SL#mYpO.C;cHi#֩%+) ӍƲVSYźg |tj38r|V1#;.SQA[S#`n+$$I P\[@s(EDzP])8G#0B[ىXIIq<9~[Z멜Z⊔IWU&A>P~#dp]9 "cP Md?٥Ifتuk/F9c*9Ǎ:ØFzn*@|Iށ9N3{'['ͬҲ4#}!V Fu,,mTIkv C7vB6kT91*l '~ƞFlU'M ][ΩũJ_{iIn$L jOdxkza۪#EClx˘oVɞljr)/,߬hL#^Lф,íMƁe̩NBLiLq}(q6IçJ$WE$:=#(KBzђ xlx?>Պ+>W,Ly!_DŌlQ![ SJ1ƐY}b,+Loxɓ)=yoh@꥟/Iѭ=Py9 ۍYӘe+pJnϱ?V\SO%(t =?MR[Șd/ nlB7j !;ӥ/[-A>dNsLj ,ɪv=1c.SQO3UƀܽE̻9GϷD7(}Ävӌ\y_0[w <΍>a_[0+LF.޺f>oNTq;y\bՃyjH<|q-eɏ_?_9+PHp$[uxK wMwNی'$Y2=qKBP~Yul:[<F12O5=d]Ysw:ϮEj,_QXz`H1,#II dwrP˂@ZJVy$\y{}^~[:NߌUOdؾe${p>G3cĖlʌ ת[`ϱ-WdgIig2 }s ؤ(%#sS@~3XnRG~\jc3vӍLM[JBTs3}jNʖW;7ç?=XF=-=qߚ#='c7ڑWI(O+=:uxqe2zi+kuGR0&eniT^J~\jyp'dtGsO39* b#Ɋ p[BwsT>d4ۧsnvnU_~,vƜJ1s QIz)(lv8MU=;56Gs#KMP=LvyGd}VwWBF'à ?MHUg2 !p7Qjڴ=ju JnA suMeƆҔ!)'8Ϣٔޝ(Vpצ֖d=ICJǠ{qkԭ߸i@Ku|p=..*+xz[Aqġ#s2aƊRR)*HRsi~a &fMP-KL@ZXy'x{}Zm+:)) IJ-iu ܒH'L(7yGӜq j 6ߌg1go,kرtY?W,pefOQS!K۟cҒA|սj>=⬒˧L[ ߿2JaB~Ru:Q] 0H~]7ƼI(}cq 'ήETq?fabӥvr )o-Q_'ᴎoK;Vo%~OK *bf:-ťIR`B5!RB@ï u ̯e\_U_ gES3QTaxU<~c?*#]MW,[8Oax]1bC|踤Plw5V%){t<d50iXSUm:Z┵i"1^B-PhJ&)O*DcWvM)}Pܗ-q\mmζZ-l@}aE6F@&Sg@ݚM ȹ 4#p\HdYDoH"\..RBHz_/5˘6KhJRPmƶim3,#ccoqa)*PtRmk7xDE\Y閣_X<~)c[[BP6YqS0%_;Àv~| VS؇ 'O0F0\U-d@7SJ*z3nyPOm~P3|Yʉr#CSN@ ƮRN)r"C:: #qbY. 6[2K2uǦHYRQMV G$Q+.>nNHq^ qmMVD+-#*U̒ p욳u:IBmPV@Or[b= 1UE_NmyKbNOU}the`|6֮P>\2PVIDiPO;9rmAHGWS]J*_G+kP2KaZH'KxWMZ%OYDRc+o?qGhmdSoh\D|:WUAQc yTq~^H/#pCZTI1ӏT4"ČZ}`w#*,ʹ 0i課Om*da^gJ݅{le9uF#Tֲ̲ٞC"qߍ ոޑo#XZTp@ o8(jdxw],f`~|,s^f1t|m򸄭/ctr5s79Q4H1꠲BB@l9@C+wpxu£Yc9?`@#omHs2)=2.ljg9$YS%*LRY7Z,*=䷘$armoϰUW.|rufIGwtZwo~5 YյhO+=8fF)W7L9lM̘·Y֘YLf큹pRF99.A "wz=E\Z'a 2Ǚ#;'}G*l^"q+2FQ hjkŦ${ޮ-T٭cf|3#~RJt$b(R(rdx >U b&9,>%E\ Άe$'q't*אެb-|dSBOO$R+H)܎K1m`;J2Y~9Og8=vqD`K[F)k[1m޼cn]skz$@)!I x՝"v9=ZA=`Ɠi :E)`7vI}dYI_ o:obo 3Q&D&2= Ά;>hy.*ⅥSӬ+q&j|UƧ}J0WW< ۋS)jQRjƯrN)Gű4Ѷ(S)Ǣ8iW52No˓ ۍ%5brOnL;n\G=^UdI8$&h'+(cȁ߫klS^cƗjԌEꭔgFȒ@}O*;evWVYJ\]X'5ղkFb 6Ro՜mi Ni>J?lPmU}>_Z&KKqrIDՉ~q3fL:Se>E-G{L6pe,8QIhaXaUA'ʂs+טIjP-y8ۈZ?J$WP Rs]|l(ԓsƊio(S0Y 8T97.WiLc~dxcE|2!XKƘਫ਼$((6~|d9u+qd^389Y6L.I?iIq9)O/뚅OXXVZF[یgQLK1RҖr@v#XlFНyS87kF!AsM^rkpjPDyS$Nqnxҍ!Uf!ehi2m`YI9r6 TFC}/y^Η5d'9A-J>{_l+`A['յϛ#w:݅%X}&PStQ"-\縵/$ƗhXb*yBS;Wջ_mcvt?2}1;qSdd~u:2k52R~z+|HE!)Ǟl7`0<,2*Hl-x^'_TVgZA'j ^2ΪN7t?w x1fIzC-ȖK^q;-WDvT78Z hK(P:Q- 8nZ܃e貾<1YT<,"6{/ ?͟|1:#gW>$dJdB=jf[%rE^il:BxSּ1հ,=*7 fcG#q eh?27,!7x6nLC4x},GeǝtC.vS F43zz\;QYC,6~;RYS/6|25vTimlv& nRh^ejRLGf? ۉҬܦƩ|Ȱ>3!viʯ>vオX3e_1zKȗ\qHS,EW[㺨uch⍸O}a>q6n6N6qN ! 1AQaq0@"2BRb#Pr3C`Scst$4D%Td ?Na3mCwxAmqmm$4n淿t'C"wzU=D\R+wp+YT&պ@ƃ3ޯ?AﶂaŘ@-Q=9Dռѻ@MVP܅G5fY6# ?0UQ,IX(6ڵ[DIMNލc&υj\XR|,4 jThAe^db#$]wOӪ1y%LYm뭛CUƃߜ}Cy1XνmF8jI]HۺиE@Ii;r8ӭVFՇ| &?3|xBMuSGe=Ӕ#BE5GY!z_eqр/W>|-Ci߇t1ޯќdR3ug=0 5[?#͏qcfH{ ?u=??ǯ}ZzhmΔBFTWPxs}G93 )gGR<>r h$'nchPBjJҧH -N1N?~}-q!=_2hcMlvY%UE@|vM2.Y[|y"EïKZF,ɯ?,q?vM 80jx";9vk+ ֧ ȺU?%vcVmA6Qg^MA}3nl QRNl8kkn'(M7m9وq%ޟ*h$Zk"$9: ?U8Sl,,|ɒxH(ѷGn/Q4PG%Ա8N! &7;eKM749R/%lc>x;>C:th?aKXbheᜋ^$Iհ hr7%F$EFdt5+(M6tÜUU|zW=aTsTgdqPQb'm1{|YXNb P~F^F:k6"j! Ir`1&-$Bevk:y#ywI0x=D4tUPZHڠ底taP6b>xaQ# WeFŮNjpJ* mQN*I-*ȩFg3 5Vʊɮa5FO@{NX?H]31Ri_uѕ 0 F~:60p͈SqX#a5>`o&+<2D: ڝ$nP*)N|yEjF5ټeihyZ >kbHavh-#!Po=@k̆IEN@}Ll?jO߭ʞQ|A07xwt!xfI2?Z<ץTcUj]陎Ltl }5ϓ$,Omˊ;@OjEj(ا,LXLOЦ90O .anA7j4 W_ٓzWjcBy՗+EM)dNg6y1_xp$Lv:9"zpʙ$^JԼ*ϭo=xLj6Ju82AH3$ٕ@=Vv]'qEz;I˼)=ɯx /W(Vp$ mu񶤑OqˎTr㠚xsrGCbypG1ߠw e8$⿄/M{*}W]˷.CK\ުx/$WPwr |i&}{X >$-l?-zglΆ(FhvS*b߲ڡn,|)mrH[a3ר[13o_U3TC$(=)0kgP u^=4 WYCҸ:vQרXàtkm,t*^,}D* "(I9R>``[~Q]#afi6l86:,ssN6j"A4IuQ6E,GnHzSHOuk5$I4ؤQ9@CwpBGv[]uOv0I4\yQѸ~>Z8Taqޣ;za/SI:ܫ_|>=Z8:SUIJ"IY8%b8H:QO6;7ISJҌAά3>cE+&jf$eC+z;V rʺmyeaQf&6ND.:NTvm<- uǝ\MvZYNNT-A>jr!SnO 13Ns%3D@`ܟ 1^c< aɽ̲Xë#w|ycW=9I*H8p^(4՗karOcWtO\ƍR8'KIQ?5>[}yUײ -h=% qThG2)"ו3]!kB*pFDlA,eEiHfPs5H:Փ~H0DتDIhF3c2E9H5zԑʚiX=:mxghd(v׊9iSOd@0ڽ:p5h-t&Xqӕ,ie|7A2O%PEhtjY1wЃ!  ࢽMy7\a@ţJ 4ȻF@o̒?4wx)]P~u57X 9^ܩU;Iꭆ 5 eK27({|Y׎ V\"Z1 Z}(Ǝ"1S_vE30>p; ΝD%xW?W?vo^Vidr[/&>~`9Why;R ;;ɮT?r$g1KACcKl:'3 cﳯ*"t8~l)m+U,z`(>yJ?h>]vЍG*{`;y]IT ;cNUfo¾h/$|NS1S"HVT4uhǜ]v;5͠x'C\SBplh}N ABx%ޭl/Twʽ]D=Kžr㻠l4SO?=k M: cCa#ha)ѐxcsgPiG{+xQI= zԫ+ 8"kñj=|c yCF/*9жh{ ?4o kmQNx;Y4膚aw?6>e]Qr:g,i"ԩA*M7qB?ӕFhV25r[7 Y }LR}*sg+xr2U=*'WSZDW]WǞ<叓{$9Ou4y90-1'*D`c^o?(9uݐ'PI& fJݮ:wSjfP1F:X H9dԯ˝[_54 }*;@ܨ ðynT?ןd#4rGͨH1|-#MrS3G3).᧏3vz֑r$G"`j 1tx0<ƆWh6y6,œGagAyb)hDß_mü gG;evݝnQ C-*oyaMI><]obD":GA-\%LT8c)+y76oQ#*{(F⽕y=rW\p۩cA^e6KʐcVf5$'->ՉN"F"UQ@fGb~#&M=8טJNu9D[̤so~ G9TtW^g5y$bY'سǴ=U-2 #MCt(i lj@Q 5̣i*OsxKf}\M{EV{υƇ);HIfeLȣr2>WIȂ6ik 5YOxȺ>Yf5'|H+98pjn.OyjY~iw'l;s2Y:'lgꥴ)o#'SaaKZ m}`169n"xI *+ }FP"l45'ZgE8?[X7(.Q-*ތL@̲v.5[=t\+CNܛ,gSQnH}*FG16&:t4ُ"Ạ$b |#rsaT ]ӽDP7ո0y)e$ٕvIh'QEAm*HRI=: 4牢) %_iNݧl] NtGHL ɱg<1V,J~ٹ"KQ 9HS9?@kr;we݁]I!{ @G["`J:n]{cAEVʆ#U96j#Ym\qe4hB7Cdv\MNgmAyQL4uLjj9#44tl^}LnR!t±]rh6ٍ>yҏNfU  Fm@8}/ujb9he:AyծwGpΧh5l}3p468)Udc;Us/֔YX1O2uqs`hwgr~{ RmhN؎*q 42*th>#E#HvOq}6e\,Wk#Xb>p}դ3T5†6[@Py*n|'f֧>lư΂̺SU'*qp_SM 'c6m ySʨ;MrƋmKxo,GmPAG:iw9}M(^V$ǒѽ9| aJSQarB;}ٻ֢2%Uc#gNaݕ'v[OY'3L3;,p]@S{lsX'cjwk'a.}}& dP*bK=ɍ!;3ngΊUߴmt'*{,=SzfD Ako~Gaoq_mi}#mPXhύmxǍ΂巿zfQc|kc?WY$_Lvl߶c`?ljݲˏ!V6UЂ(A4y)HpZ_x>eR$/`^'3qˏ-&Q=?CFVR DfV9{8gnh(P"6[D< E~0<@`G6Hгcc cK.5DdB`?XQ2ٿyqo&+1^ DW0ꊩG#QnL3c/x 11[yxპCWCcUĨ80me4.{muI=f0QRls9f9~fǨa"@8ȁQ#cicG$Gr/$W(WV"m7[mAmboD j۳ l^kh׽ # iXnveTka^Y4BNĕ0 !01@Q"2AaPq3BR?@4QT3,㺠W[=JKϞ2r^7vc:9 EߴwS#dIxu:Hp9E! V 2;73|F9Y*ʬFDu&y؟^EAA(ɩ^GV:ݜDy`Jr29ܾ㝉[E;FzxYGUeYC v-txIsםĘqEb+P\ :>iC';k|zرny]#ǿbQw(r|ӹs[D2v-%@;8<a[\o[ϧwI!*0krs)[J9^ʜp1) "/_>o<1AEy^C`x1'ܣnps`lfQ):lb>MejH^?kl3(z:1ŠK&?Q~{ٺhy/[V|6}KbXmn[-75q94dmc^h X5G-}دBޟ |rtMV+]c?-#ڛ^ǂ}LkrOu>-Dry D?:ޞUǜ7V?瓮"#rչģVR;n/_ ؉vݶe5db9/O009G5nWJpA*r9>1.[tsFnQ V 77R]ɫ8_0<՜IFu(v4Fk3E)N:yڮeP`1}$WSJSQNjٺ޵#lј(5=5lǏmoWv-1v,Wmn߀$x_DȬ0¤#QR[Vkzmw"9ZG7'[=Qj8R?zf\a=OU*oBA|G254 p.w7  &ξxGHp B%$gtЏ򤵍zHNuЯ-'40;_3 !01"@AQa2Pq#3BR?ʩcaen^8F<7;EA{EÖ1U/#d1an.1ě0ʾRh|RAo3m3 % 28Q yφHTo7lW>#i`qca m,B-j݋'mR1Ήt>Vps0IbIC.1Rea]H64B>o]($Bma!=?B KǾ+Ծ"nK*+[T#{EJSQs5:U\wĐf3܆&)IԆwE TlrTf6Q|Rh:[K zc֧GC%\_a84HcObiؖV7H )*ģK~Xhչ04?0 E<}3#u? |gS6ꊤ|I#Hڛ աwX97Ŀ%SLy6č|Fa 8b$sקhb9RAu7˨pČ_\*w묦F 4D~f|("mNKiS>$d7SlA/²SL|6N}S˯g]6; #. 403WebShell
403Webshell
Server IP : 51.79.149.130  /  Your IP : 216.73.216.210
Web Server : LiteSpeed
System : Linux linux.firevps.net 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
User : digit4868 ( 1088)
PHP Version : 8.2.30
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/local/CyberCP/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/local/CyberCP/OpenLiteSpeed_htaccess_Module_Documentation.md
# CyberPanel OpenLiteSpeed Module - Complete Usage Guide

**Version:** 2.2.0
**Last Updated:** December 28, 2025
**Status:** Production Ready

---

## Table of Contents

1. [Getting Started](#getting-started)
2. [Header Directives](#1-header-directives)
3. [Request Header Directives](#2-request-header-directives)
4. [Environment Variables](#3-environment-variables)
5. [Access Control](#4-access-control)
6. [Redirect Directives](#5-redirect-directives)
7. [Error Documents](#6-error-documents)
8. [FilesMatch Directives](#7-filesmatch-directives)
9. [Expires Directives](#8-expires-directives)
10. [PHP Directives](#9-php-directives)
11. [Brute Force Protection](#10-brute-force-protection)
12. [CyberPanel Integration](#cyberpanel-integration)
13. [Real-World Examples](#real-world-examples)
14. [Troubleshooting](#troubleshooting)

---

## Getting Started

### What is This Module?

The CyberPanel OpenLiteSpeed Module brings Apache .htaccess compatibility to OpenLiteSpeed servers. It allows you to use familiar Apache directives without switching web servers.

### Quick Start

1. **Module is pre-installed** on CyberPanel servers
2. **Create .htaccess** in your website's public_html directory
3. **Add directives** from this guide
4. **Test** using curl or browser

### Basic .htaccess Example

```apache
# Security headers
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"

# Enable brute force protection
BruteForceProtection On
```

---

## 1. Header Directives

### What Are HTTP Headers?

HTTP headers are metadata sent with web responses. They control browser behavior, caching, security, and more.

### Supported Operations

| Operation | Purpose | Syntax |
|-----------|---------|--------|
| **set** | Set header (replaces existing) | `Header set Name "Value"` |
| **unset** | Remove header | `Header unset Name` |
| **append** | Append to existing header | `Header append Name "Value"` |
| **merge** | Add if not present | `Header merge Name "Value"` |
| **add** | Always add (allows duplicates) | `Header add Name "Value"` |

### How to Use

#### Basic Security Headers

**What it does:** Protects against clickjacking, XSS, and MIME sniffing.

```apache
# Prevent site from being embedded in iframe (clickjacking protection)
Header set X-Frame-Options "SAMEORIGIN"

# Prevent MIME type sniffing
Header set X-Content-Type-Options "nosniff"

# Enable XSS filter in browsers
Header set X-XSS-Protection "1; mode=block"

# Control referrer information
Header set Referrer-Policy "strict-origin-when-cross-origin"

# Restrict browser features
Header set Permissions-Policy "geolocation=(), microphone=(), camera=()"
```

**Testing:**
```bash
curl -I https://yourdomain.com | grep -E "X-Frame|X-Content|X-XSS"
```

#### Cache Control Headers

**What it does:** Controls how browsers cache your content.

```apache
# Cache for 1 year (static assets)
Header set Cache-Control "max-age=31536000, public, immutable"

# No caching (dynamic content)
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "0"

# Cache for 1 hour
Header set Cache-Control "max-age=3600, public"
```

**Testing:**
```bash
curl -I https://yourdomain.com/style.css | grep Cache-Control
```

#### CORS Headers

**What it does:** Allows cross-origin requests (needed for APIs, fonts, n8n, etc.).

```apache
# Allow all origins
Header set Access-Control-Allow-Origin "*"

# Allow specific origin
Header set Access-Control-Allow-Origin "https://app.example.com"

# Allow specific methods
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"

# Allow specific headers
Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"

# Allow credentials
Header set Access-Control-Allow-Credentials "true"

# Preflight cache duration
Header set Access-Control-Max-Age "86400"
```

**Testing:**
```bash
curl -I -H "Origin: https://example.com" https://yourdomain.com/api
```

#### Remove Server Identification

**What it does:** Hides server information from attackers.

```apache
Header unset Server
Header unset X-Powered-By
Header unset X-LiteSpeed-Tag
```

**Testing:**
```bash
curl -I https://yourdomain.com | grep -E "Server|X-Powered"
# Should return nothing
```

### CyberPanel Integration

#### Via File Manager

1. Log into **CyberPanel**
2. Go to **File Manager**
3. Navigate to `/home/yourdomain.com/public_html`
4. Create or edit `.htaccess`
5. Add header directives
6. Save and test

#### Via SSH

```bash
# Navigate to website directory
cd /home/yourdomain.com/public_html

# Edit .htaccess
nano .htaccess

# Add your headers
Header set X-Frame-Options "SAMEORIGIN"

# Save (Ctrl+X, Y, Enter)

# Test
curl -I https://yourdomain.com | grep X-Frame
```

### Common Use Cases

#### WordPress Security Headers

```apache
# WordPress-specific security
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header unset X-Powered-By

# Disable XML-RPC header
Header unset X-Pingback
```

#### n8n CORS Configuration

```apache
# Allow n8n webhooks
Header set Access-Control-Allow-Origin "https://your-n8n-instance.com"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
```

#### API Response Headers

```apache
# JSON API headers
Header set Content-Type "application/json; charset=utf-8"
Header set X-Content-Type-Options "nosniff"
Header set Access-Control-Allow-Origin "*"
Header set Cache-Control "no-cache, no-store, must-revalidate"
```

---

## 2. Request Header Directives

### What Are Request Headers?

Request headers are sent FROM the client TO the server. This feature lets you modify or add headers before they reach your PHP application.

### How It Works

Since OpenLiteSpeed's LSIAPI doesn't support direct request header modification, these are implemented as **environment variables** accessible in PHP via `$_SERVER`.

### Supported Operations

| Operation | Syntax | Result |
|-----------|--------|--------|
| **set** | `RequestHeader set Name "Value"` | `$_SERVER['HTTP_NAME']` |
| **unset** | `RequestHeader unset Name` | Header removed |

### How to Use

#### SSL/HTTPS Detection (Behind Proxy)

**What it does:** Tells your application the request came via HTTPS (when behind Cloudflare, nginx proxy, etc.).

```apache
# Set HTTPS protocol headers
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-SSL "on"
RequestHeader set X-Real-IP "%{REMOTE_ADDR}e"
```

**PHP Usage:**
```php
<?php
// Detect HTTPS
$proto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? 'http';
$isHttps = ($proto === 'https');

// Get real IP
$realIp = $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'];

// Force HTTPS redirect
if (!$isHttps && $_SERVER['REQUEST_METHOD'] !== 'OPTIONS') {
    header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    exit;
}
?>
```

#### Application Environment Identification

**What it does:** Tags requests with environment information.

```apache
# Identify environment
RequestHeader set X-Environment "production"
RequestHeader set X-Server-Location "us-east-1"
RequestHeader set X-Request-Start "%{REQUEST_TIME}e"
```

**PHP Usage:**
```php
<?php
$env = $_SERVER['HTTP_X_ENVIRONMENT'] ?? 'development';
$location = $_SERVER['HTTP_X_SERVER_LOCATION'] ?? 'unknown';

if ($env === 'production') {
    ini_set('display_errors', 0);
    error_reporting(E_ALL & ~E_DEPRECATED);
}
?>
```

#### Custom Backend Headers

**What it does:** Passes custom information to your application.

```apache
# Custom application headers
RequestHeader set X-API-Version "v2"
RequestHeader set X-Feature-Flags "new-ui,beta-features"
RequestHeader set X-Client-Type "web"
```

**PHP Usage:**
```php
<?php
$apiVersion = $_SERVER['HTTP_X_API_VERSION'] ?? 'v1';
$features = explode(',', $_SERVER['HTTP_X_FEATURE_FLAGS'] ?? '');
$clientType = $_SERVER['HTTP_X_CLIENT_TYPE'] ?? 'unknown';

if (in_array('beta-features', $features)) {
    // Enable beta features
}
?>
```

### CyberPanel Integration

#### For WordPress Behind Cloudflare

```apache
# In /home/yourdomain.com/public_html/.htaccess
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-SSL "on"

# WordPress will now correctly detect HTTPS
```

**Verify in WordPress:**
```php
// Add to wp-config.php if needed
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}
```

### Common Use Cases

#### Cloudflare + WordPress

```apache
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-SSL "on"
RequestHeader set X-Real-IP "%{REMOTE_ADDR}e"
```

#### Laravel Behind Load Balancer

```apache
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e"
```

---

## 3. Environment Variables

### What Are Environment Variables?

Environment variables are key-value pairs accessible in your PHP application. They're useful for configuration, feature flags, and conditional logic.

### Supported Directives

| Directive | Purpose | Syntax |
|-----------|---------|--------|
| **SetEnv** | Set static variable | `SetEnv NAME value` |
| **SetEnvIf** | Conditional set (case-sensitive) | `SetEnvIf attribute regex VAR=value` |
| **SetEnvIfNoCase** | Conditional set (case-insensitive) | `SetEnvIfNoCase attribute regex VAR=value` |
| **BrowserMatch** | Detect browser | `BrowserMatch regex VAR=value` |

### How to Use

#### Static Configuration Variables

**What it does:** Sets application configuration accessible in PHP.

```apache
# Application settings
SetEnv APPLICATION_ENV production
SetEnv DB_HOST localhost
SetEnv DB_NAME myapp_db
SetEnv API_ENDPOINT https://api.example.com
SetEnv FEATURE_FLAG_NEW_UI enabled
SetEnv DEBUG_MODE off
```

**PHP Usage:**
```php
<?php
$env = $_SERVER['APPLICATION_ENV'] ?? 'development';
$dbHost = $_SERVER['DB_HOST'] ?? 'localhost';
$apiEndpoint = $_SERVER['API_ENDPOINT'] ?? '';
$newUiEnabled = ($_SERVER['FEATURE_FLAG_NEW_UI'] ?? 'off') === 'enabled';

if ($newUiEnabled) {
    require 'templates/new-ui.php';
} else {
    require 'templates/old-ui.php';
}
?>
```

#### Conditional Variables (SetEnvIf)

**What it does:** Sets variables based on request properties.

##### Supported Conditions

- `Request_URI` - URL path
- `Request_Method` - HTTP method (GET, POST, etc.)
- `User-Agent` - Browser/client identifier
- `Host` - Domain name
- `Referer` - Referrer URL
- `Query_String` - URL parameters
- `Remote_Addr` - Client IP address

**Examples:**

```apache
# Detect API requests
SetEnvIf Request_URI "^/api/" IS_API_REQUEST=1

# Detect POST requests
SetEnvIf Request_Method "POST" IS_POST_REQUEST=1

# Detect specific domain
SetEnvIf Host "^beta\." IS_BETA_SITE=1

# Detect search queries
SetEnvIf Query_String "search=" HAS_SEARCH=1

# Detect local development
SetEnvIf Remote_Addr "^127\.0\.0\.1$" IS_LOCAL=1
```

**PHP Usage:**
```php
<?php
if (!empty($_SERVER['IS_API_REQUEST'])) {
    header('Content-Type: application/json');
    $output = json_encode($data);
} else {
    header('Content-Type: text/html');
    $output = render_html($data);
}

if (!empty($_SERVER['IS_BETA_SITE'])) {
    // Enable experimental features
    define('BETA_FEATURES', true);
}
?>
```

#### Browser Detection

**What it does:** Identifies the user's browser for compatibility handling.

```apache
# Case-insensitive browser detection
SetEnvIfNoCase User-Agent "mobile|android|iphone|ipad" IS_MOBILE=1
SetEnvIfNoCase User-Agent "bot|crawler|spider|scraper" IS_BOT=1
SetEnvIfNoCase User-Agent "MSIE|Trident" IS_IE=1

# Specific browser matching
BrowserMatch "Chrome" IS_CHROME=1
BrowserMatch "Firefox" IS_FIREFOX=1
BrowserMatch "Safari" IS_SAFARI=1
BrowserMatch "Edge" IS_EDGE=1
```

**PHP Usage:**
```php
<?php
if (!empty($_SERVER['IS_MOBILE'])) {
    require 'mobile-layout.php';
} else {
    require 'desktop-layout.php';
}

if (!empty($_SERVER['IS_BOT'])) {
    // Serve cached version to bots
    serve_cached_page();
    exit;
}

if (!empty($_SERVER['IS_IE'])) {
    echo '<div class="browser-warning">Please use a modern browser</div>';
}
?>
```

### CyberPanel Integration

#### Environment-Specific Configuration

```apache
# In /home/yourdomain.com/public_html/.htaccess

# Production settings
SetEnv APPLICATION_ENV production
SetEnv DEBUG_MODE off
SetEnv CACHE_ENABLED on

# Database connection
SetEnv DB_HOST localhost
SetEnv DB_NAME wp_database

# Feature flags
SetEnv ENABLE_CDN on
SetEnv ENABLE_CACHE on
```

**WordPress Usage (wp-config.php):**
```php
<?php
// Use environment variables
define('WP_ENV', $_SERVER['APPLICATION_ENV'] ?? 'production');
define('WP_DEBUG', ($_SERVER['DEBUG_MODE'] ?? 'off') === 'on');

if (WP_DEBUG) {
    define('WP_DEBUG_LOG', true);
    define('WP_DEBUG_DISPLAY', true);
}
?>
```

### Common Use Cases

#### Mobile Detection + Redirect

```apache
# Detect mobile users
SetEnvIfNoCase User-Agent "mobile|android|iphone" IS_MOBILE=1

# Redirect mobile to subdomain (using PHP)
```

**PHP redirect:**
```php
<?php
if (!empty($_SERVER['IS_MOBILE']) && strpos($_SERVER['HTTP_HOST'], 'm.') !== 0) {
    header('Location: https://m.example.com' . $_SERVER['REQUEST_URI']);
    exit;
}
?>
```

#### API Rate Limiting Preparation

```apache
# Tag API requests
SetEnvIf Request_URI "^/api/" IS_API=1
SetEnvIf Request_Method "POST" IS_POST=1
```

**PHP rate limiting:**
```php
<?php
if (!empty($_SERVER['IS_API'])) {
    // Apply API rate limiting
    check_api_rate_limit($_SERVER['REMOTE_ADDR']);
}
?>
```

---

## 4. Access Control

### What is Access Control?

Access control restricts who can access your website based on IP addresses. Perfect for staging sites, admin panels, or development environments.

### Directives

| Directive | Syntax | Description |
|-----------|--------|-------------|
| **Order** | `Order deny,allow` or `Order allow,deny` | Set evaluation order |
| **Allow** | `Allow from IP/CIDR` | Allow specific IP |
| **Deny** | `Deny from IP/CIDR` | Deny specific IP |

### Supported IP Formats

- **Single IP:** `192.168.1.100`
- **CIDR Range:** `192.168.1.0/24` (entire subnet)
- **Large Ranges:** `10.0.0.0/8` (entire class)
- **IPv6:** `2001:db8::/32`
- **Wildcard:** `all` (everyone)

### How Order Works

#### Order deny,allow

1. Check **Deny** list first
2. Then check **Allow** list
3. **Allow overrides Deny**
4. Default: **DENY** if not in either list

```apache
Order deny,allow
Deny from all
Allow from 192.168.1.100
# Result: Only 192.168.1.100 can access
```

#### Order allow,deny

1. Check **Allow** list first
2. Then check **Deny** list
3. **Deny overrides Allow**
4. Default: **ALLOW** if not in either list

```apache
Order allow,deny
Allow from all
Deny from 192.168.1.100
# Result: Everyone except 192.168.1.100 can access
```

### How to Use

#### Block All Except Specific IPs (Recommended for Staging)

```apache
# Only allow office IP and VPN
Order deny,allow
Deny from all
Allow from 203.0.113.50      # Office IP
Allow from 192.168.1.0/24    # Office LAN
Allow from 10.8.0.0/24       # VPN range
```

**Use case:** Development/staging sites, admin areas

**Testing:**
```bash
# From allowed IP
curl https://staging.example.com
# Should work

# From other IP
curl https://staging.example.com
# Should get 403 Forbidden
```

#### Allow All Except Specific IPs

```apache
# Block known attackers
Order allow,deny
Allow from all
Deny from 198.51.100.50      # Banned IP
Deny from 203.0.113.0/24     # Banned subnet
```

**Use case:** Blocking spam IPs, attack sources

#### Protect Admin Directory

```apache
# In /home/yourdomain.com/public_html/admin/.htaccess
Order deny,allow
Deny from all
Allow from 192.168.1.0/24    # Office network
Allow from 203.0.113.100     # Your home IP
```

**Use case:** WordPress wp-admin protection

### CyberPanel Integration

#### Protect Staging Site

1. Create subdomain `staging.yourdomain.com` in CyberPanel
2. Navigate to `/home/staging.yourdomain.com/public_html`
3. Create `.htaccess`:

```apache
# Staging site - Office only
Order deny,allow
Deny from all
Allow from YOUR.OFFICE.IP.HERE
Allow from YOUR.HOME.IP.HERE
```

4. Test:
```bash
# Get your IP
curl ifconfig.me

# Test access
curl -I https://staging.yourdomain.com
# Should see 403 if not allowed
```

#### Protect WordPress Admin

```apache
# In /home/yourdomain.com/public_html/wp-admin/.htaccess
Order deny,allow
Deny from all
Allow from 203.0.113.50   # Your IP
```

**Important:** This creates TWO layers of protection:
1. IP restriction (from .htaccess)
2. Login authentication (from WordPress)

#### Protect CyberPanel Access

```apache
# In /usr/local/CyberCP/public/.htaccess (if web accessible)
Order deny,allow
Deny from all
Allow from 127.0.0.1         # localhost
Allow from 192.168.1.0/24    # Your network
```

### Common Use Cases

#### Development Environment

```apache
# Dev site - developers only
Order deny,allow
Deny from all
Allow from 192.168.1.0/24    # Office LAN
Allow from 10.8.0.0/24       # VPN
Allow from 203.0.113.50      # Lead developer home
```

#### Geographic Restriction

```apache
# Block specific countries (you need to maintain IP list)
Order allow,deny
Allow from all
Deny from 198.51.100.0/24    # Country X subnet
Deny from 203.0.113.0/24     # Country Y subnet
```

#### API Endpoint Protection

```apache
# In /home/yourdomain.com/public_html/api/.htaccess
Order deny,allow
Deny from all
Allow from 10.0.0.0/8        # Internal network
Allow from 172.16.0.0/12     # Private network
```

### Troubleshooting

**Problem:** Getting 403 even from allowed IP

**Solution:**
1. Check your actual IP: `curl ifconfig.me`
2. Verify CIDR: `192.168.1.0/24` covers `192.168.1.1` to `192.168.1.254`
3. Check logs: `tail -f /usr/local/lsws/logs/error.log`

**Problem:** Access control not working

**Solution:**
1. Verify module loaded: `ls -la /usr/local/lsws/modules/cyberpanel_ols.so`
2. Check .htaccess permissions: `chmod 644 .htaccess`
3. Restart OpenLiteSpeed: `/usr/local/lsws/bin/lswsctrl restart`

---

## 5. Redirect Directives

### What Are Redirects?

Redirects tell browsers to go to a different URL. Essential for SEO, site migrations, and URL structure changes.

### Directives

| Directive | Syntax | Use Case |
|-----------|--------|----------|
| **Redirect** | `Redirect [code] /old /new` | Simple path redirects |
| **RedirectMatch** | `RedirectMatch [code] regex target` | Pattern-based redirects |

### Status Codes

| Code | Name | When to Use |
|------|------|-------------|
| **301** | Permanent | SEO-friendly, URL has moved forever |
| **302** | Temporary | URL temporarily moved, may change back |
| **303** | See Other | Redirect after POST (form submission) |
| **410** | Gone | Resource permanently deleted |

### How to Use

#### Simple Redirects

**What it does:** Redirects one path to another.

```apache
# Old page to new page
Redirect 301 /old-page.html /new-page.html

# Old directory to new directory
Redirect 301 /old-blog /blog

# Use keywords instead of codes
Redirect permanent /old-url /new-url
Redirect temp /maintenance /coming-soon
```

**Testing:**
```bash
curl -I https://yourdomain.com/old-page.html
# Should show: HTTP/1.1 301 Moved Permanently
# Location: https://yourdomain.com/new-page.html
```

#### Force HTTPS

**What it does:** Redirects HTTP to HTTPS.

```apache
# Redirect HTTP to HTTPS
Redirect 301 / https://yourdomain.com/
```

**Better Alternative (checks if already HTTPS):**
```apache
SetEnvIf Request_URI ".*" IS_HTTP=1
# Use with PHP to avoid redirect loop
```

**PHP solution:**
```php
<?php
if ($_SERVER['REQUEST_SCHEME'] !== 'https') {
    header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
    exit;
}
?>
```

#### Force WWW or Non-WWW

**What it does:** Standardizes domain format for SEO.

```apache
# Force www
Redirect 301 / https://www.yourdomain.com/

# Force non-www (use RedirectMatch)
RedirectMatch 301 ^(.*)$ https://yourdomain.com$1
```

#### Pattern-Based Redirects (RedirectMatch)

**What it does:** Uses regex to match and redirect URLs.

```apache
# Blog restructuring
RedirectMatch 301 ^/blog/(.*)$ /news/$1
# /blog/post-1 → /news/post-1

# Product ID migration
RedirectMatch 301 ^/product-([0-9]+)$ /item/$1
# /product-123 → /item/123

# Year/month/title to title
RedirectMatch 301 ^/blog/([0-9]{4})/([0-9]{2})/(.*)$ /articles/$3
# /blog/2024/12/my-post → /articles/my-post

# Category reorganization
RedirectMatch 301 ^/category/(.*)$ /topics/$1
```

**Testing:**
```bash
curl -I https://yourdomain.com/blog/my-post
# Should redirect to /news/my-post
```

### CyberPanel Integration

#### Site Migration (Old Domain to New)

```apache
# In old site's .htaccess
Redirect 301 / https://new-domain.com/
```

**Steps:**
1. Keep old domain active in CyberPanel
2. Add redirect to `/home/old-domain.com/public_html/.htaccess`
3. Monitor traffic migration
4. After 6 months, can delete old domain

#### WordPress Permalink Change

**Scenario:** Changed permalinks from `/?p=123` to `/blog/post-title`

```apache
# WordPress handles this automatically, but for custom:
RedirectMatch 301 ^/\?p=([0-9]+)$ /blog/post-$1
```

#### E-commerce URL Update

```apache
# Old: /products/view/123
# New: /shop/product-123

RedirectMatch 301 ^/products/view/([0-9]+)$ /shop/product-$1
```

### Common Use Cases

#### Complete Site Redesign

```apache
# Redirect old structure to new
RedirectMatch 301 ^/about-us$ /about
RedirectMatch 301 ^/contact-us$ /contact
RedirectMatch 301 ^/services/(.*)$ /solutions/$1
RedirectMatch 301 ^/blog/(.*)$ /news/$1
```

#### Affiliate Link Management

```apache
# Short URLs for affiliate links
Redirect 302 /go/amazon https://amazon.com/your-affiliate-link
Redirect 302 /go/product https://example.com/long-url-here
```

#### Seasonal Campaigns

```apache
# Temporary campaign redirect
Redirect 302 /sale /christmas-sale-2025
Redirect 302 /promo /black-friday
```

#### Remove .html Extensions (SEO)

```apache
# Old: /page.html
# New: /page

RedirectMatch 301 ^/(.*)/index\.html$ /$1/
RedirectMatch 301 ^/(.*)[^/]\.html$ /$1
```

### Troubleshooting

**Problem:** Redirect loop

**Solution:** Check for conflicting rules:
```apache
# BAD - Creates loop
Redirect 301 / https://example.com/
Redirect 301 / https://www.example.com/

# GOOD - Use one or the other
Redirect 301 / https://www.example.com/
```

**Problem:** Redirect not working

**Solution:**
1. Clear browser cache (redirects are cached!)
2. Test with curl: `curl -I https://yoursite.com/old-page`
3. Check .htaccess syntax
4. Restart OpenLiteSpeed

---

## 6. Error Documents

### What Are Error Documents?

Custom error pages shown when errors occur (404 Not Found, 500 Internal Server Error, etc.).

### Supported Error Codes

| Code | Error | When It Happens |
|------|-------|-----------------|
| **400** | Bad Request | Malformed request |
| **401** | Unauthorized | Authentication required |
| **403** | Forbidden | Access denied |
| **404** | Not Found | Page doesn't exist |
| **500** | Internal Server Error | Server-side error |
| **502** | Bad Gateway | Proxy/backend error |
| **503** | Service Unavailable | Server overloaded/maintenance |

### Syntax

```apache
ErrorDocument <code> <document>
```

### How to Use

#### HTML Error Pages

**What it does:** Shows custom-designed error pages.

```apache
# Custom error pages
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html
ErrorDocument 403 /errors/403.html
ErrorDocument 503 /errors/maintenance.html
```

**Create error pages:**

```bash
mkdir -p /home/yourdomain.com/public_html/errors
```

**404.html example:**
```html
<!DOCTYPE html>
<html>
<head>
    <title>Page Not Found</title>
    <style>
        body { font-family: Arial; text-align: center; padding: 50px; }
        h1 { color: #e74c3c; }
    </style>
</head>
<body>
    <h1>404 - Page Not Found</h1>
    <p>The page you're looking for doesn't exist.</p>
    <a href="/">Go to Homepage</a>
</body>
</html>
```

**Testing:**
```bash
curl https://yourdomain.com/nonexistent-page
# Should show your custom 404 page
```

#### Inline Messages

**What it does:** Shows simple text message.

```apache
ErrorDocument 403 "Access Denied - Contact Administrator"
ErrorDocument 404 "Page Not Found - Please check the URL"
```

#### WordPress-Friendly Error Pages

**What it does:** Routes errors through WordPress.

```apache
# Let WordPress handle 404s
ErrorDocument 404 /index.php?error=404
```

**WordPress theme (404.php):**
```php
<?php
// Custom 404 page design
get_header();
?>
<h1>Page Not Found</h1>
<p>Sorry, this page doesn't exist.</p>
<?php
get_footer();
?>
```

### CyberPanel Integration

#### Setup Custom Error Pages

**Step 1:** Create error directory
```bash
cd /home/yourdomain.com/public_html
mkdir errors
cd errors
```

**Step 2:** Create error page files
```bash
nano 404.html
# Add custom HTML
# Save (Ctrl+X, Y, Enter)

nano 500.html
# Add custom HTML
# Save
```

**Step 3:** Configure .htaccess
```apache
# In /home/yourdomain.com/public_html/.htaccess
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html
ErrorDocument 403 /errors/403.html
```

**Step 4:** Test
```bash
curl https://yourdomain.com/test-404
```

#### Maintenance Page

```apache
# During maintenance
ErrorDocument 503 /maintenance.html
```

**maintenance.html:**
```html
<!DOCTYPE html>
<html>
<head>
    <title>Maintenance</title>
    <meta http-equiv="refresh" content="30">
    <style>
        body { font-family: Arial; text-align: center; padding: 100px; }
        h1 { color: #3498db; }
    </style>
</head>
<body>
    <h1>We'll be right back!</h1>
    <p>Our site is undergoing maintenance.</p>
    <p>Expected completion: 2 hours</p>
</body>
</html>
```

**Trigger maintenance mode:**
```bash
# Temporarily disable PHP
mv index.php index.php.bak
# Site will show 503
```

### Common Use Cases

#### Professional 404 Page with Search

**404.html:**
```html
<!DOCTYPE html>
<html>
<head>
    <title>Page Not Found</title>
</head>
<body>
    <h1>404 - Page Not Found</h1>
    <p>Try searching:</p>
    <form action="/search" method="get">
        <input type="text" name="q" placeholder="Search...">
        <button>Search</button>
    </form>
    <p><a href="/">Return to Homepage</a></p>
</body>
</html>
```

#### Branded Error Pages

```apache
ErrorDocument 400 /errors/400.html
ErrorDocument 401 /errors/401.html
ErrorDocument 403 /errors/403.html
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html
ErrorDocument 502 /errors/502.html
ErrorDocument 503 /errors/503.html
```

Each page styled with your brand colors, logo, navigation.

---

## 7. FilesMatch Directives

### What is FilesMatch?

FilesMatch applies directives only to files matching a regex pattern. Perfect for caching strategies, security headers per file type.

### Syntax

```apache
<FilesMatch "regex">
    # Directives here apply only to matching files
    Header set Name "Value"
</FilesMatch>
```

### Common File Patterns

| Pattern | Matches |
|---------|---------|
| `\.(jpg\|png\|gif)$` | Images |
| `\.(css\|js)$` | Stylesheets and JavaScript |
| `\.(woff2?\|ttf\|eot)$` | Fonts |
| `\.(pdf\|doc\|docx)$` | Documents |
| `\.(html\|php)$` | Dynamic pages |
| `\.json$` | JSON files |

### How to Use

#### Cache Static Assets (Performance Boost)

**What it does:** Tells browsers to cache images/fonts for a long time.

```apache
# Images - Cache for 1 year
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
    Header unset ETag
    Header unset Last-Modified
</FilesMatch>

# Fonts - Cache for 1 year
<FilesMatch "\.(woff2?|ttf|eot|otf)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
    Header set Access-Control-Allow-Origin "*"
</FilesMatch>

# CSS/JS - Cache for 1 week (you update these more often)
<FilesMatch "\.(css|js)$">
    Header set Cache-Control "max-age=604800, public"
</FilesMatch>
```

**Testing:**
```bash
curl -I https://yourdomain.com/logo.png | grep Cache-Control
# Should show: Cache-Control: max-age=31536000, public, immutable
```

**Performance Impact:**
- First visit: Downloads all files
- Return visits: Loads from browser cache (instant!)
- Page load time: -50% to -80%

#### Security Headers for HTML/PHP

**What it does:** Applies security headers only to pages (not images).

```apache
<FilesMatch "\.(html|htm|php)$">
    Header set X-Frame-Options "SAMEORIGIN"
    Header set X-Content-Type-Options "nosniff"
    Header set X-XSS-Protection "1; mode=block"
    Header set Referrer-Policy "strict-origin-when-cross-origin"
</FilesMatch>
```

#### Prevent Caching of Dynamic Content

**What it does:** Ensures dynamic pages are never cached.

```apache
<FilesMatch "\.(html|php|json|xml)$">
    Header set Cache-Control "no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "0"
</FilesMatch>
```

#### CORS for Fonts (Fix Font Loading)

**What it does:** Allows fonts to load from CDN or different domain.

```apache
<FilesMatch "\.(woff2?|ttf|eot|otf)$">
    Header set Access-Control-Allow-Origin "*"
</FilesMatch>
```

**Use case:** Fixes "Font from origin has been blocked by CORS policy" errors.

#### Download Headers for Files

**What it does:** Forces download instead of displaying in browser.

```apache
<FilesMatch "\.(pdf|zip|tar|gz|doc|docx|xls|xlsx)$">
    Header set Content-Disposition "attachment"
    Header set X-Content-Type-Options "nosniff"
</FilesMatch>
```

### CyberPanel Integration

#### WordPress Performance Optimization

```apache
# In /home/yourdomain.com/public_html/.htaccess

# Cache WordPress static assets
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>

# Cache CSS/JS (with version strings in WordPress)
<FilesMatch "\.(css|js)$">
    Header set Cache-Control "max-age=2592000, public"
</FilesMatch>

# Don't cache WordPress admin
<FilesMatch "(wp-login|wp-admin|wp-cron)\.php$">
    Header set Cache-Control "no-cache, no-store, must-revalidate"
</FilesMatch>
```

**Result:** PageSpeed score +20-30 points

#### WooCommerce Security

```apache
# Protect sensitive files
<FilesMatch "(\.log|\.sql|\.md|readme\.txt|license\.txt)$">
    Order deny,allow
    Deny from all
</FilesMatch>

# JSON API security
<FilesMatch "\.json$">
    Header set X-Content-Type-Options "nosniff"
    Header set Content-Type "application/json; charset=utf-8"
</FilesMatch>
```

### Common Use Cases

#### Complete Caching Strategy

```apache
# Aggressive caching for static assets (1 year)
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico|woff2?|ttf|eot|otf)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
    Header unset ETag
</FilesMatch>

# Moderate caching for CSS/JS (1 month)
<FilesMatch "\.(css|js)$">
    Header set Cache-Control "max-age=2592000, public"
</FilesMatch>

# Short caching for HTML (1 hour)
<FilesMatch "\.html$">
    Header set Cache-Control "max-age=3600, public"
</FilesMatch>

# No caching for dynamic content
<FilesMatch "\.(php|json)$">
    Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>
```

#### Media Library Protection

```apache
# Prevent hotlinking (bandwidth theft)
<FilesMatch "\.(jpg|jpeg|png|gif)$">
    SetEnvIf Referer "^https://yourdomain\.com" local_ref
    SetEnvIf Referer "^$" local_ref
    Order deny,allow
    Deny from all
    Allow from env=local_ref
</FilesMatch>
```

---

## 8. Expires Directives

### What is mod_expires?

Alternative syntax for setting cache expiration. More concise than Cache-Control headers.

### Directives

```apache
ExpiresActive On
ExpiresByType mime-type base+seconds
```

### Time Bases

- **A** = Access time (when user requests file)
- **M** = Modification time (when file was last modified)

### Common Durations

| Duration | Seconds | Example |
|----------|---------|---------|
| 1 minute | 60 | `A60` |
| 1 hour | 3600 | `A3600` |
| 1 day | 86400 | `A86400` |
| 1 week | 604800 | `A604800` |
| 1 month | 2592000 | `A2592000` |
| 1 year | 31557600 | `A31557600` |

### How to Use

#### Complete Expiration Strategy

```apache
# Enable module
ExpiresActive On

# Images - 1 year
ExpiresByType image/jpeg A31557600
ExpiresByType image/png A31557600
ExpiresByType image/gif A31557600
ExpiresByType image/webp A31557600
ExpiresByType image/svg+xml A31557600
ExpiresByType image/x-icon A31557600

# CSS and JavaScript - 1 month
ExpiresByType text/css A2592000
ExpiresByType application/javascript A2592000
ExpiresByType application/x-javascript A2592000
ExpiresByType text/javascript A2592000

# Fonts - 1 year
ExpiresByType font/ttf A31557600
ExpiresByType font/woff A31557600
ExpiresByType font/woff2 A31557600
ExpiresByType application/font-woff A31557600
ExpiresByType application/font-woff2 A31557600

# HTML - no cache
ExpiresByType text/html A0

# PDF - 1 month
ExpiresByType application/pdf A2592000

# JSON/XML - 1 hour
ExpiresByType application/json A3600
ExpiresByType application/xml A3600
```

**Testing:**
```bash
curl -I https://yourdomain.com/image.jpg | grep -E "Expires|Cache-Control"
```

### CyberPanel Integration

#### WordPress Caching

```apache
# In /home/yourdomain.com/public_html/.htaccess

ExpiresActive On

# WordPress uploads (images in wp-content/uploads)
ExpiresByType image/jpeg A31557600
ExpiresByType image/png A31557600
ExpiresByType image/gif A31557600

# WordPress theme assets
ExpiresByType text/css A2592000
ExpiresByType application/javascript A2592000

# WordPress HTML (dynamic, don't cache)
ExpiresByType text/html A0
```

### FilesMatch vs Expires

**Use FilesMatch when:**
- Need multiple headers per file type
- Need complex regex patterns
- Want more control

**Use Expires when:**
- Only setting cache expiration
- Want concise syntax
- Working with MIME types

**Both together:**
```apache
ExpiresActive On

<FilesMatch "\.(jpg|png|gif)$">
    ExpiresByType image/jpeg A31557600
    Header set Cache-Control "public, immutable"
    Header unset ETag
</FilesMatch>
```

---

## 9. PHP Directives

### What Are PHP Directives?

Change PHP configuration per-directory without editing php.ini.

### Directives

| Directive | Syntax | Purpose |
|-----------|--------|---------|
| **php_value** | `php_value name value` | Set numeric/string values |
| **php_flag** | `php_flag name on/off` | Set boolean (on/off) values |

### Requirements

- Must use **LSPHP** (not PHP-FPM)
- Must be **PHP_INI_ALL** or **PHP_INI_PERDIR** directive
- CyberPanel uses LSPHP by default ✅

### How to Use

#### Memory and Execution Limits

**What it does:** Allows scripts to use more memory/time.

```apache
# Increase memory (default 128M)
php_value memory_limit 256M

# Increase execution time (default 30s)
php_value max_execution_time 300

# Increase input time (default 60s)
php_value max_input_time 300

# Increase max input variables (default 1000)
php_value max_input_vars 5000
```

**Use case:** WordPress imports, WooCommerce bulk operations, data processing.

**Testing:**
```php
<?php
echo 'Memory Limit: ' . ini_get('memory_limit') . "\n";
echo 'Max Execution Time: ' . ini_get('max_execution_time') . "\n";
?>
```

#### Upload Limits

**What it does:** Allows larger file uploads.

```apache
# Allow 100MB uploads (default 2M)
php_value upload_max_filesize 100M
php_value post_max_size 100M

# Increase max file uploads (default 20)
php_value max_file_uploads 50
```

**Use case:** Media uploads, plugin/theme installation, backup uploads.

**Testing:**
```php
<?php
phpinfo();
// Search for upload_max_filesize and post_max_size
?>
```

#### Error Handling

**What it does:** Controls error display and logging.

```apache
# Production (hide errors)
php_flag display_errors off
php_flag log_errors on
php_value error_log /home/yourdomain.com/logs/php_errors.log

# Development (show errors)
php_flag display_errors on
php_value error_reporting 32767
```

**Use case:** Debugging vs production security.

#### Session Configuration

**What it does:** Configures PHP sessions.

```apache
# Session lifetime (1 hour)
php_value session.gc_maxlifetime 3600

# Session cookie (close browser = logout)
php_value session.cookie_lifetime 0

# Session security
php_flag session.cookie_httponly on
php_flag session.cookie_secure on
php_value session.cookie_samesite Strict
```

**Use case:** Login session duration, security.

#### Timezone

**What it does:** Sets server timezone.

```apache
php_value date.timezone "America/New_York"
php_value date.timezone "Europe/London"
php_value date.timezone "Asia/Tokyo"
```

**Use case:** Correct timestamps in logs, posts, events.

**Testing:**
```php
<?php
echo date_default_timezone_get();
?>
```

### CyberPanel Integration

#### WordPress Performance Tuning

```apache
# In /home/yourdomain.com/public_html/.htaccess

# WordPress recommended settings
php_value memory_limit 256M
php_value max_execution_time 300
php_value max_input_time 300
php_value max_input_vars 5000
php_value upload_max_filesize 64M
php_value post_max_size 64M

# Production error handling
php_flag display_errors off
php_flag log_errors on
php_value error_log /home/yourdomain.com/logs/php_errors.log

# Session security
php_flag session.cookie_httponly on
php_flag session.cookie_secure on
```

#### WooCommerce Optimization

```apache
# WooCommerce needs more resources
php_value memory_limit 512M
php_value max_execution_time 600
php_value max_input_vars 10000
php_value upload_max_filesize 128M
php_value post_max_size 128M
```

#### Development vs Production

**Development .htaccess:**
```apache
php_flag display_errors on
php_value error_reporting 32767
php_flag display_startup_errors on
php_value memory_limit 512M
```

**Production .htaccess:**
```apache
php_flag display_errors off
php_flag log_errors on
php_value error_log /home/yourdomain.com/logs/php_errors.log
php_value memory_limit 256M
```

### Common Use Cases

#### Fix "Memory Exhausted" Error

```apache
php_value memory_limit 512M
```

#### Fix "Maximum Execution Time Exceeded"

```apache
php_value max_execution_time 300
```

#### Fix "Upload Failed" (File Too Large)

```apache
php_value upload_max_filesize 100M
php_value post_max_size 100M
```

#### Fix "Maximum Input Vars Exceeded" (WordPress Theme Options)

```apache
php_value max_input_vars 10000
```

### Supported Directives

Most PHP ini settings can be changed:

**✅ Supported:**
- memory_limit
- max_execution_time
- max_input_time
- max_input_vars
- upload_max_filesize
- post_max_size
- display_errors
- log_errors
- error_log
- error_reporting
- session.* (all session directives)
- date.timezone
- default_charset
- output_buffering

**❌ Not Supported:**
- enable_dl (PHP_INI_SYSTEM only)
- safe_mode (deprecated)
- open_basedir (security setting)

---

## 10. Brute Force Protection

### What is Brute Force Protection?

Built-in WordPress login protection. Limits POST requests to wp-login.php and xmlrpc.php to stop password guessing attacks.

### Quick Start

```apache
BruteForceProtection On
```

That's it! Default settings: 10 attempts per 5 minutes.

### How It Works

1. Tracks POST requests to `/wp-login.php` and `/xmlrpc.php`
2. Counts requests per IP address
3. Uses time-window quota system (e.g., 10 requests per 300 seconds)
4. When quota exhausted, applies action (block, log, or throttle)
5. Quota resets after time window expires

### Phase 1 Directives (Basic)

| Directive | Values | Default | Description |
|-----------|--------|---------|-------------|
| **BruteForceProtection** | On/Off | Off | Enable protection |
| **BruteForceAllowedAttempts** | 1-1000 | 10 | Max POST requests per window |
| **BruteForceWindow** | 60-86400 | 300 | Time window (seconds) |
| **BruteForceAction** | block/log/throttle | block | Action when limit exceeded |

### Phase 2 Directives (Advanced)

| Directive | Values | Default | Description |
|-----------|--------|---------|-------------|
| **BruteForceXForwardedFor** | On/Off | Off | Use X-Forwarded-For for real IP |
| **BruteForceWhitelist** | IP list | (empty) | Bypass protection for these IPs |
| **BruteForceProtectPath** | path | (none) | Additional paths to protect |

### Actions Explained

#### block (Recommended)

**What it does:** Immediately returns 403 Forbidden.

```apache
BruteForceAction block
```

**Response:**
```
HTTP/1.1 403 Forbidden
Content-Type: text/html

<html>
<head><title>403 Forbidden</title></head>
<body>
<h1>Access Denied</h1>
<p>Too many login attempts. Please try again later.</p>
</body>
</html>
```

**Use case:** Production sites, maximum security.

#### log (Monitoring)

**What it does:** Allows request but logs to error.log.

```apache
BruteForceAction log
```

**Use case:** Testing, monitoring before enabling blocking.

**Check logs:**
```bash
grep BruteForce /usr/local/lsws/logs/error.log
```

#### throttle (New in v2.2.0)

**What it does:** Applies progressive delays before responding.

```apache
BruteForceAction throttle
```

**Throttle levels:**

| Over-Limit Attempts | Level | Delay | HTTP Response |
|---------------------|-------|-------|---------------|
| 1-2 | Soft | 2 seconds | 429 Too Many Requests |
| 3-5 | Medium | 5 seconds | 429 Too Many Requests |
| 6+ | Hard | 15 seconds | 429 Too Many Requests |

**Response includes:**
```
HTTP/1.1 429 Too Many Requests
Retry-After: 15
```

**Use case:** Slows down attackers while allowing legitimate users who forgot password.

### How to Use

#### Basic Protection (Small Site)

```apache
# Simple protection
BruteForceProtection On
```

**Result:** Default 10 attempts per 5 minutes, then block.

#### Strict Protection (High Security)

```apache
# Only 3 attempts per 15 minutes
BruteForceProtection On
BruteForceAllowedAttempts 3
BruteForceWindow 900
BruteForceAction block
```

**Result:** Very strict, good for high-value targets.

#### Moderate Protection with Throttle (Recommended)

```apache
# 5 attempts per 5 minutes, then progressive throttle
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
```

**Result:** Legitimate users can still login (slowly), attackers waste time.

#### Behind Cloudflare/Proxy

**Problem:** All requests appear to come from proxy IP.

**Solution:** Use X-Forwarded-For to get real client IP.

```apache
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
BruteForceXForwardedFor On
```

**Important:** Only enable if behind trusted proxy (Cloudflare, nginx).

#### With IP Whitelist

**What it does:** Allows unlimited attempts from trusted IPs.

```apache
BruteForceProtection On
BruteForceAllowedAttempts 3
BruteForceWindow 900
BruteForceAction block
BruteForceWhitelist 203.0.113.50, 192.168.1.0/24, 10.0.0.0/8
```

**Use case:** Whitelist office IP, admin home IP, VPN range.

#### Protect Custom Login Pages

```apache
# Protect custom endpoints
BruteForceProtection On
BruteForceProtectPath /admin/login
BruteForceProtectPath /api/auth
BruteForceProtectPath /members/signin
```

**Default protected:** `/wp-login.php` and `/xmlrpc.php`

### CyberPanel Integration

#### WordPress Security Setup

**Step 1:** Navigate to website .htaccess
```bash
cd /home/yourdomain.com/public_html
nano .htaccess
```

**Step 2:** Add protection
```apache
# At top of .htaccess
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
```

**Step 3:** Save and test
```bash
# Try multiple wrong passwords
# After 5 attempts, should get throttled
```

**Step 4:** Monitor logs
```bash
tail -f /usr/local/lsws/logs/error.log | grep BruteForce
```

#### WooCommerce + WordPress

```apache
# Protect both WordPress and WooCommerce login
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction block
BruteForceProtectPath /my-account/
BruteForceProtectPath /checkout/
```

#### Multi-Site WordPress

```apache
# Apply to all subsites
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
BruteForceXForwardedFor On
```

### Shared Memory Storage

**Location:** `/dev/shm/ols/`

```bash
ls -la /dev/shm/ols/
# BFProt.shm  - Stores IP quota data
# BFProt.lock - Synchronization lock
```

**Persistence:** Data survives OpenLiteSpeed restarts (stored in tmpfs).

**Reset/Clear:**
```bash
# Clear all quota data
rm -f /dev/shm/ols/BFProt.*
/usr/local/lsws/bin/lswsctrl restart
```

**Use case:** Accidentally locked out, need to reset.

### Monitoring and Logs

#### View Brute Force Events

```bash
grep BruteForce /usr/local/lsws/logs/error.log
```

**Sample log entries:**

```
[INFO] [BruteForce] Initialized: 10 attempts per 300s window, action: throttle
[WARN] [BruteForce] Warning: 192.168.1.50 has 2 attempts remaining for /wp-login.php
[NOTICE] [BruteForce] Blocked 192.168.1.50 - quota exhausted for /wp-login.php (10 attempts in 300s)
[NOTICE] [BruteForce] Throttling 192.168.1.50 (medium level, 5000ms delay) for /wp-login.php
```

#### Real-Time Monitoring

```bash
# Watch in real-time
tail -f /usr/local/lsws/logs/error.log | grep BruteForce

# Count blocked IPs today
grep "BruteForce.*Blocked" /usr/local/lsws/logs/error.log | grep "$(date +%Y-%m-%d)" | wc -l
```

#### Check Specific IP

```bash
grep "BruteForce.*192.168.1.50" /usr/local/lsws/logs/error.log
```

### Testing Brute Force Protection

#### Manual Test

```bash
# Try multiple wrong passwords
for i in {1..15}; do
    curl -X POST https://yourdomain.com/wp-login.php \
         -d "log=admin&pwd=wrong$i&wp-submit=Log+In" \
         -I | grep "HTTP"
    sleep 1
done

# After BruteForceAllowedAttempts, should see:
# HTTP/1.1 403 Forbidden (if action=block)
# HTTP/1.1 429 Too Many Requests (if action=throttle)
```

#### Check Logs

```bash
grep BruteForce /usr/local/lsws/logs/error.log | tail -20
```

### Common Use Cases

#### Production WordPress

```apache
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction block
```

#### Behind Cloudflare

```apache
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
BruteForceXForwardedFor On
```

#### Enterprise with Whitelist

```apache
BruteForceProtection On
BruteForceAllowedAttempts 3
BruteForceWindow 900
BruteForceAction block
BruteForceXForwardedFor On
BruteForceWhitelist 10.0.0.0/8, 192.168.1.0/24, 203.0.113.100
BruteForceProtectPath /admin/
BruteForceProtectPath /api/login
```

### Troubleshooting

**Problem:** Legitimate users getting blocked

**Solution:**
```apache
# Increase allowed attempts
BruteForceAllowedAttempts 10

# Or use throttle instead of block
BruteForceAction throttle

# Or whitelist their IP
BruteForceWhitelist 203.0.113.50
```

**Problem:** Protection not working

**Solution:**
```bash
# Check module loaded
ls -la /usr/local/lsws/modules/cyberpanel_ols.so

# Check .htaccess syntax
cat /home/yourdomain.com/public_html/.htaccess | grep BruteForce

# Check logs
grep BruteForce /usr/local/lsws/logs/error.log

# Restart OpenLiteSpeed
/usr/local/lsws/bin/lswsctrl restart
```

**Problem:** Shared memory errors

**Solution:**
```bash
# Create directory if missing
mkdir -p /dev/shm/ols

# Set permissions
chmod 755 /dev/shm/ols

# Restart
/usr/local/lsws/bin/lswsctrl restart
```

---

## CyberPanel Integration

### Accessing Website Files

#### Via CyberPanel File Manager

1. Log into **CyberPanel** (https://yourserver:8090)
2. Click **File Manager**
3. Navigate to `/home/yourdomain.com/public_html`
4. Create or edit `.htaccess`
5. Add directives from this guide
6. Click **Save**

#### Via SSH

```bash
# Log in via SSH
ssh root@yourserver

# Navigate to website
cd /home/yourdomain.com/public_html

# Edit .htaccess
nano .htaccess

# Add directives
# Save: Ctrl+X, Y, Enter
```

#### Via FTP (FileZilla)

1. Connect via FTP
2. Navigate to `/home/yourdomain.com/public_html`
3. Download `.htaccess`
4. Edit locally
5. Upload back

### Creating New Website

1. **Create Website** in CyberPanel
2. **Navigate to directory:**
   ```bash
   cd /home/newsite.com/public_html
   ```
3. **Create .htaccess:**
   ```bash
   nano .htaccess
   ```
4. **Add base configuration:**
   ```apache
   # Security headers
   Header set X-Frame-Options "SAMEORIGIN"
   Header set X-Content-Type-Options "nosniff"

   # Brute force protection
   BruteForceProtection On

   # Cache static assets
   <FilesMatch "\.(jpg|png|gif|css|js)$">
       Header set Cache-Control "max-age=31536000, public"
   </FilesMatch>
   ```

### WordPress on CyberPanel

#### Complete WordPress .htaccess

```apache
# Security Headers
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header unset X-Powered-By

# Brute Force Protection
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle

# Performance - Cache Static Assets
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>

<FilesMatch "\.(css|js)$">
    Header set Cache-Control "max-age=2592000, public"
</FilesMatch>

# PHP Configuration
php_value memory_limit 256M
php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value max_execution_time 300
php_flag display_errors off

# WordPress Rewrite Rules (leave as-is)
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
```

### Staging Environment

```apache
# Staging site - restrict access
Order deny,allow
Deny from all
Allow from YOUR.OFFICE.IP
Allow from YOUR.HOME.IP

# No search engine indexing
Header set X-Robots-Tag "noindex, nofollow"

# Show errors (development)
php_flag display_errors on
php_value error_reporting 32767
```

### Testing After Configuration

```bash
# Test headers
curl -I https://yourdomain.com | grep -E "X-Frame|Cache-Control|X-Content"

# Test specific file
curl -I https://yourdomain.com/wp-content/uploads/2024/12/image.jpg | grep Cache

# Test PHP settings
echo '<?php phpinfo(); ?>' > /home/yourdomain.com/public_html/info.php
curl https://yourdomain.com/info.php | grep memory_limit

# Clean up
rm /home/yourdomain.com/public_html/info.php
```

---

## Real-World Examples

### Example 1: High-Performance WordPress

```apache
# Security
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header unset Server
Header unset X-Powered-By

# Brute Force Protection
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
BruteForceXForwardedFor On

# Aggressive Caching
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
    Header unset ETag
</FilesMatch>

<FilesMatch "\.(woff2?|ttf|eot)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
    Header set Access-Control-Allow-Origin "*"
</FilesMatch>

<FilesMatch "\.(css|js)$">
    Header set Cache-Control "max-age=2592000, public"
</FilesMatch>

# PHP Optimization
php_value memory_limit 256M
php_value max_execution_time 300
php_value upload_max_filesize 64M
php_value post_max_size 64M
php_flag display_errors off
php_flag log_errors on
```

### Example 2: WooCommerce E-commerce

```apache
# Security Headers
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"

# Strict Brute Force Protection
BruteForceProtection On
BruteForceAllowedAttempts 3
BruteForceWindow 900
BruteForceAction block
BruteForceProtectPath /my-account/
BruteForceProtectPath /checkout/

# Product Image Caching
<FilesMatch "\.(jpg|jpeg|png|webp)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>

# Don't Cache Checkout/Cart
<FilesMatch "(cart|checkout|my-account)">
    Header set Cache-Control "no-cache, no-store, must-revalidate"
</FilesMatch>

# PHP for WooCommerce
php_value memory_limit 512M
php_value max_execution_time 600
php_value max_input_vars 10000
php_value upload_max_filesize 128M
php_value post_max_size 128M
```

### Example 3: API Server

```apache
# CORS for API
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-API-Key"
Header set Access-Control-Max-Age "86400"

# JSON Response Headers
<FilesMatch "\.json$">
    Header set Content-Type "application/json; charset=utf-8"
    Header set X-Content-Type-Options "nosniff"
    Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>

# API Rate Limiting
BruteForceProtection On
BruteForceAllowedAttempts 100
BruteForceWindow 60
BruteForceAction throttle
BruteForceProtectPath /api/

# Environment
SetEnv API_VERSION v2
SetEnv API_ENVIRONMENT production
```

### Example 4: Static Site with CDN

```apache
# Aggressive Caching
ExpiresActive On
ExpiresByType image/jpeg A31557600
ExpiresByType image/png A31557600
ExpiresByType image/gif A31557600
ExpiresByType text/css A31557600
ExpiresByType application/javascript A31557600
ExpiresByType text/html A3600

# CORS for CDN
Header set Access-Control-Allow-Origin "*"

# Security Headers
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set Content-Security-Policy "default-src 'self' https://cdn.example.com"

# Remove Server Info
Header unset Server
Header unset X-Powered-By
```

### Example 5: Multi-Environment Setup

**Production (.htaccess):**
```apache
SetEnv APPLICATION_ENV production
php_flag display_errors off
php_flag log_errors on
BruteForceProtection On
BruteForceAction block
Header set X-Robots-Tag "index, follow"
```

**Staging (staging.example.com/.htaccess):**
```apache
SetEnv APPLICATION_ENV staging
php_flag display_errors on
BruteForceProtection On
BruteForceAction log
Header set X-Robots-Tag "noindex, nofollow"

# IP Restriction
Order deny,allow
Deny from all
Allow from 203.0.113.50
```

**Development (dev.example.com/.htaccess):**
```apache
SetEnv APPLICATION_ENV development
php_flag display_errors on
php_value error_reporting 32767
BruteForceProtection Off
Header set X-Robots-Tag "noindex, nofollow"
```

---

## Troubleshooting

### Common Issues

#### 1. Directives Not Working

**Symptoms:** Headers not appearing, PHP settings not applied.

**Solutions:**

```bash
# Check module is installed
ls -la /usr/local/lsws/modules/cyberpanel_ols.so
# Should show 147KB file

# Check module is loaded in config
grep cyberpanel_ols /usr/local/lsws/conf/httpd_config.conf
# Should show: module cyberpanel_ols {

# Restart OpenLiteSpeed
/usr/local/lsws/bin/lswsctrl restart

# Check logs for errors
tail -50 /usr/local/lsws/logs/error.log
```

#### 2. .htaccess File Permissions

**Symptoms:** 500 Internal Server Error

**Solutions:**

```bash
# Set correct permissions
chmod 644 /home/yourdomain.com/public_html/.htaccess

# Set correct ownership
chown nobody:nogroup /home/yourdomain.com/public_html/.htaccess

# Verify
ls -la /home/yourdomain.com/public_html/.htaccess
# Should show: -rw-r--r-- nobody nogroup
```

#### 3. Headers Not Showing

**Symptoms:** `curl -I` doesn't show custom headers

**Solutions:**

```bash
# Clear browser cache
# Some headers are cached aggressively

# Test with curl (bypasses cache)
curl -I https://yourdomain.com

# Test specific file
curl -I https://yourdomain.com/test.jpg

# Check if file exists
ls -la /home/yourdomain.com/public_html/test.jpg

# Verify .htaccess syntax
cat /home/yourdomain.com/public_html/.htaccess
```

#### 4. PHP Directives Not Applied

**Symptoms:** `phpinfo()` shows old values

**Solutions:**

```bash
# Verify using LSPHP (not PHP-FPM)
# CyberPanel uses LSPHP by default

# Check if directive is allowed
# Some directives are PHP_INI_SYSTEM only

# Create test file
echo '<?php phpinfo(); ?>' > /home/yourdomain.com/public_html/info.php

# Check value
curl https://yourdomain.com/info.php | grep memory_limit

# Delete test file
rm /home/yourdomain.com/public_html/info.php
```

#### 5. Brute Force Protection Not Triggering

**Symptoms:** Can submit unlimited login attempts

**Solutions:**

```bash
# Check shared memory directory
ls -la /dev/shm/ols/
# Should show BFProt.shm and BFProt.lock

# Create if missing
mkdir -p /dev/shm/ols
chmod 755 /dev/shm/ols

# Check .htaccess syntax
grep BruteForce /home/yourdomain.com/public_html/.htaccess

# Must be POST request to protected path
curl -X POST https://yourdomain.com/wp-login.php -d "log=test&pwd=test"

# Check logs
grep BruteForce /usr/local/lsws/logs/error.log

# Restart
/usr/local/lsws/bin/lswsctrl restart
```

#### 6. Access Control Allowing All

**Symptoms:** IP restrictions not working

**Solutions:**

```bash
# Verify your actual IP
curl ifconfig.me

# Check CIDR syntax
# 192.168.1.0/24 = 192.168.1.1 to 192.168.1.254
# 10.0.0.0/8 = 10.0.0.0 to 10.255.255.255

# Check logs for access decisions
grep "cyberpanel_access" /usr/local/lsws/logs/error.log

# Test with curl from different IP
curl -I https://yourdomain.com
# Should get 403 if not allowed
```

#### 7. Redirect Loop

**Symptoms:** ERR_TOO_MANY_REDIRECTS

**Solutions:**

```bash
# Check for conflicting redirects
grep Redirect /home/yourdomain.com/public_html/.htaccess

# Common mistake:
# BAD: Both redirects active
# Redirect 301 / https://example.com/
# Redirect 301 / https://www.example.com/

# GOOD: Only one
Redirect 301 / https://www.example.com/

# Check WordPress settings
# wp-admin > Settings > General
# WordPress Address and Site Address must match
```

### Getting Help

#### Enable Debug Logging

```bash
# Edit OpenLiteSpeed config
nano /usr/local/lsws/conf/httpd_config.conf

# Change Log Level to DEBUG
# Restart
/usr/local/lsws/bin/lswsctrl restart

# Monitor logs
tail -f /usr/local/lsws/logs/error.log
```

#### Collect Information

```bash
# Module version
ls -lh /usr/local/lsws/modules/cyberpanel_ols.so

# OpenLiteSpeed version
/usr/local/lsws/bin/openlitespeed -v

# Check .htaccess
cat /home/yourdomain.com/public_html/.htaccess

# Recent logs
tail -100 /usr/local/lsws/logs/error.log

# Test headers
curl -I https://yourdomain.com
```

#### Report Issue

When reporting issues, include:

1. **What you're trying to do** (which feature)
2. **.htaccess content** (sanitized)
3. **Expected behavior** vs **actual behavior**
4. **Error logs** (last 50 lines)
5. **Test results** (curl output)
6. **Module version** and **OpenLiteSpeed version**

---

## Performance Optimization

### Best Practices

1. **Minimize .htaccess size** - Only include necessary directives
2. **Use FilesMatch carefully** - Each pattern adds regex overhead
3. **Prefer block over throttle** - Throttle holds connections longer
4. **Whitelist known IPs** - Skips brute force checks entirely
5. **Set long cache times** - Reduce server load

### Benchmarks

| Metric | Value |
|--------|-------|
| Overhead per request | < 1ms |
| Memory per cached .htaccess | ~2KB |
| Memory per tracked IP (brute force) | ~64 bytes |
| Cache invalidation | mtime-based (instant) |

### Optimization Examples

**Before (Slow):**
```apache
# Every request checks all patterns
Header set X-Custom "Value"
Header set X-Another "Value"
Header set X-More "Value"

<FilesMatch ".*">
    Header set Cache-Control "max-age=3600"
</FilesMatch>
```

**After (Fast):**
```apache
# Only static assets checked
<FilesMatch "\.(jpg|png|css|js)$">
    Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>
```

---

## Appendix

### Quick Reference

#### Headers
```apache
Header set Name "Value"
Header unset Name
Header append Name "Value"
```

#### Access Control
```apache
Order deny,allow
Deny from all
Allow from 192.168.1.0/24
```

#### Redirects
```apache
Redirect 301 /old /new
RedirectMatch 301 ^/blog/(.*)$ /news/$1
```

#### PHP
```apache
php_value memory_limit 256M
php_flag display_errors off
```

#### Brute Force
```apache
BruteForceProtection On
BruteForceAllowedAttempts 5
BruteForceWindow 300
BruteForceAction throttle
```

### Common MIME Types

```
image/jpeg, image/png, image/gif, image/webp, image/svg+xml
text/css, text/html, text/javascript, text/plain
application/javascript, application/json, application/xml, application/pdf
font/ttf, font/woff, font/woff2
```

### Time Duration Reference

```
1 minute  = 60
5 minutes = 300
15 minutes = 900
1 hour    = 3600
1 day     = 86400
1 week    = 604800
1 month   = 2592000
1 year    = 31557600
```

### IP CIDR Cheat Sheet

```
/32 = 1 IP (255.255.255.255)
/24 = 256 IPs (255.255.255.0)
/16 = 65,536 IPs (255.255.0.0)
/8  = 16,777,216 IPs (255.0.0.0)
```

---

## Support

- **GitHub:** [github.com/usmannasir/cyberpanel_ols](https://github.com/usmannasir/cyberpanel_ols)
- **Community:** [community.cyberpanel.net](https://community.cyberpanel.net)

---

**Document Version:** 1.0
**Module Version:** 2.2.0
**Last Updated:** December 28, 2025

---

*Thank you for using the CyberPanel OpenLiteSpeed Module!*

Youez - 2016 - github.com/yon3zu
LinuXploit