Showing posts with label Web Server. Show all posts
Showing posts with label Web Server. Show all posts

Friday, 10 May 2024

Introduction to Nginx

 




What is Nginx?

  • HTTP and reverse proxy server
  • widely used webserver 


How to install Nginx on Linux?


Nginx serves a static HTML file by default so we can verify the deployment.


Where is Nginx binary?

# which nginx
/usr/sbin/nginx

To check Nginx version:

# nginx -v
nginx version: nginx/1.24.0


Nginx Configuration



Nginx configuration file is /etc/nginx/nginx.conf.

cat /etc/nginx/nginx.conf
#######################################################################
#
# This is the main Nginx configuration file.
#
# More information about the configuration options is available on
#   * the English wiki - http://wiki.nginx.org/Main
#   * the Russian documentation - http://sysoev.ru/nginx/
#
#######################################################################

#----------------------------------------------------------------------
# Main Module - directives that cover basic functionality
#
#   http://wiki.nginx.org/NginxHttpMainModule
#
#----------------------------------------------------------------------

user                 mywebapp-user;
# user                 nginx;

worker_processes     auto;
worker_rlimit_nofile 10000;

#timer_resolution 100ms;

error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;

pid        /var/run/nginx.pid;

#----------------------------------------------------------------------
# Events Module
#
#   http://wiki.nginx.org/NginxHttpEventsModule
#
#----------------------------------------------------------------------

events {
worker_connections  4000;
# worker_connections  1024;
use epoll;
#    accept_mutex on;
}

#----------------------------------------------------------------------
# HTTP Core Module
#
#   http://wiki.nginx.org/NginxHttpCoreModule
#
#----------------------------------------------------------------------

http {

server_names_hash_bucket_size 128;

        map $http_cf_ipcountry $allowed_country {
           default 1;
           "KP"    0; # Korea, Democratic Peoples Republic of (North Korea)
        }

include       /etc/nginx/mime.types;
default_type  application/octet-stream;

        log_format    main '$remote_addr - $remote_user [$time_local] "$host"
                      "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" 
                      "$http_cf_ipcountry"';

access_log  /var/log/nginx/access.log  main;

gzip            on;
gzip_vary       on;
gzip_types      text/plain 
                        text/xml 
                        text/css 
                        application/json
                        application/x-javascript;
gzip_min_length 1024;

server_tokens off;

# Replace client IP from proxies
real_ip_header X-Forwarded-For;
set_real_ip_from 10.0.0.0/8;  # AWS VPC CIDR
set_real_ip_from 108.22.214.0/22; # Cloudflare 
...
set_real_ip_from 2b06:27c0::/29; # Cloudflare 
real_ip_recursive on;

sendfile        on;
# tcp_nopush      on;
# tcp_nodelay     on;

keepalive_timeout  60;

server {
  listen 80;
server_name "";
return 403;
}

# Load config files from the /etc/nginx/conf.d directory
include /etc/nginx/conf.d/*.conf;
}

This is a base config file which is usually enough if we're hosting a single website.

If we're hosting multiple websites/domains/brands, we want to keep their configuration isolated in separate files which reside in /etc/nginx/conf.d/*.conf. We create a config file for each website and define for example different error and access log files.

ls -la /etc/nginx/conf.d/
total 56
drwxr-xr-x. 3 root     root       175 May  8 13:07 .
drwxr-xr-x. 4 root     root     16384 May  8 13:07 ..
drwxr-x---. 2 ec2-user ec2-user 16384 May  8 13:07 includes
-rw-r-----. 1 ec2-user ec2-user  1474 May  8 13:03 nginx.brandA.conf
-rw-r-----. 1 ec2-user ec2-user  1434 May  8 13:03 nginx.brandB.conf
-rw-r-----. 1 ec2-user ec2-user  1545 May  8 13:03 nginx.brandC.conf
-rw-r-----. 1 ec2-user ec2-user   858 May  8 13:03 nginx_status.conf

Let's check what can be in the override file: 

cat  /etc/nginx/conf.d/nginx.brandA.conf 
server {

# server settings
listen      80;
# listen      443 ssl;

server_name ~^(dev-|stage-|beta-)?(mywebapp)\.mydomainA\.com$;
      # server_name phpfpm.local;
      # server_name localhost; 
               
resolver    149.214.169.253; # Amazon EC2 inside VPC

# log settings
error_log /home/mywebapp-user/logs/nginx/error-mywebapp.log;
access_log /home/mywebapp-user/logs/nginx/access-mywebapp.log main;

# client settings
client_body_temp_path /home/mywebapp-user/tmp/client_body;

        # block visitors from certain countries
        if ($allowed_country = 0) {
          return 403; # forbidden
        }

# path settings
root  /home/mywebapp-user/public;
index index.html index.htm index.php;

# protect private files
        location ~ ^/private/(.*)$ {
include conf.d/includes/nginx.trusted-ips.conf;
include conf.d/includes/nginx.php-fpm-brandA.conf;
}

        # serve dmg files
        location ~ \.dmg$ {
            try_files $uri $uri/ /index.php?$query_string;
        }

        # serve pkg files
        location ~ \.pkg$ {
            try_files $uri $uri/ /index.php?$query_string;
        }

        # serve bz2 files
        location ~ \.bz2$ {
            try_files $uri $uri/ /index.php?$query_string;
        }

        # serve zip files
        location ~ \.zip$ {
            try_files $uri $uri/ /index.php?$query_string;
        }

        # serve exe files
        location ~ \.exe$ {
            add_header Content-Disposition "attachment";
            try_files $uri $uri/ /index.php?$query_string;
        }

        # return 404 for anything else
        location / {
           return 404;
        }

        # block countries defined in nginx.conf
        include conf.d/includes/nginx.geoip2.conf;

# allow .php files to be executed
include conf.d/includes/nginx.php-fpm-brandA.conf;
}


server block defines a virtual server that will handle requests. We can define multiple server blocks to handle different domains or ports.

  • listen <port_number> 
    • Listen on port <port_number> for incoming HTTP connections. 
  • listen <port_number> ssl
    • Listen on port <port_number> for incoming HTTPS connections. 
  • server_name <domain_name | IP>
    • Domain name or IP address that this server block should respond to.
    • localhost is typically used for local development. For local development we can actually use an arbitrary domain name value but then in /etc/hosts we need to add a line: 127.0.0.1 <domain_name>
    • For a live server, replace this with the actual domain name.
  • resolver
  • error_log
  • access_log
  • client_body_temp_path
  • root
    • Set the root directory for the server. This is where Nginx will look for files to serve.
    • This is where our application files should be located.
    • /var/www/html is a common directory for web content. 
  • index <file_1> <file_2> ... <file_N>
    • Specifies the default files to serve when a directory is requested.
    • If a user navigates to http://example.com/, Nginx will look for index.html, index.htm and index.php, in that order.
  • location / { ... }
    • Defines how to process requests for the root URL path.
    • This block specifies how to handle requests to the root of the website.
  • location ~ \.php$  { ... }
    • This block handles requests for PHP files. 
    • The tilde (~) indicates a regular expression match. Any request that ends in .php will be processed by this block.
  • include


location block attributes:

  • fastcgi_pass
    • Specifies the address and port of the FastCGI server (PHP-FPM).
    • Example: fastcgi_pass php-fpm:9000;
      • In this case, php-fpm:9000 indicates that PHP-FPM is running on the php-fpm service on port 9000. php-fpm matches the hostname of the machine which runs the PHP-FMP service 
  • fastcgi_index
    • Sets the default file to serve if the FastCGI request points to a directory. If a directory is requested, Nginx will serve index.php from that directory.
    • Example: 
      • fastcgi_index index.php;
      • fastcgi_index helloworld.php;
  • include fastcgi_params;
    • Includes a file with FastCGI parameters. These parameters are necessary for Nginx to communicate with PHP-FPM. The fastcgi_params file typically resides in /etc/nginx/ or /etc/nginx/conf.d/.
  •  fastcgi_param - sets FastCGI parameter's value that Nginx will send to php-fpm service (which is usually listening on port 9000)
    • SCRIPT_FILENAME $document_root$fastcgi_script_name;
      • Sets the SCRIPT_FILENAME parameter, which tells PHP-FPM the path of the script to execute. The value is constructed by appending the script name ($fastcgi_script_name) to the document root ($document_root).
    • PATH_INFO $fastcgi_path_info;
  • try_files path1 [path2] uri - Checks for the existence of files in order, and returns the first file that is found. A trailing slash indicates a directory - $uri /. In the event that no file is found, an internal redirect to the last parameter is invoked. The last parameter is the fallback URI and must exist, or else an internal error will be raised.
        
Nginx config file variables:

  • $document_root
    • a variable that represents the root directory for the current request. It is used to specify the base directory from which files are served. This variable is particularly useful when configuring PHP handling, redirections, and other file-serving directives.
    • holds the path to the root directory specified in the root directive of the server or location block handling the request.
    • commonly used in conjunction with other variables like $fastcgi_script_name to construct the full path to the PHP script being executed or served.
    • Example: if root is set to /var/www/html, a request is made for /path/to/file.html (https://www.example.com/path/to/file.html), Nginx will look for the file at /var/www/html/path/to/file.html
  • $fastcgi_script_name
    • path of the requested PHP script relative to the document root. It is used to pass the script's path to PHP-FPM for processing.
    • Suppose a client requests http://example.com/index.php
      • If $document_root is /var/www/html,  Nginx will look in /var/www/html for index.php
      • $fastcgi_script_name would be /index.php, the path relative to $document_root.
      • The full path passed to PHP-FPM via fastcgi_param SCRIPT_FILENAME would be /var/www/html/index.php.

--- --- ---

Before restarting or reloading Nginx server completely it is advisable to test its configuration file:

nginx -t
nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If we try to run this command as non-admin user, we'll get an error:

nginx -t
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
2024/05/09 16:12:33 [emerg] 349382#349382: open() "/etc/nginx/nginx.conf" failed (13: Permission denied)
nginx: configuration file /etc/nginx/nginx.conf test failed


Nginx Service


To check if Nginx service is running:

# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/nginx.service.d
             └─php-fpm.conf
     Active: active (running) since Wed 2024-05-08 13:31:37 UTC; 1 day 19h ago
    Process: 3797 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
    Process: 3804 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
    Process: 3805 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
   Main PID: 3806 (nginx)
      Tasks: 3 (limit: 2120)
     Memory: 9.6M
        CPU: 42.250s
     CGroup: /system.slice/nginx.service
             ├─3806 "nginx: master process /usr/sbin/nginx"
             ├─3807 "nginx: worker process"
             └─3808 "nginx: worker process"

May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Starting nginx.service - The nginx HTTP and reverse proxy server...
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3804]: nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3804]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3804]: nginx: configuration file /etc/nginx/nginx.conf test is successful
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[3805]: nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Started nginx.service - The nginx HTTP and reverse proxy server.

If we try to run the binary when service is already working, it will try to bind to local ports which would obvously fail:

# nginx
nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:81 failed (98: Address already in use)
nginx: [emerg] still could not bind()


To verify that nginx processes are listening on TCP ports 80 and 81 we can use lsof (list open files) command with option -i (match Internet address):

# lsof -i TCP:80
COMMAND    PID          USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
nginx     3806          root   18u  IPv4   20970      0t0  TCP *:http (LISTEN)
nginx   559036 my-user    3u  IPv4 3101478      0t0  TCP ip-10-107-112-168.ec2.internal:http->ip-10-107-112-40.ec2.internal:36372 (ESTABLISHED)
nginx   559036 my-userk    9u  IPv4 3101479      0t0  TCP ip-10-107-112-168.ec2.internal:http->ip-10-107-112-141.ec2.internal:14406 (ESTABLISHED)
...
nginx   559036 my-user   15u  IPv4 3101485      0t0  TCP ip-10-107-112-168.ec2.internal:http->ip-10-107-112-59.ec2.internal:29186 (ESTABLISHED)
nginx   559036 my-user   18u  IPv4   20970      0t0  TCP *:http (LISTEN)
nginx   559037 my-user   18u  IPv4   20970      0t0  TCP *:http (LISTEN)

# lsof -i TCP:81
COMMAND    PID          USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx     3806          root   19u  IPv4  20971      0t0  TCP *:81 (LISTEN)
nginx   559036 my-user   19u  IPv4  20971      0t0  TCP *:81 (LISTEN)
nginx   559037 my-user   19u  IPv4  20971      0t0  TCP *:81 (LISTEN)


Changing the configuration


After changing nginx.conf we need to restart nginx:

$ /etc/init.d/nginx stop
rm: cannot remove ‘/var/run/nginx.pid’: Permission denied  [FAILED]

We need to become root in order to restart nginx:

# /etc/init.d/nginx stop
Stopping nginx:                                            [  OK  ]

# /etc/init.d/nginx start
Starting nginx:                                            [  OK  ]


To reload the configuration without downtime:

# systemctl reload  nginx


Let's check the status again:

# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/nginx.service.d
             └─php-fpm.conf
     Active: active (running) since Wed 2024-05-08 13:31:37 UTC; 1 day 19h ago
    Process: 3797 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
    Process: 3804 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
    Process: 3805 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
    Process: 559035 ExecReload=/usr/sbin/nginx -s reload (code=exited, status=0/SUCCESS)
   Main PID: 3806 (nginx)
      Tasks: 3 (limit: 2120)
     Memory: 10.3M
        CPU: 42.343s
     CGroup: /system.slice/nginx.service
             ├─  3806 "nginx: master process /usr/sbin/nginx"
             ├─559036 "nginx: worker process"
             └─559037 "nginx: worker process"

May 08 13:31:37 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Starting nginx.service - The nginx HTTP and reverse proxy server...
...
May 10 09:11:32 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Reloading nginx.service - The nginx HTTP and reverse proxy server...
May 10 09:11:32 ip-10-107-112-168.us-east-1.env.my-domain.com nginx[559035]: nginx: [warn] could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
May 10 09:11:32 ip-10-107-112-168.us-east-1.env.my-domain.com systemd[1]: Reloaded nginx.service - The nginx HTTP and reverse proxy server.


Running Nginx & PHP-FPM as Docker containers


Nginx and PHP-FPM can run separately, each in its own Docker container. For Nginx, we can use the original Nginx image and for PHP-FPM we can crate a custom image, which also contains our PHP application.

It is important that both containers need to have PHP application at the same path
  • In PHP-FPM Dockerfile we can set WORKDIR to e.g. /var/www/html or /usr/share/nginx/app and copy our application's source code there
  • In Nginx conf file, in server block, we then need to set root to the absolute path to the main php script e.g. index.php. If web requests is http://example.com/path/to/index.php and path to this script in PHP-FPM container is e.g. /usr/share/nginx/app/index.php then in nginx conf we'll use  /usr/share/nginx/app/ as the value of root ($document_root)
  • As Nginx container needs to have an access to PHP app's source code, we'll then use a volume which maps local directory with app to /var/www/html or /usr/share/nginx/app

----

References:



Thursday, 5 November 2020

Apache Web Sever on Ubuntu

Many Linux distros, including Ubuntu Debian, come with preinstalled Apache HTTP web server. It is also known as HTTPD (HTTP Daemon).


Its configuration file is /etc/apache2/apache2.conf:

$ cat /etc/apache2/apache2.conf
# This is the main Apache server configuration file.  It contains the
# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.

# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
#       /etc/apache2/
#       |-- apache2.conf
#       |       `--  ports.conf
#       |-- mods-enabled
#       |       |-- *.load
#       |       `-- *.conf
#       |-- conf-enabled
#       |       `-- *.conf
#       `-- sites-enabled
#               `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
#   together by including all remaining configuration files when starting up the
#   web server.
#
# * ports.conf is always included from the main configuration file. It is
#   supposed to determine listening ports for incoming connections which can be
#   customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
#   directories contain particular configuration snippets which manage modules,
#   global configuration fragments, or virtual host configurations,
#   respectively.
#
#   They are activated by symlinking available configuration files from their
#   respective *-available/ counterparts. These should be managed by using our
#   helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
#   their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
#   the default configuration, apache2 needs to be started/stopped with
#   /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
#   work with the default configuration.


# Global configuration
#

#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE!  If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"

#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
#Mutex file:${APACHE_LOCK_DIR} default

#
# The directory where shm and other runtime files will be stored.
#

DefaultRuntimeDir ${APACHE_RUN_DIR}

#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}

#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On

#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 100

#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5


# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off

# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here.  If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log

#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn

# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf

# Include list of ports to listen on
Include ports.conf


# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
        Options FollowSymLinks
        AllowOverride None
        Require all denied
</Directory>

<Directory /usr/share>
        AllowOverride None
        Require all granted
</Directory>

<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>

#<Directory /srv/>
#       Options Indexes FollowSymLinks
#       AllowOverride None
#       Require all granted
#</Directory>




# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives.  See also the AllowOverride
# directive.
#
AccessFileName .htaccess

#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^\.ht">
        Require all denied
</FilesMatch>


#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.

# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf

# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Let's try to find the index page of the default web site. From the config file above, we can see where to look for website content:

$ ls /etc/apache2/sites-
sites-available/ sites-enabled/   

$ ls /etc/apache2/sites-available/
000-default.conf  default-ssl.conf

$ ls /etc/apache2/sites-enabled/
000-default.conf

$ cat /etc/apache2/sites-enabled/000-default.conf 
<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

And now we can see where is index.html:

$ ls /var/www/html/
index.html



We can see the content of the index.html if we type in /var/www/html/index.html or http://localhost in the browser:


To check which processes are currently listening on which ports:

$ sudo lsof -i -P -n | grep LISTEN
...
apache2    1456                   root    4u  IPv6  31674      0t0  TCP *:80 (LISTEN)
apache2   10763        www-data    4u  IPv6  31674      0t0  TCP *:80 (LISTEN)
apache2   10764        www-data    4u  IPv6  31674      0t0  TCP *:80 (LISTEN)
apache2   10765        www-data    4u  IPv6  31674      0t0  TCP *:80 (LISTEN)
apache2   10766        www-data    4u  IPv6  31674      0t0  TCP *:80 (LISTEN)
apache2   10767        www-data    4u  IPv6  31674      0t0  TCP *:80 (LISTEN)
...


To check if Apache2 service is running:

$ sudo systemctl status apache2
[sudo] password for xxx: 
● apache2.service - The Apache HTTP Server
   Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/apache2.service.d
           └─apache2-systemd.conf
   Active: active (running) since Fri 2020-09-25 10:49:52 BST; 6 days ago
  Process: 4039 ExecReload=/usr/sbin/apachectl graceful (code=exited, status=0/SUCCESS)
 Main PID: 1456 (apache2)
    Tasks: 6 (limit: 4915)
   CGroup: /system.slice/apache2.service
           ├─1456 /usr/sbin/apache2 -k start
           ├─4043 /usr/sbin/apache2 -k start
           ├─4044 /usr/sbin/apache2 -k start
           ├─4045 /usr/sbin/apache2 -k start
           ├─4046 /usr/sbin/apache2 -k start
           └─4047 /usr/sbin/apache2 -k start

Sep 29 07:08:29 bobox systemd[1]: Reloaded The Apache HTTP Server.
Sep 30 00:08:52 bobox systemd[1]: Reloading The Apache HTTP Server.
Sep 30 00:08:52 bobox apachectl[17514]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the '
Sep 30 00:08:52 bobox systemd[1]: Reloaded The Apache HTTP Server.
Oct 01 00:06:42 bobox systemd[1]: Reloading The Apache HTTP Server.
Oct 01 00:06:42 bobox apachectl[12396]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the '
Oct 01 00:06:42 bobox systemd[1]: Reloaded The Apache HTTP Server.
Oct 02 00:06:29 bobox systemd[1]: Reloading The Apache HTTP Server.
Oct 02 00:06:29 bobox apachectl[4039]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'S
Oct 02 00:06:29 bobox systemd[1]: Reloaded The Apache HTTP Server.


How to check if Apache service is enabled at boot time?

$ sudo systemctl is-enabled apache2
enabled

How to disable Apache service at boot time:

$ sudo systemctl disable apache2
Synchronizing state of apache2.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable apache2

The previous command does not stop the service which is already running:

$ sudo lsof -i -P -n | grep LISTEN
...
apache2    1456            root    4u  IPv6   31674      0t0  TCP *:80 (LISTEN)
apache2    4043        www-data    4u  IPv6   31674      0t0  TCP *:80 (LISTEN)
apache2    4044        www-data    4u  IPv6   31674      0t0  TCP *:80 (LISTEN)
apache2    4045        www-data    4u  IPv6   31674      0t0  TCP *:80 (LISTEN)
apache2    4046        www-data    4u  IPv6   31674      0t0  TCP *:80 (LISTEN)
apache2    4047        www-data    4u  IPv6   31674      0t0  TCP *:80 (LISTEN)
...

To stop currently running Apache service:

$ sudo systemctl stop apache2

To verify that the service is stopped:

$ sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
   Loaded: loaded (/lib/systemd/system/apache2.service; disabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/apache2.service.d
           └─apache2-systemd.conf
   Active: inactive (dead)

Sep 30 00:08:52 bobox systemd[1]: Reloaded The Apache HTTP Server.
Oct 01 00:06:42 bobox systemd[1]: Reloading The Apache HTTP Server.
Oct 01 00:06:42 bobox apachectl[12396]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the '
Oct 01 00:06:42 bobox systemd[1]: Reloaded The Apache HTTP Server.
Oct 02 00:06:29 bobox systemd[1]: Reloading The Apache HTTP Server.
Oct 02 00:06:29 bobox apachectl[4039]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'S
Oct 02 00:06:29 bobox systemd[1]: Reloaded The Apache HTTP Server.
Oct 02 04:36:27 bobox systemd[1]: Stopping The Apache HTTP Server...
Oct 02 04:36:27 bobox apachectl[26754]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the '
Oct 02 04:36:27 bobox systemd[1]: Stopped The Apache HTTP Server.

We can also verify that it's not listening on any ports:

$ sudo lsof -i -P -n | grep LISTEN
// shows no apache2 entries