Setting up a basic web server

Peter Boy (pboy) Version F40,F41 Last review: 2025-01-xx
The recommended and fully supported Fedora Web server is Apache, named httpd in the distribution. It is a Fedora Server key functionality that is part of the services specified in the technical specification. This article is about setting up a basic server to serve simple html pages. Further articles build on this and describe additional deployment configurations.

You are in the Fedora Server documentation staging area!

These documents are not approved yet and may be incomplete and/or incorrect. Take everything here with a grain of salt! You would probably prefer to study the published documentation.

Status of this document: Work in progress (Jan 08, 2025).

The Fedora Web server httpd is basically an Apache web server. This document covers in detail especially the setup and maintenance of a simple service basically serving directly some html pages. A typical use scenario would be the Jamstack concept or a typical "one pager" web presentation (not to be confused with one page microservice application).

Further articles describe how httpd can be configured for other usage scenarios such as frontend for application servers, proxy for containers, integration of dynamic languages and other deployment options.

How it works

A Fedora Web Server installation stores the configuration in subdirectories of /etc/httpd. Only 2 subdirectories are relevant for the system administrator. The directory /etc/httpd/conf.d is the more important one and stores especially the configuration of the different web sites. This directory is where the system administrator works the most. The directory /etc/httpd/conf.modules.d contains the modules to be loaded dynamically and their configuration. Only very rarely does anything need to be changed here.

The data for the default web site (or "main" site) is by default located in /var/www, the html-files in its subdirectory html. Additional directories are provided for extended configurations, e.g. the cgi-bin subdirectory for storing (classic) CGI files.

This structure dates back to the early days of Linux systems, when the server hardware was capable to serve only one site (i.e. one Domain). As the hardware got more powerful, and became capable of serving more than one domain, "virtual servers" were added that provided additional domains – distinguished either by name (virtual named hosts) or by IP. This situation is still virulent in the term "main“ site or "main“ server.

All these distinctions have now been abandoned. Today, it is widespread for a server to host several domains as a matter of course. And it is now best practice to configure everything as a virtual host, even if a server only serves one domain.

One option is to use the /var/www/ directory to create domain-specific subdirectories and additional appropriate subdirectory within. The advantage of this procedure is that it uses many default httpd configurations, e.g. the SELinux labels. The disadvantage is that the default configuration of the distribution is modified. It is generally better to leave this untouched.

An alternative option, in many cases a better fit to FHS compliance is the /srv directory. Today you would have many Domains, which are served by one or more applications. According to the FHS, the /srv directory is the appropriate place for storing data. You create a domain-specific directory, e.g. example.com, and therein a htdocs subdirectory for static html files, a webapps subdirectory for your web applicaion, e.g Ruby on Rails, a mail subdirectory for a postfix/dovecot mail hub, etc.

In this guide we use the latter option. Therefore, we use directories like /srv/<DOMAINNAME>/ to store all data relevant to a domain, and /srv/<DOMAINMANE>/htdocs/ for static HTML pages. If you want to use the former option, you can replace /srv/ by /var/www/.

Manual Installation

  1. Prepare Storage

    Create a logical volume for either /war/www or /srv.

    Details TBD

  2. Install the Apache httpd web server.

    […]$ sudo dnf install httpd mod_ssl mod_md
    […]$ sudo firewall-cmd --add-service=https --permanent
    […]$ sudo firewall-cmd --add-service=http  --permanent
    […]$ sudo firewall-cmd --reload
  3. Start the web server and check the status

    […]$ sudo systemctl start httpd
    […]$ sudo systemctl status httpd

    The Web server should already answer to requests. Enter your server’s address into your browser’s address input field and Fedora test page should come up.

    Fedora test page

    This intermediate stwep is important as the server creates the default self-signed certificates.

    If everything works as expected, activate the automatic server start at boot up.

    […]$ sudo systemctl enable httpd
    Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
  4. Optional: If you intend to use httpd with different ports as 80 / 437 adjust the main config file and add a specific listen.conf file

    1. Replace the main config file

      […]$ sudo mv /etc/httpd/conf/httpd.conf{,.f41}
      […]$ sudo wget {ServerRepo} /etc/ httpd/conf/httpd.conf.mod
      […]$ sudo ln -s /etc/ httpd/conf/httpd.conf.mod /etc/ httpd/conf/httpd.conf
    2. Add a specific listener.conf file

      […]$ sudo wget {ServerRepo}/httpd/conf.d/listen.conf.add /etc/httpd/conf.d/listen.conf
    3. Adjust the added listen.conf file according to your requirements. In any case you may specify a server name to avoid warning message at startup

      […]$ sudo vim /etc/httpd/conf.d/listen.conf
      ...
      # Change this to Listen on a specific IP address, but note that if
      # httpd.service is enabled to run at boot time, the address may not be
      # available when the service starts.  See the httpd.service(8) man
      # page for more information.
      #
      #Listen 12.34.56.78:80
      Listen 80                          # <== Adjust if required
      
      # ServerName gives the name and port that the server uses to identify itself.
      # This can often be determined automatically, but we recommend you specify
      # it explicitly to prevent problems during startup.
      #
      # If your host doesn't have a registered DNS name, enter its IP address here.
      #
      #ServerName www.example.com:80
      ServerName myweb.mydomain.tld      # <== Add and Adjust anyway

Ansible assisted installation

TPD

Manually setting up a simple web site

  1. Ensure the necessary Domain Name entries are available

    […]$ sudo resolvectl query YOUR_DOMAIN_NAME(S)
  2. Setup the web site Document Root directory

    […]$ sudo mkdir -p  /var/www/SITE_SHORT_NAME/htdocs

    It you opt for thinly provisioned volumes use Cockpit to create the volume, format the filesystem and permanently mount it at the base location /srv/SITEMANE/. Cockpit performs all these steps, you just need to create the htdocs subdirectory.

    Alternatevly use the /srv directory and manage the SELinux labels

    […]$ sudo mkdir -p  /srv/SITE_SHORT_NAME/htdocs
    […]# semanage fcontext -a -t httpd_sys_content_t  -s system_u  "/srv/SITE_SHORT_NAME/htdocs(/.*)?"
    […]# restorecon -R -vF /srv/SITE_SHORT_NAME/htdocs
    Relabeled /srv/SITE_SHORT_NAME/htdocs from unconfined_u:object_r:var_t:s0 to system_u:object_r:httpd_sys_content_t:s0

    In any case, leave the document root (htdocs) empty for now.

  3. Configure a Virtual Host for the domain

    1. Copy the simple web site template

      cp /etc/http/conf.vhost.d/vhost-simple-html.template /etc/http(conf.vhost.d/[SITE_SHOFRT_NAME].vhost

      It is good practice to follow a systematic naming convention. In the example, we use the prefix "vhost" to clearly distinguish the domain virtual host configurations from other configurations.

    2. Adjust the configuration file

      […]$ sudo vi /etc/httpd/conf.d/[SITE_SHOFRT_NAME].vhost
      
      # Apache vhost configuration for a static html server.
      # It manages SSL connections including certificates.
      # Initially, a self-signed certificate is active.
      # Incoming http traffic is automatically redirected to https.
      # Version 2.1
      
      #==> To adjust in vi/vim copy and adjust to the vi command line:
      # : %s/SHORT_DESCR/real_short_descr/g    e.g. my-domain.org production server
      # : %s/FQN_NAME/your_domain/g            e.g. my-domain.org
      # : %s/BASE_NAME/your_shortname/g        e.g. my-domain
      # : %s/OPTIONAL_ALIAS/your_alias/g       e.g. www.my-domain.org
      # afterwards delete these lines
      
      # Certificates are managed by Apache md module.
      #==> To activate, remove the leading '#' character and comment out the
      # the default distribution provided certificates further down.
      #==> Adjust the mail address as appropriate!
      #MDContactEmail root@FQN_NAME
      #MDCertificateAgreement accepted
      #MDomain FQN_NAME
      
      <VirtualHost *:443>
      	# Secure virtual WEB host configuration for
      	# SHORT_DESCR
      
      	# The site can be accessed by https/ssl only. Without a valid certificate
      	# you have to use a self-signed certificate as a quick temporary fix.
      
      	ServerName      FQN_NAME
      	ServerAlias	OPTIONAL_ALIAS
      
          #==> Adjust the mail address as appropriate!
      	ServerAdmin     root@FQN_NAME
      
      	# ##########################################################################
      	# NOTE: We re-route everything from the insecure site to this secure site!
      	# ##########################################################################
      
      	# Optional: Ensure that all registered domain names are rewritten to the
      	# official base name
      	#RewriteEngine   On
      	#RewriteCond     %{HTTP_HOST}    !^FQN_NAME [NC]
      	#RewriteCond     %{HTTP_HOST}    !^$
      	#RewriteRule     ^(.*)$          https://FQN_NAME$1  [R=301,L]
      
      	# ====================================================================
      	# Certificates configuration
      	# ====================================================================
      	SSLEngine on
      	# We rely on Fedora's systemwide configuration of SSL security.
      
      	# By default, certificates are managed by Apache md module (see above)
      	# In this case, no certificates needs bo be configured here.
      	# Otherwise, insert proper certificate configuration.
      
      	# DEFAULT mod_ssl provided, needed for initial startup.
      	#==> Comment OUT when module md created a certificate or you use
      	# custom certificates.
      	SSLCertificateFile	/etc/pki/tls/certs/localhost.crt
      	SSLCertificateKeyFile	/etc/pki/tls/private/localhost.key
      
      	# LetsEncrypt certificates managed by certbot (NOT by module md!)
      	#SSLCertificateFile      /etc/letsencrypt/live/DOMAIN_NAME/cert.pem
      	#SSLCertificateKeyFile   /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem
      	#SSLCertificateChainFile /etc/letsencrypt/live/DOMAIN_NAME/chain.pem
      
      	# ===============================================================
      	# Directory Locations
      	# ===============================================================
      	DirectoryIndex	index.html
      	DocumentRoot	/srv/BASE_NAME/htdocs
      	# Specific to default 2.4 configuration:
      	# Enable access to server-specific base file location
      	<Directory "/srv/BASE_NAME">
      		AllowOverride None
      		# Allow open access:
      		Require all granted
      	</Directory>
      	# Further relax access to the default document root
      	<Directory "/srv/BASE_NAME/htdocs">
      		#
      		# Possible values for the Options directive are "None", "All",
      		# or any combination of:
      		#   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
      		#
      		# Note that "MultiViews" must be named *explicitly* --- "Options All"
      		# doesn't give it to you.
      		#
      		# The Options directive is both complicated and important.  Please see
      		# http://httpd.apache.org/docs/2.4/mod/core.html#options
      		# for more information.
      		#
      		Options Indexes FollowSymLinks
      
      		#
      		# AllowOverride controls what directives may be placed in .htaccess files.
      		# It can be "All", "None", or any combination of the keywords:
      		#   Options FileInfo AuthConfig Limit
      		#
      		AllowOverride None
      
      		#
      		# Controls who can get stuff from this server:
      		# Allow open access:
      		Require all granted
      
      	</Directory>
      
      	# ===============================================================
      	# Optional: Protect access to start page (and subsequent pages)
      	#==>        Ensure you created the additional auth.d directory
      	#           including SELinux labels
      	# ===============================================================
      	#<Location />
      	#	AuthType Basic
      	#	AuthName "Access start page"
      	#	AuthUserFile /srv/BASE_NAME/auth.d/htuser
      	#	Require valid-user
      	#</Location>
      
      	# ===============================================================
      	# Optional: Configure webDAV access
      	#==>        Ensure you created the additional davlock directory
      	#           including SELinux labels
      	# ===============================================================
      	#DavLockDB /srv/SERVER_SHORT_NAME/davlock/dav_lock_db
      
      	#<Location /dav>
      	#	DAV On
      	#	ForceType text/plain
      
      	#	Order Allow,Deny
      	#	Allow from all
      	#	Options all
      	#	DirectoryIndex none
      
      		# Optional: Protect basic dav page (and all subsequent page)
      		#AuthType Basic
      		#AuthName "Application Server WebDAV access"
      		#AuthUserFile /srv/SERVER_SHORT_NAME/auth.d/htdavuser
      		#Require valid-user
      	#</Location>
      
      	# ===============================================================
      	# Logging configuration
      	# ===============================================================
      	# Use separate log files for the SSL virtual host; note that LogLevel
      	# is not inherited from httpd.conf.
      	# NOTE: fail2ban searches for ~/logs/*access_log and  ~/logs/*error_log
      	#       to access log files to watch and analyze!
      	ErrorLog        logs/BASE_NAME-ssl_error_log
      	CustomLog       logs/BASE_NAME-ssl_access_log combined
      	LogLevel warn
      
      </VirtualHost>
      
      <VirtualHost *:80>
      	# INSECURE virtual WEB host configuration for
      	# SHORT_DESCR
      
      	# NOTE: Everything from the insecure port 80 is redirected to this instance'
      	#       SECURE site
      
      	ServerName      FQN_NAME
      	ServerAlias	OPTIONAL_ALIAS
      
      	ServerAdmin     root@FQN_NAME
      
      	# ##########################################################################
      	# NOTE: We re-route everything to the secure site!
      	#       We retain all aliase names for now.
      	#       There is no need for an exception for Let's Encrypt anymore.
      	#       Version 2.x can deal with self-signed certificates and https
      	# ##########################################################################
      	RewriteEngine   On
      	RewriteRule	(.*)	https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
      
      	# ===============================================================
      	# Logging configuration
      	# ===============================================================
      	# Use separate log files for the SSL virtual host; note that LogLevel
      	# is not inherited from httpd.conf.
      	# NOTE: fail2ban searches for ~/logs/*access_log and  ~/logs/*error_log
      	#       to access log files to watch and analyze!
      	ErrorLog        logs/BASE_NAME-error_log
      	CustomLog       logs/BASE_NAME-access_log combined
      
      </VirtualHost>
  4. Restart and check the web server

    […]# systemctl  restart  httpd
    […]# systemctl  status  httpd
    ● httpd.service - The Apache HTTP Server
         Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
         Active: active (running) since ...
      ...
      ...
  5. Test the configuration

    Again, enter your server’s address into your browser’s address input field. Because we already re-route everything to the secure site which uses a self-signed certificate so far, you get a warning message. Select "Advanced" and accept the 'risk' here. You’ll see the provisional test page.

  6. [ ] Final commissioning

    Delete the the provisional index.html file and fill your Web content into the Document Root  ~/SITE_SHORT_NAME/htdocs/.

Ansible assisted setting up a simple web site

+ TBD