Learning tailwind (Getting started)

For website speed, I am considering tailwind, a CSS framework that acts more like a library than a framework.

I will be adding my notes here, and the links at the bottom.

Which is better, tailwind or bootstrap

Well, like i said above, you are comparing apples to oranges, while it is very easy to spot a bootstrap theme when you see one, tailwind is more like CSS extended, so you have elements that you can use in your design, but your design is yours 😉

Some of the cool tutorials I have found….

Traversy Media : Tailwind CSS Crash Course (30 minutes)
Traversy Media : Tailwind Crash Course | Project From Scratch (1:30)
Net Ninja – Tailwind CSS Tutorial

Development in TailWind CSS

All you need for developing in TailWind is your CSS editor (VS Code in this post), then you will need NodeJS, and NPM to generate the production CSS and minify it

I will create a few ultra simple files for you to learn the process,

  • the HTML file: Where you add your HTYML
  • The tailwindCSS file, from which the production CSS file is copied.
  • The NPM config file and the tailwind config file WHICH YOU CAN SIMPLY COPY FROM HERE and modify if needed

I personally use Debian Linux, everything should be identical on Windows and Mac, I will assume you are using the command line on Linux, but if you open the command prompt on windows, it should work exactly the same way

Website building checklist 2023

Long gone are the days where you published a simple page and search engines sent you traffic, in this day and age, even that page, no matter how important the content in it is, needs to be on a website that meets certain criteria

  • Privacy Policy: A privacy policy is essential, I will enumerate all the things that you will lose for not having a privacy policy right after this list
  • Cookie banner: or any notification in general, asking the user for consent to use cookies
  • Mobile and small screen compatibility: the most common form of that is a responsive design, no design at all can often be responsive as well, but that is a different topic altogether, this compatibility also includes the spacing of clickable content as well as showing elegantly on the small screens
  • Speed: Search engines seem to like faster websites more, it improves their visitor’s experience
  • Create distinctive favicons of various sizes, they help people identify your website in search results and other places, so whether they are looking for something they have seen on your website before, or want to find the tab in their browser, you make it easy for them

How to pick a domain name registrar

Factors to consider

First of all, the choice depends on 3 things, or 4 but to me, the fourth is not very important

  • PRICE for a given TLD (TLD = .com, .net, etc…) and it’s persistence
    This is probably the most important factor, there is no such thing as “Performance” as your registrar does not run the TLD’s registry, something to take into account is also the renewal price next year.
  • whether or not you plan to use their “Usually free” nameservers (Most people will use their web host’s nameservers and not the registrar’s)
  • The business stability of the registrar, when a registrar goes down, you might find your domains with a registrar who picked up all the domains the sunken registrar had, and if you were using the old registrar’s add on services, you will end up needing to redo them, and probably find a different registrar that you like to move those domains to.
  • And last but not least, the interface and speed of the registrar’s website and tools, I don’t think this is very important as most registrars have a usable interface and you will only need to use it infrequently

Which one do i recommend ?

I personally use more than one registrar, for some TLDs, I use nameCheap, and for the more standard domain TLDs (Like .COM etc…) I used godaddy for a long time, then i switched to a godaddy reseller (PoloDomains), it has the same exact products (and phone support) as godaddy and in my experience this reseller has very persistent prices that are lower than those of godaddy themselves, not to mention that godaddy keeps surprising me with different pricing when the time comes to renew. Again, godaddy is a good registrar that checks all the boxes, but the reseller is more or less just cheaper. other good well known registrars include namesilo.com, google domains (Not recommended as google is selling it to another company), Name.com, domain.com and many others that you can research online…

Get it for free when it makes sense

Some web hosts offer free domain names for as long as you are paying for your hosting, this is not exactly a catch, but it might be, so what I do is decide on a web host through reviews and what have you, and if that web host offers free or cheap domains with their web hosting, then that is where I will get my domain, But mind you, when i make the choice, i subtract 1/12 of the normal domain price (that you would get if you used a separate registrar) from the monthly hosting fee, and then compare the web-hosts with the new discounted price tag, the last thing i want is to get stuck with a bad web host because they offer a free domain, that would be a very bad decision.

When is the registrar relevant to performance ?

The main function of a registrar is to sell you domains and register them with a registry, after registering them, the registrar also informs the registry of what nameservers to use with the domain name. after that, the registrar in it’s strict form has no technical function, up until you either want to renew that domain, or change the nameservers attached to that domain, a web request (from a website visitor for example) does not pass through your registrar.

The above remains true, unless you opt to use one of those free DNS services that are provided by many registrars, in this scenario you are using the registrar’s DNS servers instead of your host’s or a third party, which is not a bad idea depending on the quality of your registrar, godaddy (and it’s resellers) provides a free DNS service that uses anycast ! anycast is a cool internet technology where the user will be using the closest DNS server to them without knowing, effectively cutting down the latency of the DNS request.

NGINX – Common tweaks

if you are processing data with nginx and PHP-FPM, you might want to increase the following

“504 Gateway Timeout” is when nginx is waiting for a response from php-fpm for too long, you can fix that with

Increase PHP maximum execution time in /etc/php.ini: max_execution_time = 300
Increase PHP-FPM request terminate timeout in the pool configuration (/etc/php/8.2/fpm/pool.d/www.conf): request_terminate_timeout = 300

To disable all timeouts… you can add the following into any context, for serverwide, add anywhere in the http context (in /etc/nginx/nginx.conf)

keepalive_timeout 1d;
send_timeout 1d;
client_body_timeout 1d;
client_header_timeout 1d;
proxy_connect_timeout 1d;
proxy_read_timeout 1d;
proxy_send_timeout 1d;
fastcgi_connect_timeout 1d;
fastcgi_read_timeout 1d;
fastcgi_send_timeout 1d;
#memcached_connect_timeout 1d;
#memcached_read_timeout 1d;
#memcached_send_timeout 1d;

URL Rewrite in nginx (coming from Apache)

If you are like me, you already know how to use MOD-REWRITE in apache2, but need guidance to implement things in nginx !

There are three directives in nginx concerning rewriting, namely return, rewrite, and try_files Directives, what i will be starting with is rewrite, since most websites on Apache use “rewrite_rule” which can be easily translated into rewrite

I will also provide the most common examples for software such as WordPress, laravel, and other software so that you can get up and running in the shortest possible time

1- Translating my RewriteRule from Apache into nginx

The good news is, it is very easy, I will provide a few simple guidelines, then provide examples.

  • The counterpart to RewriteRule in apache2 in nginx is rewrite, so start by changing the text RewriteRule into rewrite
  • Replace [L] or [QSA,L] with the string “last;”, Notice that configuration entries in nginx end in a semicolon
  • Wherever there is an occurrence of ^ follow it with a /, Making it ^/
  • In nginx, curly braces are used for two purposes, block control and regular expressions, so if your existing apache2 rules contain those curly braces for regular expressions, you can tell nginx that this is a regular expression not block control by surrounding the regular expression with quotes (double or single).

So let me create an example, explain what it does, and show you how it is translated into nginx rewrite

What it doesIn ApacheIn nginx
This rewrites
everything onto
the index.php file,
except for the
contents of one
folder named
norewrite
* RewriteEngine on
* RewriteRule ^norewrite(.) – [L]
* RewriteRule ^(.)$ index.php?q=$1 [L,QSA]
Create a separate section
for the folder norewrite,
and then use the following
* rewrite ^(.*)$ /index.php?q=$1 last;

Changing the default port 80 on nginx

First of all, check what ports nginx is currently listening on, you can do that with any of the following commands

netstat -tlpn| grep nginx
ss -tlpn| grep nginx

So, you probably found nginx listening to port 443 for SSL connections, and on port 80 for plain http….

On many occasions, you may want other application (Such as varnish or apache) to be listening on port 80, So nginx needs to move to another port, in this example, I am moving it to port 8080

Step 1: Go to sites available, there is the default site, and there are any other sites you added to nginX, open those config files that you will find in /etc/nginx/sites-available, search for 80, and replace it wherever it may occure with 8080 or any port of your choice, restrictions are the following, port numbers under 1024 will requier root privilages (So keep it above 1024), and the maximum port number is 65535, Also port 0 can not be used for http (Relevant to UDP though)

WordPress does not load correctly (SOLVED) behind nginx/varnish reverse proxies !

Here is my problem, I have a website, and in a directory in that website, I have a wordpress installation, and that installation opens correctly, loads all the images, css, js and any other files for a proper experience, only problem is, when you put this behind a varnish reverse proxy, and an nginx reverse proxy for SSL (https), the website design (theme) does not load, you only see the actual html page that was loaded, but all other elements are never fetched from the server, i actually sniffed the data and found that css, javascript, and images are never even requested !

So the short of this story, if you are having problems with page loading without the theme or design, and you have a similar setup, odds are the problem is with wordpress settings not with nginx or with varnish !

So a closer look at the page source reveals that the page was loaded with https, but the links to all the page resources are in HTTP ! why is that ? simple

when you open the website in SSL, your browser creates a secure connection with nginx (termination), nginx requests the page from varnish, which relays the page again to the server.

As far as the web server serving wordpress is concerned, this request came in http, not https ! so all the page resources should be in http right ? yes, this is what is happening, but what is the solution

I tried a few solutions, for example, i changed the wordpress address and site address to httpS, but wordpress is smart enough to use whatever protocol the user accessed and use it for all resources !

there are many solutions programmatically, which is something i avoid because i update wordpress, and don’t want to fix it every time i upgrade, so whatever solution i need has got to be in the only file that is never modified when upgrading wordpress, the config file

wordpress knows it is on SSL from the following two entries in the environment, the entries $_SERVER[‘HTTPS’] and $_SERVER[‘SERVER_PORT’], the proxy sends a hint that the user used https with the variable $_SERVER[‘HTTP_X_FORWARDED_PROTO’] in the request header, hence, adding the following code snippet somewhere in the beginning of the config file should deceive wordpress into thinking it has been accessed over https !

if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'){
   $_SERVER['HTTPS'] = 'on';
   $_SERVER['SERVER_PORT'] = 443;
 }

Hope this all works okay for you, if not please let me know in the comments and i would be more than glad to help

Varnish would not listen on port 80 on debian 11 and 12 (Bookworm)

So, before we start, I assume you have already installed Varnish the casual way, and that you have made sure you do not have something else occupying port 80, if nginx for example is listening on port 80, try this post to switch it to a different port (Changing the default port 80 on nginx), if it is a different app, just follow that app’s instructions to change it’s port before asking varnish to listen on it.

To check that port 80 is not occupied and free to use, try the following command

netstat -anpe | grep "80" | grep "LISTEN"

If for example you want to know what ports nginx is listening to, try one of the following commands

netstat -tlpn| grep nginx
or
ss -tlpn| grep nginx

Within the results, check if any are using port 80, mind you, a service using port 8083 for example will show up, you need to see if anything is using port 80 , Now, install varnish with the following command.

apt-get install varnish

As you may have noticed, and probably the reason why you are here, varnish will not work !

this is somewhat of an old problem, since Debian moved to systemD back with the Debian 8 release (Jessie), instead of editing the file in /etc/default/varnish, you will need to create a file in /etc/systemd/system/ and name it varnish.service, the contents of such a file should look like the following, note that xxx.xxx.xxx.xxx is the IP varnish should be listening on, one of the IPs assigned to the machine running varnish.

So to run the following command

systemctl edit varnish.service
[Unit]
Description=Varnish HTTP accelerator
Documentation=https://www.varnish-cache.org/docs/6.1/ man:varnishd

[Service]
Type=simple
LimitNOFILE=131072
LimitMEMLOCK=82000
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a xxx.xxx.xxx.xxx:80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m
ExecReload=/usr/share/varnish/varnishreload
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
PrivateDevices=true

[Install]
WantedBy=multi-user.target

Once you have added the file execute the following

systemctl daemon-reload
systemctl restart varnish

Should i let varnish cache in RAM or switch to disk ?

Note that the configuration file above uses RAM to cache the content, My recommendation is to use DISK (Disk is cached in ram in a more dynamic and more useful way utilizing all the ram you are not using, while keeping it available to any app that needs it), but that is just me…

To switch from RAM to File system, replace the following in the above as follows

"-s malloc,512m" becomes "-s file,/path/to/cahce/file.bin,100G"

WordPress, Varnish, nginx: The SSL https detection problem

I have a certain setup with a Varnish5 caching reverse proxy, with nginx to terminate SSL connections.

The problem with this setup is that wordpress can’t detect https, hence, it can not enforce it, nor will it link the CSS accordingly etc…, and if your blog’s address starts with https, you have a problem.

there is more than one solution that i will enumerate here, I chose to force all connections to come through https (The first), but there are others, the one i will present here (Which i did not use) resolves the problem and allows wordpress to detect whether we are on a secure connection or not.

And even though this post-article talks about wordpress, everything here can apply to any PHP application (Or even other applications written in different programming languages)

1- Enforce https for the whole website

The simplest way to solve the problem (Which i chose) is to redirect all traffic to https.

in the varnish script, implement the following

in the sub vcl_recv, implement the following

if (req.http.host ~ "^(www\.)?example\.com$") 
{
	if (req.http.host ~ "^(?i)example.com" || req.http.X-Forwarded-Proto !~ "(?i)https") {
		return (synth(750, ""));
	}
}

Now, the following section is the sub vcl_synth

sub vcl_synth {
    if (resp.status == 750) {
        set resp.status = 301;
        set resp.http.Location = "https://www.example.com" + req.url;
        return(deliver);
    }
}

Once the above is in place in the varnish script, You will need to tell wordpress that it’s all HTTPS (SSL)

We do that in the config file, the only file we know that does not change when we update

define('FORCE_SSL_ADMIN', true);
$_SERVER['HTTPS']='on';

Now, the above should do it if you don’t mind that your website only works in https, if you do want http to remain an option, then here is another solution

Start by creating a phpinfo() page to check whether you have the $_SERVER[‘HTTP_X_FORWARDED_PROTO‘] variable , if you do, your work is partially done, but you need to mind too things

the varnish server needs to only cache the https copy (because most browsers won’t allow mixed content these days, and if the css is linked to as http, it won’t display correctly), you can do that easily with something like the following in the vcl_hash area

if (req.http.X-Forwarded-Proto) {
        hash_data(req.http.X-Forwarded-Proto);
    }

And then, also in the wp-config file, add the following (probably almost anywhere)

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
        $_SERVER['HTTPS']='on';

Exposing visitor IP to apache through varnish

In a previous post, i posted how you can put varnish on a virtual machine to cache content for your web server, But there was one small thing that we did not deal with, The IP address in the logs and that the website can see is simply that of the varnish server, not the visitor’s IP, and if you write PHP like me, I use the IP in everything, from securing logins to limiting page views to limiting comments. So, here is how we can work around this problem

First, the mission is as follows, Varnish needs to append something in the request header, that apache needs to consider the Visitor’s IP

To make apache do that, there is already a module (mod-remoteip) to do this

1- Tool to check the IP of the visitor

Create a PHP script to find out if what we are doing actually worked.

<?php
print "Your IP is: {$_SERVER['REMOTE_ADDR']} <br />\n\n";
$headers = apache_request_headers();
foreach($headers as $xheader => $xvalue)
{
print "$xheader : $xvalue <br />\n"; }
?>

and upload it to the website, when accessing this from the internet, you should see the IP as the IP of the varnish server, not your IP (Like it should)

1- Playing with cpanel

First, we must download mod_remoteip from the cpanel website (See here)

Once downloaded, we will upload it to the cpanel server at

/var/cpanel/easy/apache/custom_opt_mods/

Once done, we will now extract it as we would extract any tar.gz file

cd /var/cpanel/easy/apache/custom_opt_mods
tar -C /var/cpanel/easy/apache/custom_opt_mods -xvf custom_opt_mod-remoteip.tgz

Now, this mod should appear in easy apache when rebuilding apache, so go ahead, visit

Home »Software »EasyApache 3

and on the Exhaustive Options List you should be able to see mod_remoteip, be sure to check it.

Now, before coming to configure it, We need to inform Varnish to send us those headers. So add this at the very beginning of the Varnish sub vcl_recv section

NOTE: It seems that for the latest varnish (VCL 4), you no longer need this, if you add this, you will get the header as ( X-Forwarded-For : xxx.105.60.194, xxx.105.60.194) meaning the same IP twice

if (req.restarts == 0) {
  if (req.http.X-Forwarded-For) {
    set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
  } else {
    set req.http.X-Forwarded-For = client.ip;
  }
}

Now, we need to tell apache, what the extra header’s name is (X-Forwarded-For) and what servers this header should be honored for (the varnish server IPs, currently displaying in the script we wrote right after Your IP is:) So start by editing

/usr/local/apache/conf/includes/pre_virtualhost_global.conf

And add this, the IP here is the varnish server IP

<IfModule mod_remoteip.c>
   RemoteIPHeader X-Forwarded-For
   RemoteIPInternalProxy xxx.172.13.208
</IfModule>

Or, Probably the more suitable

/usr/local/apache/conf/includes/pre_virtualhost_global.conf

And add this, the IP here is the varnish server IP

<IfModule mod_remoteip.c>
   RemoteIPHeader X-Forwarded-For
   RemoteIPTrustedProxy xxx.172.13.0/24
   RemoteIPTrustedProxy xxx.172.14.0/24
   RemoteIPTrustedProxy xxx.172.19.0/24
</IfModule>

Now, visit Home >> Restart Services on your cpanel server, and restart apache

There you have it, refresh that PHP script, and your IP address should appear.

Now, the apache logs will still log the Varnish server IP, to fix that, you need to modify the log section in your apache config, changing %h with %a, like so

#LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined