Ravindra BagaleCourses & study guides मराठी Track your progress

Install WordPress on Amazon Linux 2023 with Nginx

You can now run PHP code and keep its data in MariaDB. In this chapter you install a complete PHP application that millions of websites use: WordPress. You will set it up on one Amazon Linux 2023 EC2 server with nginx, php-fpm and MariaDB, give it its own database user and the right folder owner, go through the installer, publish a post with an image, change the theme, and learn why a WordPress site breaks when the server's IP changes.

What you'll learn in this class

  • What a CMS is, how it differs from a framework, and what you can build with WordPress
  • The LEMP stack for WordPress, with php-mysqlnd, and a quick HTML and PHP test
  • Downloading the stable latest.zip and unzipping it into /usr/share/nginx/html/wordpress
  • The nginx server block: root, index index.php;, try_files and server_name _;
  • The same steps on Ubuntu: what changes
  • A wordpressdb database and a dedicated wpuser
  • Folder ownership for the php-fpm user, 755 and 644, and why never 777
  • The two installer screens: database details, then the website login
  • The wp-admin dashboard: posts, the block editor, the Media Library and themes
  • Why the site breaks when the EC2 public IP changes, and how to avoid it

1. What WordPress is: a CMS, not a framework

Why: before you install something, know what kind of software it is. It decides who does the work after the install: a developer writing code, or a site owner typing content.

What:

  1. A framework is ready-made code that helps developers build an app faster: Laravel for PHP, Django and Flask for Python, Express for Node.js. You still write the pages, the forms and the login yourself.
  2. A CMS (content management system) is a finished website that you install and then fill with content. WordPress is a CMS written in PHP. The site owner writes, styles and publishes from an admin dashboard, without code.
  3. In WordPress, pages and posts are rows in a database, not separate HTML files. When a visitor opens a post, PHP reads the row and builds the page on the spot, the way an app loads each reel from its database.

What you can build: a blog, a news site, a company website, a portfolio, a video site, or an online shop with a plugin such as WooCommerce. A shop like Flipkart could be built with WordPress too, although very large shops usually write their own code.

A framework gives you parts; a CMS givesyou a working website Framework Laravel (PHP) Django, Flask (Python) Express (Node.js) Ready-made code that helps developersbuild an app faster. You still write thepages, the forms and the login yourself.Every change means changing code. CMS: content management system WordPress (written in PHP) A finished website you install and fill.Write, style and publish from an admindashboard, with no code. Pages and postsare rows in a database, not HTML files.Themes change the look in one click. What you can build with WordPress Blog News site Company website Portfolio Video site Online shop (with a plugin) Many big sites run on WordPress. A shop like Flipkart could bebuilt with it too, although large shops usually write their owncode.

Figure 1. A framework (Laravel, Django, Flask, Express) gives developers ready-made parts; a CMS such as WordPress is a finished website that the owner fills from a dashboard. Blogs, news, company sites, portfolios, video sites and shops.

2. The server: LEMP

Why: WordPress is PHP code that keeps everything in a MySQL-compatible database. It needs a web server, PHP, an empty database and a folder it can write to.

What: LEMP = Linux + nginx (pronounced Engine-X) + MariaDB + PHP. With Apache instead of nginx the same stack is called LAMP. Here we use nginx.

How:

  1. Launch an EC2 instance with Amazon Linux 2023 and a small type such as t3.micro. In its security group allow SSH (22) from your IP and HTTP (80).
  2. Connect: ssh -i key.pem ec2-user@SERVER-IP.
  3. Install the stack, including PHP's MySQL driver:

    sudo yum install nginx mariadb105-server php php-fpm php-mysqlnd -y
    
  4. If an install fails, update the package list first with sudo yum update -y, then try again.

Classroom line

If some software won't install, update the package manager first.

  1. Start the three services:

    sudo service nginx start
    sudo service mariadb start
    sudo service php-fpm start
    
  2. Test HTML and PHP before WordPress:

    echo '<h1>HTML works</h1>' | sudo tee /usr/share/nginx/html/index.html
    echo '<?php phpinfo();' | sudo tee /usr/share/nginx/html/info.php
    
  3. Open http://SERVER-IP/ and http://SERVER-IP/info.php. You see HTML works and the long PHP information page. Then delete the test page, because it shows server details: sudo rm /usr/share/nginx/html/info.php.

L E M P: Linux, nginx (Engine-X), MariaDB, PHP Browser Opens http://SERVER-IP/ nginx Web server, port 80 · root: the wordpress folder /usr/share/nginx/html/wordpress php-fpm Runs WordPress code as user apache · needs php-mysqlnd MariaDB Database server wordpressdb · user 'wpuser' Install and start (Amazon Linux 2023) sudo yum install nginx mariadb105-server php php-fpmphp-mysqlnd -y sudo service nginx start sudo service mariadb start sudo service php-fpm start Test before WordPress echo '<h1>HTML works</h1>' | sudo tee/usr/share/nginx/html/index.html echo '<?php phpinfo();' | sudo tee/usr/share/nginx/html/info.php Both pages open: nginx and PHP work. Delete info.php after the test: itshows server details.

Figure 2. LEMP for WordPress: nginx on port 80 with its root in the wordpress folder, php-fpm running the WordPress code as apache (with php-mysqlnd), and MariaDB holding wordpressdb. Install, start and test.

3. PHP's MySQL driver

Why: WordPress's index.php starts by connecting to the database. Without the driver, PHP has no mysqli functions and the installer stops with an error that your PHP installation is missing the MySQL extension.

Classroom line

WordPress's index.php has database code in it; if you don't install the MySQL connector, the code will fail.

How:

  1. The package is php-mysqlnd. It was in the install line above; if you skipped it, install it now: sudo yum install php-mysqlnd -y.
  2. Restart only php-fpm, the program that loads PHP extensions: sudo service php-fpm restart.
  3. Check: php -m | grep -i mysql lists mysqli, mysqlnd and pdo_mysql.

4. Download WordPress

Why: WordPress is free, open-source code. You download it once onto the server, and nginx serves it from there.

Classroom line

We have to get that code from somewhere.

What: always take the stable release from https://wordpress.org/latest.zip. A copy of the development branch from GitHub is unfinished code meant for WordPress developers, not for a website.

How:

  1. Go to the web root and download:

    cd /usr/share/nginx/html
    sudo wget https://wordpress.org/latest.zip
    
  2. Unzip it: sudo unzip latest.zip. You need sudo because the web root belongs to root. If wget or unzip is missing, install them with sudo yum install wget unzip -y.

  3. The zip makes one folder, wordpress, with index.php, wp-admin, wp-content, wp-includes and wp-config-sample.php inside. Check with ls wordpress.
  4. Keep the folder name wordpress: one word, all lowercase. Linux paths are case-sensitive, so WordPress and wordpress are two different folders, and the nginx config must match exactly.

Classroom line

Use a single word; then there's no hassle later.

  1. Remove the zip: sudo rm latest.zip.

5. Point nginx at WordPress

Why: nginx still serves /usr/share/nginx/html, so the IP shows the old test page. It must serve the wordpress folder, open index.php by default, and send WordPress's post links to index.php.

What: open the main config with sudo nano /etc/nginx/nginx.conf and find the server { ... } block. These are directives, settings that nginx reads:

  1. server_name _; The underscore matches any name or IP. Keep it while you have no domain; do not invent a domain name here.
  2. root /usr/share/nginx/html/wordpress; The folder nginx serves.
  3. index index.php; When someone asks for a folder, such as /, nginx opens its index.php.
  4. location / { try_files $uri $uri/ /index.php?$args; } If the request is not a real file ($uri) or a real folder ($uri/), hand it to WordPress's index.php. WordPress post links such as /hello-world/ do not exist on disk, so without this line they give 404 Not Found.
  5. Leave the line include /etc/nginx/default.d/*.conf; in place: on Amazon Linux 2023 the php-fpm package puts its PHP settings there, so nginx can hand .php files to php-fpm.

Classroom line

If there's no domain name, you have to put an underscore there.

How: the block looks like this after the change:

server {
    listen       80;
    listen       [::]:80;
    server_name  _;
    root         /usr/share/nginx/html/wordpress;
    index        index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;
    ...
}
  1. Save, then test the syntax: sudo nginx -t. It must say syntax is ok and test is successful.
  2. Apply it: sudo service nginx reload.
  3. Open http://SERVER-IP/. WordPress redirects you to /wp-admin/setup-config.php, the installer.
The server block in /etc/nginx/nginx.conf server { listen 80; listen [::]:80; server_name _; ← _ = any name or IP; right while you have no domain root /usr/share/nginx/html/wordpress; ← the unzipped WordPress folder, all lowercase index index.php; ← a folder is asked for: open its index.php location / { try_files $uri $uri/ /index.php?$args; ← no such file or folder? hand it to WordPress   } include /etc/nginx/default.d/*.conf; ← keep it: PHP (php-fpm) handling comes from here   ... } Check, then apply sudo nginx -t # syntax is ok ... test is successful sudo service nginx reload root and index are directives, not variables. A typo stops nginx -t; fix itbefore you reload.

Figure 3. The server block: server_name _, root in the wordpress folder, index index.php, try_files to /index.php, and the include that brings in php-fpm. Then sudo nginx -t and sudo service nginx reload.

6. The same steps on Ubuntu

Why: WordPress runs on any Linux. Once you know what each piece does, only the names and paths change.

Classroom line

We've matured enough now that we can choose any OS.

What changes on Ubuntu:

  1. apt instead of yum: sudo apt install nginx mariadb-server php-fpm php-mysql -y.
  2. The web root is /var/www/html, so WordPress goes to /var/www/html/wordpress.
  3. The server block lives in /etc/nginx/sites-available/default, and PHP needs its own location ~ \.php$ block there that points to the php-fpm socket.
  4. php-fpm runs as www-data, and its service has the version in its name, such as php8.3-fpm.
  5. Apache is called apache2 on Ubuntu and httpd on Amazon Linux; nginx is nginx on both.
Same steps on Ubuntu, different names and paths Install packages AL2023 sudo yum install ... Ubuntu sudo apt install ... nginx web root AL2023 /usr/share/nginx/html Ubuntu /var/www/html nginx site config AL2023 /etc/nginx/nginx.conf Ubuntu /etc/nginx/sites-available/default MariaDB package AL2023 mariadb105-server Ubuntu mariadb-server PHP MySQL driver AL2023 php-mysqlnd Ubuntu php-mysql php-fpm service AL2023 php-fpm Ubuntu php8.3-fpm (24.04) php-fpm runs as AL2023 apache Ubuntu www-data Apache web server AL2023 httpd Ubuntu apache2 AL2023 = Amazon Linux 2023 On Ubuntu, unzip WordPress into /var/www/html/wordpress and give it towww-data. Everything else is the same.

Figure 5. Amazon Linux 2023 and Ubuntu side by side: yum and apt, /usr/share/nginx/html and /var/www/html, nginx.conf and sites-available/default, package names, and the php-fpm user apache or www-data.

7. The database and a dedicated WordPress user

Why: WordPress needs an empty database and a login for it. That login should not be root: give WordPress its own user that can touch only its own database. If the site is ever hacked, the damage stays inside that database.

How:

  1. Open MariaDB as the administrator: sudo mysql (or mysql -u root -p if you set a root password).
  2. Create the database and the user, with your own strong password in place of the placeholder:

    CREATE DATABASE wordpressdb;
    CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'YOUR_STRONG_DB_PASSWORD';
    GRANT ALL ON wordpressdb.* TO 'wpuser'@'localhost';
    FLUSH PRIVILEGES;
    exit;
    
  3. GRANT ALL ON wordpressdb.* gives wpuser every right on every table inside wordpressdb, and nothing anywhere else. WordPress needs those rights to create its tables and, later, to update them.

  4. Use lowercase names. On Linux, MariaDB database names are case-sensitive: WordPressDB and wordpressdb are two different databases, and a mismatch with the installer gives a database connection error.

Classroom line

Always use small letters, everywhere.

  1. The installer will ask for four things from this step: the database name, the user name, its password, and the host, localhost, because MariaDB runs on the same server.

Classroom line

We'll have to give these four things there.

8. Let WordPress write to its folder

Why: the installer writes wp-config.php, and later WordPress saves uploaded images, themes and updates into its folder. The folder belongs to root after sudo unzip, so PHP cannot write there. Never "fix" this with chmod 777: that lets every user and every program on the server change every file.

What: make the user that runs PHP the owner of the folder. On Amazon Linux 2023, php-fpm runs as apache (the user = apache line in /etc/php-fpm.d/www.conf). On Ubuntu it is www-data.

How:

  1. Give the folder to apache:

    sudo chown -R apache:apache /usr/share/nginx/html/wordpress
    
  2. Set folders to 755 and files to 644:

    sudo find /usr/share/nginx/html/wordpress -type d -exec chmod 755 {} +
    sudo find /usr/share/nginx/html/wordpress -type f -exec chmod 644 {} +
    
  3. 755 and 644 mean: the owner (apache) can write; everyone else, including nginx, can only read. That is all nginx needs to send images and CSS.

  4. Another way: copy wp-config-sample.php to wp-config.php yourself and type the four database values into it. The installer then skips the first screen. WordPress still needs to own wp-content for uploads and themes.
Let WordPress write to its own folder:ownership, not 777 Never do this sudo chmod -R 777 wordpress 777 = every user and every program onthe server may change every file.One bad plugin or one hacked processcan rewrite your whole site. Do this: the PHP user owns the folder W=/usr/share/nginx/html/wordpresssudo chown -R apache:apache $Wsudo find $W -type d -exec chmod 755 {} +sudo find $W -type f -exec chmod 644 {} + Result (ls -l) drwxr-xr-x apache apache wp-content-rw-r--r-- apache apache index.php-rw-r----- apache apache wp-config.php (640) 755 folders, 644 files: the owner (apache) canwrite; everyone else can only read. php-fpm runs as apache on Amazon Linux 2023 (www-data onUbuntu), so WordPress can save its files. After the install, wp-config.php holds the database password:tighten it to 640.

Figure 6. Never chmod 777. Make apache (the php-fpm user) the owner, with 755 for folders and 644 for files, so only the owner can write; tighten wp-config.php to 640 after the install.

9. The installer

Why: the installer connects WordPress to the database, creates its tables and makes your admin account. It runs once, in the browser.

How:

  1. Open http://SERVER-IP/. The first screen asks for the language. Then comes the welcome screen that lists what you need.
WordPress logo above a white box: Welcome to WordPress. Before getting started, you will need to know the following items: 1. Database name, 2. Database username, 3. Database password, 4. Database host, 5. Table prefix (if you want to run more than one WordPress in a single database). It explains that the information is used to create a wp-config.php file, and ends with a Let's go! button.

Whiteboard: The installer's welcome screen: database name, username, password, host and table prefix, which it writes into wp-config.php.

  1. Click Let's go! and fill screen 1, the database details:
    1. Database Name: wordpressdb
    2. Username: wpuser
    3. Password: the one you set in CREATE USER
    4. Database Host: localhost
    5. Table Prefix: wp_. Every WordPress table starts with this prefix, so two sites with different prefixes could even share one database. Keep wp_ for one site.
  2. Click Submit, then Run the installation. WordPress writes wp-config.php and creates its own tables in the empty database: wp_posts, wp_users, wp_options and nine more.

Classroom line

WordPress creates its own tables.

  1. Fill screen 2, the details of your website. This is a different login from the database one:
    1. Site Title: the name of the site, for example My Practice Blog. You can change it later.
    2. Username: the admin login. Pick a unique name, never admin or root: attackers try those first.
    3. Password: long and strong. WordPress suggests one; keep it safe.
    4. Your Email: where WordPress sends password resets and notices.
    5. Search engine visibility: ticking Discourage search engines from indexing this site asks Google and others not to list the site. It is a request, not a lock: anyone with the address can still open the site. Tick it while you practise; untick it when the site goes live.
  2. Click Install WordPress. You see Success!. Click Log In and sign in at http://SERVER-IP/wp-admin with the username and password from screen 2.
  3. The installer wrote wp-config.php with the database password inside and left it readable by every user on the server. Tighten it: sudo chmod 640 /usr/share/nginx/html/wordpress/wp-config.php.
The installer: database details first, then yourwebsite login Screen 1: how WordPress reaches the database Database Name wordpressdb Username wpuser Password ************ Database Host localhost Table Prefix wp_ Submit writes these into wp-config.php. define( 'DB_NAME', 'wordpressdb' ); define( 'DB_USER', 'wpuser' ); define( 'DB_PASSWORD', '...' ); define( 'DB_HOST', 'localhost' ); $table_prefix = 'wp_'; These are the values from CREATE DATABASE and CREATE USER,nothing new. Run the installation: WordPress creates its own tables MariaDB [wordpressdb]> SHOW TABLES; wp_commentmeta wp_comments wp_links wp_optionswp_postmeta wp_posts wp_term_relationshipswp_term_taxonomy wp_termmeta wp_terms wp_usermetawp_users 12 rows in set The database was empty. Every table starts with the prefix wp_, sotwo sites with different prefixes could even share one database. Screen 2: the login for your website, not for the database Site Title My Practice Blog Username site-owner-7 Password Strong (green) Your Email you@example.com ☐ Discourage search engines from indexing this site Username: unique, never admin or root; attackers try those first. Password: long and strong; keep it safe. Discourage: asks search engines not to index the site. A request, not alock. Install WordPress, then Log In at /wp-admin with this username andpassword.

Figure 7. Animation: screen 1 takes the database details and writes wp-config.php; the installation creates the 12 wp_ tables; screen 2 creates your website login: a unique username, a strong password and the search engine choice.

10. The dashboard and your first post

Why: wp-admin is the control room of the site. The site owner works here, much like managing a social media page: write, add pictures, publish.

Classroom line

What does an admin do? Supplies the content.

WordPress dashboard. A dark left menu with Dashboard, Home, Updates, Posts, Media, Pages, Comments, Appearance, Plugins, Users, Tools, Settings and Collapse Menu. On the right a dark Welcome to WordPress! banner, and below it three cards: Author rich content with blocks and patterns, Customize your entire site with block themes, and Switch up your site's look and feel with Styles.

Whiteboard: The wp-admin dashboard: the left menu (Posts, Media, Pages, Appearance, Plugins, Users, Settings) and the Welcome to WordPress panel.

How to write a post: suppose you want a small poetry blog.

Classroom line

Suppose I now want to build a shayari (poetry) website.

  1. Posts > Add Post. Type a title, then the text below it. Each paragraph is a block.
  2. To style a block, select it. The toolbar above it has bold, italic and links; the panel on the right has text colour, background and font size (S, M, L, XL).
  3. To add a picture, use your own image or one you have the right to use. Upload it first: Media > Add Media File, or the Image block's Upload button. It lands in the Media Library, and the image file is stored on your server in wp-content/uploads. Avoid inserting an image by its URL from another website: it can vanish at any time, and it is usually someone else's work.
  4. Click Publish, then View Post. Open the site's address in a new tab: the post is on the home page.
  5. Posts > All Posts lists your posts. The sample post Hello world! can be edited or moved to the trash.
The wp-admin dashboard: where thesite owner works Dashboard Posts Media Pages Comments Appearance Plugins Users Settings Posts, Add New Post Title, text, then Publish. Bold, colour and size Media, Add New Media File Upload your own images; insert them from theMedia Library Appearance, Themes Activate a theme: the whole site gets a new look Settings, General WordPress Address and Site Address: the savedURL The block editor styles a selected block from itstoolbar and the right-hand panel.

Figure 8. The dashboard menu: Posts for writing and publishing, Media for uploading images, Appearance > Themes for the look, and Settings > General for the saved site address.

11. Themes

Why: a theme decides how the whole site looks: layout, fonts, colours, header and footer. The content stays the same; one click changes the look.

How:

  1. Appearance > Themes lists the installed themes. The active one is marked Active.
WordPress admin with Appearance > Themes selected in the left menu. The page title Themes with the count 15 and an Add Theme button. Two theme cards: Twenty Twenty-Five marked Active with a Customize button, showing a blog preview with a red photo of birds, and Twenty Eleven showing a close-up photo of a wheel.

Whiteboard: Appearance > Themes: the active theme, Twenty Twenty-Five, and another installed theme, Twenty Eleven.

  1. Hover over another theme, such as Twenty Eleven, and click Activate. Refresh the site in the other tab: same posts, new look.

Classroom line

Now it feels like you've built a website, right? That's the feeling.

  1. Add Theme lets you browse thousands of free themes for blogs, news, business and shops.
  2. If WordPress asks for FTP connection details when you install a theme or plugin, it cannot write to its own folder. Check that apache owns /usr/share/nginx/html/wordpress (section 8). Installing themes with FTP is covered in the next chapter.

12. Why the site breaks when the IP changes

Why: this is the most common surprise with WordPress on EC2. During the install, WordPress saves the address you used, http://SERVER-IP, in the wp_options table as siteurl and home, and builds every link, image and CSS address from it.

What happens:

  1. An EC2 instance without an Elastic IP gets a new public IP every time it is stopped and started.
  2. You open the new IP. The page arrives, but its styles, images and links still point to the old IP, where nobody answers. /wp-admin redirects to the old IP, so you cannot even log in.

How to avoid it:

  1. Before the site goes live, give the server an address that does not change: allocate an Elastic IP and associate it with the instance, or point a domain name at that Elastic IP. Install WordPress at that address.
  2. While you practise, do not stop the instance in the middle of the work, or expect the site to break when the IP changes.
  3. You can see the saved address under Settings > General (WordPress Address and Site Address). Repairing a site whose IP has already changed is covered in the next chapter.

Classroom line

When you use WordPress, always use a static IP before going live.

Why a WordPress site breaks when the EC2 publicIP changes 1. You install WordPress at http://3.3.3.3 (example IP). SELECT option_name, option_value FROM wp_options WHEREoption_name IN ('siteurl','home'); siteurl http://3.3.3.3 home http://3.3.3.3 WordPress saves the address it was installed at, and builds every link,image and CSS URL from it. Everything works while the server keeps that IP. 2. You stop and start the instance. AWS gives it a newpublic IP: 5.5.5.5. Browser: http://5.5.5.5/ -> the page arrives, but <link href="http://3.3.3.3/wp-content/themes/..."> ->nobody answers there http://5.5.5.5/wp-admin/ -> redirects tohttp://3.3.3.3/wp-login.php The page loads without its styling, links lead to the old IP, and youcannot reach wp-admin. Repairing a site that already moved is the next chapter. 3. Before you go live: give the server an address that doesnot change. Elastic IP A static public IP you allocate and associate with the instance. Itstays the same across stop and start. A domain name For example www.example.com, pointing to the Elastic IP. InstallWordPress at the domain from the start. While practising: do not stop the instance in the middle of your work, ornote that the IP will change.

Figure 9. Animation: WordPress saves siteurl and home with the install address; after a stop and start the new IP serves a page whose links, CSS and wp-admin still point to the old IP. Use an Elastic IP or a domain before going live.

13. When something goes wrong

Why: a WordPress install has many small steps, and each error message points to one of them.

Classroom line

There are reasons behind errors; you have to look for those reasons.

  1. The IP still shows "Welcome to nginx" or your test page: root still points to /usr/share/nginx/html, or you did not reload. Fix the path, run sudo nginx -t, then sudo service nginx reload.
  2. 403 Forbidden on the home page: nginx found the folder but no index file it may open. Add index index.php; and check that root ends in /wordpress.
  3. 404 Not Found for every page: the root path does not match the folder name. /usr/share/nginx/html/WordPress is not /usr/share/nginx/html/wordpress.
  4. The installer says PHP is missing the MySQL extension: install php-mysqlnd and restart php-fpm.
  5. Error establishing a database connection: the database name, user, password or host does not match what you created. Check the case of the names, and log in with mysql -u wpuser -p wordpressdb to test the same values.
  6. The installer cannot write wp-config.php: the folder is not owned by apache. Use chown, never 777.
  7. Post links give 404, but the home page works: the try_files line is missing.
  8. You made a mistake on screen 1 or 2 and want to start again: delete and recreate the database, then open the site again; the installer runs again with the same wp-config.php. This erases everything in the site.

    sudo mysql -e "DROP DATABASE wordpressdb; CREATE DATABASE wordpressdb;"
    

    If the mistake was in the database details themselves, also delete wp-config.php so that screen 1 appears again.

Ravindra Bagale's Tip

Build the stack one layer at a time and test each layer before the next: index.html opens (nginx), info.php opens (php-fpm), mysql -u wpuser -p wordpressdb logs in (database and user), sudo nginx -t passes (config). Then open the installer. When a step fails, sudo tail -n 20 /var/log/nginx/error.log and /var/log/php-fpm/www-error.log usually name the cause in one line. And give the server an Elastic IP before you show the site to anyone.

When you're done practising, stop the EC2 instance, and remember that its public IP will change unless it has an Elastic IP.

14. Hands-on lab: WordPress from an empty server to a first post

Why this lab. WordPress runs a large share of the web, and installing it touches every skill so far: packages, services, nginx, a database user and file permissions. Each step below has a check, so you never reach the installer with a hidden problem.

  1. Install the LEMP pieces
    • Command: sudo yum install nginx mariadb105-server php php-fpm php-mysqlnd -y
    • You should see: Complete!
    • Check: php -m | grep -i mysqli → mysqli.
    • Why: WordPress is PHP code that keeps everything in a MySQL-compatible database. Without php-mysqlnd, it stops at "Your PHP installation appears to be missing the MySQL extension".
  2. Start the services
    • Command: sudo service nginx start; sudo service mariadb start; sudo service php-fpm start
    • You should see: Three redirect lines.
    • Check: http://PUBLIC_IP/ shows the nginx test page.
    • Why: Seeing the test page proves nginx and port 80 work before WordPress is involved.
  3. Download and unpack WordPress
    • Command: cd /usr/share/nginx/html && sudo wget https://wordpress.org/latest.zip && sudo unzip -q latest.zip
    • You should see: latest.zip ... saved, then the prompt.
    • Check: ls wordpress shows wp-admin, wp-content, wp-includes and index.php.
    • Why: wget on the server downloads straight from wordpress.org. -q keeps unzip from printing thousands of file names.
  4. Create the database and its user
    • Do: In sudo mysql -u root -p, run CREATE DATABASE wordpressdb;, CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'YOUR_STRONG_DB_PASSWORD'; and GRANT ALL ON wordpressdb.* TO 'wpuser'@'localhost';.
    • Check: mysql -u wpuser -p wordpressdb -e "SELECT 1;" prints 1.
    • Why: WordPress gets its own user with rights on its own database only. A hacked plugin then can't touch your other databases.
  5. Point nginx at WordPress
    • Do: In /etc/nginx/nginx.conf, set root /usr/share/nginx/html/wordpress; and add index index.php index.html; (section 5).
    • Check: sudo nginx -t → syntax is ok, then sudo service nginx reload.
    • Why: Without index.php in the index list, nginx looks only for index.html and returns 403.
  6. Let WordPress write to its folder
    • Command: sudo chown -R apache:apache /usr/share/nginx/html/wordpress
    • You should see: Nothing.
    • Check: ls -ld /usr/share/nginx/html/wordpress shows apache apache.
    • Why: On Amazon Linux, php-fpm runs as the user apache. It must own the folder to write wp-config.php and save uploads.
  7. Run the installer
    • Do: Open http://PUBLIC_IP/, pick a language, enter wordpressdb, wpuser, its password and localhost, then set the site title and your admin login.
    • You should see: Success!, then the login page.
    • Check: sudo mysql -u root -p -e "SHOW TABLES FROM wordpressdb;" lists tables starting with wp_.
    • Why: The installer writes wp-config.php and creates the wp_ tables. If it can't write the file, step 6 was missed.
  8. Publish a first post
    • Do: Log in at http://PUBLIC_IP/wp-admin, go to Posts → Add New, write a title and a line, and click Publish.
    • Check: The home page lists your post.
    • Why: The post is saved in the database, not as a file. That is why the database is what you back up for WordPress.
  9. Note the IP, then stop
    • Do: Write down the public IP you installed with, then stop the instance.
    • Check: State Stopped.
    • Why: WordPress saved that IP as the site address. After a start the IP changes, and the next chapter shows how to fix the address safely.

15. The whole class on one page

  1. A framework gives developers parts to write an app; a CMS such as WordPress is a finished website you fill from a dashboard.
  2. LEMP: sudo yum install nginx mariadb105-server php php-fpm php-mysqlnd -y, start the three services, test index.html and a PHP page.
  3. php-mysqlnd lets PHP reach MariaDB; after installing it, restart only php-fpm.
  4. Download the stable https://wordpress.org/latest.zip and unzip it into /usr/share/nginx/html/wordpress, all lowercase.
  5. Server block: server_name _;, root .../wordpress;, index index.php;, try_files $uri $uri/ /index.php?$args;; then sudo nginx -t and reload.
  6. Ubuntu: apt, /var/www/html, sites-available/default, php-mysql, user www-data.
  7. CREATE DATABASE wordpressdb; and wpuser with GRANT ALL ON wordpressdb.*, never root; lowercase names.
  8. chown -R apache:apache the folder, folders 755, files 644, never 777; wp-config.php 640 after the install.
  9. Screen 1: database name, user, password, localhost, prefix wp_. Screen 2: site title, a unique admin username, a strong password, email, and the search engine request.
  10. Dashboard: Posts to write and style, Media Library for images, Appearance > Themes for the look.
  11. WordPress saves its address; a new EC2 IP breaks the site, so use an Elastic IP or a domain before going live.
  12. To rerun the installer, drop and recreate the database.

16. Try at home

Try at home

Task 1: the stack

  1. Launch an Amazon Linux 2023 instance, install nginx, MariaDB, PHP, php-fpm and php-mysqlnd, and start all three services.
  2. Open a test index.html and info.php, then delete info.php.

Task 2: WordPress

  1. Download latest.zip, unzip it into /usr/share/nginx/html/wordpress, and set root, index and try_files.
  2. Create wordpressdb and wpuser, give the folder to apache with 755 and 644, and run the installer with a unique admin username.
  3. Run SHOW TABLES; in wordpressdb and count the wp_ tables.

Task 3: content

  1. Publish two posts, one with bold coloured text and one with an image uploaded to the Media Library.
  2. Activate a different theme and compare the site before and after.

Task 4: break it on purpose

  1. Comment out the try_files line, reload nginx, and open a post. Note the error, then put the line back.
  2. Check Settings > General and write down the saved address. Which address would break after a stop and start?

Recap

In short

  1. WordPress is a CMS written in PHP: a finished website the owner fills from a dashboard, unlike a framework, which helps developers write code.
  2. It runs on LEMP: nginx, php-fpm with php-mysqlnd, and MariaDB, all on one Amazon Linux 2023 server.
  3. Download the stable latest.zip into /usr/share/nginx/html/wordpress and point nginx's root there, with index index.php; and try_files ... /index.php?$args;.
  4. Give WordPress its own database, wordpressdb, and its own user, wpuser, with GRANT ALL ON wordpressdb.*.
  5. Make apache, the php-fpm user, the owner of the folder, with 755 and 644; never 777.
  6. Screen 1 of the installer takes the database details; screen 2 creates your website login with a unique username and a strong password.
  7. Write posts with the block editor, upload images to the Media Library, and change the look under Appearance > Themes.
  8. WordPress remembers its address, so use an Elastic IP or a domain before the site goes live.

Practice Tasks

About this scenario

Texas Solar Co is a solar energy business in Austin. Carlos Ramirez looks after its IT and cloud work. They count money in USD and run their AWS resources in the us-east-2 Region. In the tasks below you do real jobs for them using what this lesson teaches. All names, account IDs, IP addresses and numbers are made up for practice.

0 / 12

Easy Restart a service after a change

Why: Config changes only apply after the service restarts or reloads.

What to do: Restart the nginx service.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Easy Check if a service is running

Why: When a site is down, first check whether the web server process is running.

What to do: Show the status of the httpd service.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Easy Install a package on Ubuntu

Why: Ubuntu uses apt. Package names differ: on Ubuntu Apache is apache2.

What to do: Install the apache2 package on Ubuntu without being asked to confirm.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Easy Install a package on Amazon Linux

Why: dnf is the package manager on Amazon Linux 2023. -y answers yes for you.

What to do: Install the httpd package on Amazon Linux 2023 without being asked to confirm.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Easy Test a website from the server

Why: curl shows whether the web server answers, even before DNS is ready.

What to do: Request http://localhost and show only the response headers.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Easy Download code from GitHub

Why: git clone copies the whole repository to the server, ready to deploy.

What to do: Clone https://github.com/texassolar/website.git into the current folder.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Medium Test the nginx config

Why: A test catches typos before a restart takes your site down.

What to do: Check the nginx configuration files for errors.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Medium Start a service now and at boot

Why: enable makes it start after reboot; --now also starts it right away.

What to do: Enable the nginx service and start it immediately, in one command.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Medium Open port 80 to the world

Why: Visitors can reach your website only if the security group allows HTTP.

What to do: Allow inbound TCP port 80 from 0.0.0.0/0 on security group sg-011225c015104c3b2.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Remove small orders

Why: Querying the database is daily work after you set up RDS.

What to do: Delete orders with amount below 200.

Tables: customers(id, name, city) and orders(id, customer_id, amount, odate).

How:
  1. Find the table the task is about (see the table list above the box).
  2. Write the SQL statement step by step: what, from where, which rows.
  3. End the statement with ;
  4. Click Check answer. Your query runs on a practice copy of the table.

Hard Enable an nginx site on Ubuntu

Why: On Ubuntu, a site is enabled by a symbolic link from sites-available to sites-enabled.

What to do: Create a symbolic link to /etc/nginx/sites-available/texassolar inside /etc/nginx/sites-enabled/.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Hard Sales per customer

Why: Querying the database is daily work after you set up RDS.

What to do: Show customer_id and total amount per customer, only where total is above 1000.

Tables: customers(id, name, city) and orders(id, customer_id, amount, odate).

How:
  1. Find the table the task is about (see the table list above the box).
  2. Write the SQL statement step by step: what, from where, which rows.
  3. End the statement with ;
  4. Click Check answer. Your query runs on a practice copy of the table.

Revision, comparison and interview cards

Revise this lesson in a few minutes. Save the cards on your phone or download them as PNG files. The QR code on each card opens this lesson.

Revision card: What is a CMS like WordPress?. Non-coders must add posts and pages without editing HTML. A CMS (content management system) is a ready app with an admin panel to manage content. Install it on LEMP, then manage everything at /wp-admin. Blog, shop or college site: posts, Media Library and themes.
Revision card: What is a CMS like WordPress? · Download PNG
Revision card: Nginx server block for WordPress. Without the right block, Nginx shows 404 or downloads PHP. root = WordPress folder, index index.php, and try_files sends pretty URLs to index.php. Edit the block, nginx -t, reload. Key line:
Revision card: Nginx server block for WordPress · Download PNG
Revision card: WordPress database and user. Using root for the app is risky; a leak gives full database access. Create one database and one user with rights only on it. Run the SQL, then give these details on the first installer screen. SQL:
Revision card: WordPress database and user · Download PNG
Revision card: WordPress file permissions. Uploads and plugin installs fail if PHP cannot write; 777 lets anyone write. Owner = the php-fpm user. Folders 755, files 644. Never 777. chown the folder, then set 755/644 with find. Folders:
Revision card: WordPress file permissions · Download PNG
Comparison: CMS vs Framework. CMS: A ready app with an admin panel for content. Framework: A toolkit of code to build your own app.
Comparison: CMS vs Framework · Download PNG
Interview card: What is the difference between a CMS and a framework?. A CMS is a finished app you configure; a framework is a toolkit to write your own app. CMS is fast for content sites; frameworks fit custom logic. WordPress = CMS. Laravel or Flask = framework.
Interview card: What is the difference between a CMS and a framework? · Download PNG
Interview card: Why never set WordPress folders to 777?. 777 lets every user and process write and run files. One hacked plugin could then change any file. Right way: owner = php-fpm user, 755 folders, 644 files.
Interview card: Why never set WordPress folders to 777? · Download PNG
Interview card: Why does WordPress break when the EC2 public IP changes?. WordPress saves the site URL with the old IP in its database. Links and CSS still point to the old IP. Use an Elastic IP or a domain from the start.
Interview card: Why does WordPress break when the EC2 public IP changes? · Download PNG
Interview card: What does try_files do in the WordPress Nginx config?. It serves a real file if it exists, otherwise passes the request to index.php. WordPress pretty links like /about/ are not real folders. Line:
Interview card: What does try_files do in the WordPress Nginx config? · Download PNG

More cards: Ravi Sir's Cards.