Can I make Apache only start once the system got its address from DHCP?

I am running Ubuntu in a VM for the purpose of having a local Wordpress installation, needed to do some local testing.

To this end I configured this machine's networking mode in VirtualBox to bridged, configured my home router to always lease the same IP address (192.168.0.101) to the MAC address of this VM and configured Apache to listen on this address in etc/apache2/ports.conf:

Listen 192.168.0.101:80

<IfModule ssl_module>
        Listen 192.168.0.101:443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 192.168.0.101:443
</IfModule>

An unfortunate result of this is that Apache often refuses to start on system bootup:

m@m-VirtualBox:~$ sudo systemctl status apache2
[sudo] password for m: 
× apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Fri 2021-10-22 16:12:19 CEST; 28s ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 681 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
        CPU: 19ms

paź 22 16:12:19 m-VirtualBox systemd[1]: Starting The Apache HTTP Server...
paź 22 16:12:19 m-VirtualBox apachectl[701]: (99)Cannot assign requested address: AH00072: make_sock: could not bind to address 192.168.0.101:80
paź 22 16:12:19 m-VirtualBox apachectl[701]: no listening sockets available, shutting down
paź 22 16:12:19 m-VirtualBox apachectl[701]: AH00015: Unable to open logs
paź 22 16:12:19 m-VirtualBox apachectl[681]: Action 'start' failed.
paź 22 16:12:19 m-VirtualBox apachectl[681]: The Apache error log may have more information.
paź 22 16:12:19 m-VirtualBox systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
paź 22 16:12:19 m-VirtualBox systemd[1]: apache2.service: Failed with result 'exit-code'.
paź 22 16:12:19 m-VirtualBox systemd[1]: Failed to start The Apache HTTP Server.

I can always start Apache manually with sudo systemctl start apache2 and then Apache starts successfully.

Making Apache2 listen on 127.0.0.1 instead of 192.168.0.101 also makes Apache succesfully start on system bootup, without errors such as the one shown above.

Therefore I suspect that the problem may be that Apache tries to start before DHCP manages to finish its job. Apache tries to listen on 192.168.0.101, but the machine is not assigned this address yet, so Apache is refused and errors out.

To try to resolve this issue and check if my guess is right I'd like to somehow set apache to only start once the DHCP client is finished. Is this possible and how?


Solution 1:

The previous (sadly, now deleted) answer by a helpful user whose nick slipped my mind already was almost correct.

It suggested to amend the /lib/systemd/system/apache2.service file to make it depend on network-online.target instead of the default network.target or, better, to add a second file to /lib/systemd/system called my-apache2.service with this modification. As per the documentation this is the correct way to make sure that a service only starts when the network is really up.

While this works the problem here is that the contents of /lib are not supposed to be edited and /etc/systemd/system should be used for this purpose instead. (Yes, this answer I linked to deals with systems other than Ubuntu, but reading man 7 file-hierarchy and man 5 systemd.unit on Ubuntu shows the same thing).

The second problem is that, from my experience, trying to run Apache2 twice leads to problems.

To remedy both problems my answer previously recommended the creation of a conflicting service in /etc/systemd/system. However, this was overly complicated and failed to solve some of the above problems, namely it was not future proof: changes to the original .service file made by upstream authors would not automatically be incorporated into our new .service file.

The correct solution is to create a drop-in file that adds a new After dependency to the original apache2.service, as documented by man 5 systemd.unit. To do so one needs to enter the following command:

# systemctl edit apache2.service

(which is documented in man 1 systemctl)

...and when the editor opens one needs to enter the following contents between the ### Anything between here and the comment below... and ### Lines below this comment... lines:

[Unit]
After=network-online.target

And save the new file.

Note that as per man 5 systemd.unit this will not replace the original After dependencies of the service; rather, this will add a new dependency to the ones that are already present.

For reference, here are the original contents of /lib/systemd/system/apache2.service:

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=https://httpd.apache.org/docs/2.4/

[Service]
Type=forking
Environment=APACHE_STARTED_BY_SYSTEMD=true
ExecStart=/usr/sbin/apachectl start
ExecStop=/usr/sbin/apachectl graceful-stop
ExecReload=/usr/sbin/apachectl graceful
KillMode=mixed
PrivateTmp=true
Restart=on-abort

[Install]
WantedBy=multi-user.target

From now on Apache2 should no longer fail to start on system boot.