7

What I want to do?

I'm trying to make nginx load configurations from /vagrant mounted by vagrant automatically.

So I edited nginx.service to make it boot after shared folder mounted, but it not works.

Certainly nginx has been booted after virtualbox-guest-utils.service, however, it seems to be booted before vagrant.mount (/vagrant). Because nginx couldn't load configurations from /vagrant and it works after running command systemctl restart nginx.service manually.

How to run .service unit after auto generated .mount unit started?

Environment

  • Vagrant 1.8.1
  • Ubuntu Server 15.10 (ubuntu/wily64)
  • VirtualBox 5.0.14

systemctl cat nginx.service

Pattern 1 : Not work

# /lib/systemd/system/nginx.service
# Stop dance for nginx
# =======================
#
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
# and sends SIGTERM (fast shutdown) to the main process.
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
#
# nginx signals reference doc:
# http://nginx.org/en/docs/control.html
#
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/nginx.service.d/override.conf
[Unit]
Requires=virtualbox-guest-utils.service vagrant.mount
After=virtualbox-guest-utils.service vagrant.mount

Pattern 2 : Not work

# /lib/systemd/system/nginx.service
# Stop dance for nginx
# =======================
#
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
# and sends SIGTERM (fast shutdown) to the main process.
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
#
# nginx signals reference doc:
# http://nginx.org/en/docs/control.html
#
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/nginx.service.d/override.conf
[Unit]
RequiresMountsFor=/vagrant

5 Answers5

8

Using the mount.target unit seems to work.

Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/wily64"
  config.vm.provision :shell, path: "bootstrap.sh"

  # Disabling mounting of the /vagrant directory to make sure ngnix is blocked
  # Comment this out to allow the shared folder
  config.vm.synced_folder ".", "/vagrant", disabled: true
end

bootstrap.sh:

#!/usr/bin/env bash

apt-get update
apt-get install -y nginx

# Make vagrant.mount loosely dependent on nginx.service
sed -i 's/WantedBy=multi-user.target/WantedBy=vagrant.mount/' /lib/systemd/system/nginx.service
systemctl daemon-reload

# Update service symlinks
systemctl disable nginx.service
systemctl enable nginx.service

Test this by running vagrant reload to cause the VM to boot without the /vagrant directory mounted. Log into the VM and see that nginx isn't running:

vagrant@vagrant-ubuntu-wily-64:~$ sudo systemctl status nginx.service 
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: inactive (dead)

Then comment out the Vagrantfile line that disables the shared folder and vagrant reload again. Log into the VM again and see that nginx is running:

vagrant@vagrant-ubuntu-wily-64:~$ systemctl status nginx.service 
● nginx.service - A high performance web server and a reverse proxy server
  Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
  Active: active (running) since Mon 2016-07-25 04:28:00 UTC; 42s ago
 Process: 1152 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Process: 1146 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 1156 (nginx)
  Memory: 7.4M
     CPU: 17ms
  CGroup: /system.slice/nginx.service
          ├─1156 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
      └─1157 nginx: worker process
Jacob Wan
  • 2,521
  • 25
  • 19
  • I have tested this and can confirm that this is the correct answer. When you have `WantedBy=vagrant.mount` in the `[Install]` section and then **disable** and **enable** the service it will start properly on the next boot. – Thomas Sep 22 '16 at 07:05
  • You don't need to disable the NFS mount first. Otherwise, this should be the accepted answer. No "hack" needed. – dohpaz42 Mar 25 '17 at 04:13
  • 1
    Works for me, too. Semantically, it does feel like a hack, as the `WantedBy` dependency relationship is the wrong way around. I tried various other solutions though (`Requires`, `RequiresMountsFor`, `After`, and combinations of those), but none of them work, since systemd ignores dependencies that do not exist (yet), as indicated by log messages like "Cannot add dependency job for unit xxx.service, ignoring: Unit vagrant.mount failed to load: No such file or directory". – d0gb3r7 Jul 16 '17 at 12:04
  • 1
    DO NOT edit the `nginx.service` file in `/lib/systemd/system` while this file can be overwritten by an package update. Make a copy of the file to `etc/systemd/system` instead and make your edits there. This path is meant for admin purposes. And all `systemd` units located there are loaded with a higher priority. Further be aware, that the name `vagrant.mount` depends on the path mounted. If you mount `vagrant/somefolder` your mount is named `vagrant-somefolder.mount`. – codekandis May 04 '18 at 08:26
  • This might make them come up in parallel which...might be close enough but feels odd...see also https://stackoverflow.com/questions/43001223/how-to-ensure-that-there-is-a-delay-before-a-service-is-started-in-systemd – rogerdpack Jan 22 '21 at 00:45
2

edit /lib/systemd/system/nginx.service and change WantedBy directive under Install section...

WantedBy=vagrant.mount

You can check if the vagrant.mount event exists via: systemctl list-units vagrant.mount. You should see this:

UNIT          LOAD   ACTIVE SUB     DESCRIPTION
vagrant.mount loaded active mounted /vagrant

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

1 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
vigo
  • 298
  • 3
  • 8
  • 2
    DO NOT edit the `nginx.service` file in `/lib/systemd/system` while this file can be overwritten by an package update. Make a copy of the file to `etc/systemd/system` instead and make your edits there. This path is meant for admin purposes. And all `systemd` units located there are loaded with a higher priority. Further be aware, that the name `vagrant.mount` depends on the path mounted. If you mount `vagrant/somefolder` your mount is named `vagrant-somefolder.mount`. – codekandis May 04 '18 at 08:28
  • Totally agree with this comment, altering this file is a big no no in the same way you wouldn't jump into c:\windows\system32.. and edit something (showing my age?) – John Hunt Jan 31 '19 at 14:17
2

Summarization previous answers and comments in terms of Ansible (if used for provision):

- name: Copy Nginx Systemd unit to /etc/
  copy:
    src: /lib/systemd/system/nginx.service
    dest: /etc/systemd/system/nginx.service
    remote_src: yes

- name: Change Nginx Systemd unit
  lineinfile:
    path: /etc/systemd/system/nginx.service
    regexp: '^WantedBy='
    line: 'WantedBy={{ vagrant_mount_unit }}'
    state: present

- name: Systemd daemon reload
  systemd:
    daemon_reload: yes

- name: Disable Nginx
  service:
    name: nginx
    enabled: no

- name: Enable Nginx
  service:
    name: nginx
    enabled: yes

Replace {{ vagrant_mount_unit }} by Vagrant mount unit name. It depends from mount point, e.g. if mount point is /home/vagrant/app, unit name would be home-vagrant-app.mount.

agarb7
  • 21
  • 2
1

I wrote a post how I'm using udev event to restart nginx and php5-fpm.

In short I'm adding /etc/udev/rules.d/50-vagrant-mount.rules with rule:

SUBSYSTEM=="bdi",ACTION=="add",RUN+="/bin/bash /root/.udev-mount-restart-services.sh"

And the script /root/.udev-mount-restart-services.sh is:

sleep 5 # wait for a bit for NFS to make sure resources are available
systemctl restart php5-fpm > /dev/null 2>&1
systemctl restart nginx > /dev/null 2>&1
Rafał Malinowski
  • 1,126
  • 1
  • 7
  • 8
1

I wanted to drop my own answer here as it did seem each answer has parts of a correct answer and some details can be found in comments only.

In this example I have 2 file system mounts in /var/www/mymount1 and /var/www/mymount2

This part of my Vagrantfile:

config.vm.provision "shell", path: "docs/vagrant/init-vagrant.sh"
config.vm.synced_folder "mymount1", "/var/www/mymount1", type: "nfs"
config.vm.synced_folder "mymount2", "/var/www/mymount2", type: "nfs"

I am placing the script below in /docs/vagrant/init-vagrant.sh as its my provisioner file.

# Copy nginx systemd script and make edits in /etc/systemd/system, as updates might change the original in /lib/systemd/system/nginx.service
cp /lib/systemd/system/nginx.service /etc/systemd/system/
# These tell that nginx should not be started before file system mounts are available
echo WantedBy=var-www-mymount1.mount >> /etc/systemd/system/nginx.service
echo WantedBy=var-www-mymount2.mount >> /etc/systemd/system/nginx.service

# Update service symlinks
systemctl daemon-reload
systemctl disable nginx.service
systemctl enable nginx.service
Firze
  • 3,939
  • 6
  • 48
  • 61