In the path to have a #RaspberryPi serving a blog, one classic step is to install an #Apache2 web server. In this post I describe the process including permissions, modules and virtual host setup.


  1. Requirements & Assumptions

  2. Install Apache2

  3. Adjust permissions

  4. Apache2 modules

  5. Add a Virtual Host

  6. Wrapping up

1. Requirements & Assumptions

  • A Raspberry Pi up and running, following my previous article Spawning a Raspberry Pi 4 with Raspberry Pi OS. It is also up to date by following the recent article Upgrade Raspberry Pi OS from 11 Bullseye to 12 Bookworm.

  • What is the goal for it? Usually it servers webpages, sometimes you want to support PHP or it can also work as a Reverse Proxy. Apache2 offers a set of modules that you need to install separately depending on your goal. This article will cover a general installation to serve webpages.

  • The host uses a local DNS server as explained in Quick DNS server on a Raspberry Pi and that's why you won't see IP addresses here.

  • The hostname is alderaan and the linux user is xavi. You may want to change them for your IP address and your own username.

2. Install Apache2

  1. Update your system so that the package list is up to date.

    sudo apt-get update
    sudo apt-get upgrade
  2. Install Apache2

    sudo apt install apache2 -y

At this point we should end up with a basic installation of Apache2. Our system si able to serve webpages and is in fact serving under http://alderaan.

You can execute the following command to know the IP of this host:

hostname -I

and it should tell the IPv4 and IPv6. The IPv4 can be placed directly in the browser and then should appear the default Apache2 site.


3. Adjust permissions

The current state of the system is the following:

  • We are meant to have our virtual host directiories (the sites we want to serve) under /var/www. This is of course not mandatory but having all of them centered under a directory easies our administration of the server.

  • We have the default site already set up by the installation under /var/www/html

  • After the installation, the whole /var/www directory and subdirectories and files inside belong to root, which is not ideal. First, because Apache has defined a default user www-data and group www-data to use for the files of the sites and second because you don't want to have to use sudo every time you edit a file.

  • We're logged as a normal user (xavi as mentioned above, or pi in the default installation) and most likely this is the user that most of the aplications in the system will run (say Python projects, files copied up and down,...)

So here we have 2 main routes we can go towards having a proper user/group/permissions set up:

  1. The default one: We add ourselves (xavi) into the Apache's default group and make all files there inside belonging to the Apache's default user and group.

    1. Pros: You have more security (one user for one purpose) and also all documentations refer to this solution, so it may be easier for you to move on.

    2. Cons: Everytime you add a file or a directory there you need to change the ownership to the www-data user or group. At least, you need to set up permissions for every application that interact with these files. If you have processes from a different aplication running under a different user, you most likely will fall into permission issues when writing or reading from Apache. It's quite a headache.

  2. The custom one: We can make Apache to use OUR user when behaving with the files in the virtual hosts, so all files that are created and edited belong to the same user of the rest of aplications.

    1. Pros: Easier maintenance, all files belong to the same user / group, we rarely enter into issues between aplications accessing the same files

    2. Cons: This is an obvious security hole, as once an attacker gains access to the user, it can access the whole system. This is of course not that easy and still this is not the root user, but the consideration needs to be said.

So, at this point, you have to choose which option you take. Each option will be setup in one of the following sections:

3.1. Default permission system: Apache user & group

We want to be able to behave with the files in the /var/www/html and in general the files that Apache manages.

Apache uses the user www-data and the group www-data for the files in the published directories, so we need to add our user into that group:

  1. Add our xavi user to the www-data default group

    sudo usermod -a -G www-data xavi
  2. Make the whole /var/www to belong to the www-data user

    sudo chown -R -f www-data:www-data /var/www
  3. Logout and log in to the system again to let the changes to take effect on you

3.2. Custom permission system: Our user & group

The Raspberry Pi is also a nice toy to play around. One may have a Python script that generates files than then are published in an Apache so a CRUD app edits them and then go back to another app. On the way we need to work on the permissions system, or simply make the applications to work with the same user. At the end of the daty, this is sometimes just a toy and besides making everything as root, we can also easy our life a bit.

What we'll do here is to set up Apache so that the files in the Virtual Hosts are owned by the same overall non-root user xavi.

  1. Edit the file that contain the definition of the user and group to use

    sudo nano /etc/apache2/envvars
  2. Find the following lines

    export APACHE_RUN_USER=www-data
    export APACHE_RUN_GROUP=www-data
  3. Change the user and group www-data to the desired one (xavi in my case)

    export APACHE_RUN_USER=xavi
    export APACHE_RUN_GROUP=xavi
  4. Save (ctrl + o) and exit (ctrl + x)

  5. Make the whole /var/www to belong to the xavi user

    sudo chown -R -f xavi:xavi /var/www
  6. Restart the Apache2

    sudo service apache2 restart

4. Apache2 modules

Depending on the project you manage, you'd need a set of modules to be installed. Modules extend the functionality of our web server.

4.1. Which modules do we have already installed?

First of all, here is a command to see which Apache2 modules we already have activated:

apache2ctl -M

it should output something like the following:

Loaded Modules:
 core_module (static)
 so_module (static)
 watchdog_module (static)
 http_module (static)
 log_config_module (static)
 logio_module (static)
 version_module (static)
 unixd_module (static)
 access_compat_module (shared)
 alias_module (shared)
 auth_basic_module (shared)
 authn_core_module (shared)
 authn_file_module (shared)
 authz_core_module (shared)
 authz_host_module (shared)
 authz_user_module (shared)
 autoindex_module (shared)
 deflate_module (shared)
 dir_module (shared)
 env_module (shared)
 filter_module (shared)
 mime_module (shared)
 mpm_event_module (shared)
 negotiation_module (shared)
 reqtimeout_module (shared)
 setenvif_module (shared)
 status_module (shared)

4.2. Activate an Apache2 module

Now let's activate a module. I'll use mod_rewrite as an example.

  1. Activate the module mod_rewrite

    sudo a2enmod rewrite
  2. Restart Apache2 so the changes take effect

    sudo service apache2 restart

5. Add a Virtual Host

Virtual Hosts are the way to define sites in Apache2. This section is just to show how we should continue with our Apache2 setup so that we can serve content, but of course it's very minimal and just as an example.

ℹ️ We assume here that:

  • Our Raspberry Pi is connected to the internet and therefore, there is a public IP that we know or at least a Dynamic DNS set up.

  • We have a domain called and a subdomain there that is already set up to forward the traffic to the public IP of our Raspberry Pi o at least to the set up Dynamic DNS

  • Our router is also set up to forward the traffic incoming from the port 80 to the Raspberry PI internal IP address.

To add a new Virtual Host we need:

  • A directory that contains the site. Ideally inside the /var/www so we can maintain it easily, and can contain simply an index.html

  • A new Virtual Host file enabled in Apache2.

For the first point, you most likely have a fancy webpage to publish. Just for the purposes of this article:

  1. Create a directory for the site inside the /var/www directory

    mkdir /var/www/my_app
  2. Create and edit an index.html file in the recently created directory

    nano /var/www/my_app/index.html
  3. Add an example content to the file so we can see the Virtual Host working

          <title>It works!</title>
          <h1>This Virtual Host works!</h1>
  4. Save (ctrl + o) and exit (ctrl + x)

  5. Ensure that the directory and the content have the right permissions. Refer to the section 3 above to know if you need to chown / chmod to it.

For the second point, and now that we have any example content to serve, let's create a new Virtual Host file for it.

  1. Create a new Virtual Host file where all Virtual Host file should live

    sudo nano /etc/apache2/sites-available/my_app.conf
  2. Add the basic content for the Virtual Host file

    <VirtualHost *:80>
        DocumentRoot /var/www/my_app
        ErrorLog ${APACHE_LOG_DIR}/my_app_error.log
        CustomLog ${APACHE_LOG_DIR}/my_app_access.log combined

    Of course, these are just some of the parameters that we can set up here. You have plenty of examples in the official Apache documentation or simply search the net.

    Still, what we have here means:

    • VirtualHost *:80: Apache should listen any IP address coming throught the port 80.

    • ServerName: The request asking for the domain defined by this directive will be handled by this VirtualHost

    • ServerAlias: This is an alias, meaning that the request can be asking for this domain / subdomain too

    • DocumentRoot: Where is the directory containing the content to serve.

    • ErrorLog: Errors for this Virtual Host will be registered in the defined log file

    • CustomLog: Accesses (requests) to this Virtual Host will be registered in the defined log file.

  3. Save (ctrl + o) and exit (ctrl + x)

  4. Activate this site

    There are 2 ways to activate the site that we just created in Sites Available. Just choose one 😉

    • Make use of the apache tool
    sudo a2ensite my_app.conf
    • Manually link the enabled site from the available sites
    sudo ln -s /etc/apache2/sites-available/my_app.conf /etc/apache2/sites-enabled/my_app.conf
  5. Restart Apache2 so the changes take effect

    sudo service apache2 restart

At this point we have our host set up and ready to receive requests. Recalling that we have all the DNS and router stuff already done (that is, the domains pointing to our machine and the router also set up), we should be able to visit in a browser and see our content 😊

6. Wrapping up

Setting up an Apache2 web server is not really complicated. There is this point to take care about permissions that can become a headache, and the set up of a Virtual Host is something that has a whole world behind.

And talking about modules, we'll most likely want to install PHP or any other scripting language support so that we can do fancy things. Stay tuned, another article is in the oven!

Previous Post Next Post