Debian example

The example describes a module that packages a Spring Boot web application that is started at boot time using systemd and has a config directory in /etc.

The app needs to run as a non privileged user which is created using a preinstall script.

The non priviledged user should be granted the privilege to write to the application log folder.

Folder structure

  pom.xml
  +--- src/main/resources/deb/
      +--- DEBIAN/
      |   +--- preinst
      +--- etc/hiapp/
      |   +--- hiapp.properties
      +--- lib/systemd/system
          +--- hiapp.service

The src/main/resources/deb folder is the starting point for the file system resources. The DEBIAN subfolder contains the Debian control files, in this example only preinst is used, other possible files are postinst, prerm, postrm, ...

The other folders and files are considered to be data files, in this example the systemd script hiapp.service and it's parent folders become data archive members using the default username and groupname. The permissions for these files and folders are the default file and folder mode respectively.

The files in the /etc/hiapp folder are marked as config file and are read only for members of the application's group.

Pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>be.hobbiton.app</groupId>
        <artifactId>hiapp</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <packaging>deb</packaging>
        <name>Cloud hi server</name>
        <description>Cloud hi server - Non Secure Implementation</description>

        <developers>
                <developer>
                        <name>Sam</name>
                        <email>sam@hobbiton.be</email>
                </developer>
        </developers>
...

The use of deb as the packaging type is significant.

...
        <dependencies>
                <dependency>
                        <groupId>be.hobbiton.app</groupId>
                        <artifactId>hiapp-web</artifactId>
                        <type>jar</type>
                        <version>${project.version}</version>
                </dependency>
        </dependencies>
...

If we want to package an artifact we have to declare it as a dependency, hiapp-web is our Spring Boot web app.

...
        <build>
                <plugins>
                        <plugin>
                                <groupId>be.hobbiton.maven</groupId>
                                <artifactId>linux-packaging-maven-plugin</artifactId>
                                <extensions>true</extensions>
...

Extensions should be enabled for the plugin to kick in. Without it, the deb type lifecycle would not be picked up by maven.

...
                                <configuration>
                                        <artifacts>
                                                <artifact>
                                                        <groupId>be.hobbiton.app</groupId>
                                                        <artifactId>hiapp-web</artifactId>
                                                        <destination>/opt/hiapp/hiapp.jar</destination>
                                                </artifact>
                                        </artifacts>
...

The hiapp-web artifact is installed in the /opt/hiapp/ folder with hiapp.jar as it's file name.

...
                                        <folders>
                                                <folder>
                                                        <path>/var/log/hiapp</path>
                                                        <username>hiapp</username>
                                                </folder>
                                        </folders>
...

The /var/log/hiapp folder owned by the hiapp user must be created by the package.

...
                                        <attributes>
                                                <attribute>
                                                        <expression>/etc/hiapp/*</expression>
                                                        <groupname>hiapp</groupname>
                                                        <mode>0640</mode>
                                                        <config>true</config>
                                                </attribute>
                                        </attributes>
...

The files in the /etc/hiapp folder are marked as config file and are read only for members of the application's group, the default user (root) has read-write permissions.

...
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

Result

The resulting Debian package:

$ mvn be.hobbiton.maven:linux-packaging-maven-plugin:info -Dfile=target/hiapp-1.0.0-SNAPSHOT.deb
Package: hiapp
Version: 1.0.0-20151019011349
Architecture: all
Maintainer: Sam <sam@hobbiton.be>
Installed-Size: 380
Description: Cloud hi server
 Cloud hi server - Non Secure Implementation

Control files:
conffiles
control
preinst

Configuration files:
/etc/hiapp/hiapp.properties

Data files:
drwxr-xr-x     root/root         0 ./etc/
drwxr-xr-x     root/root         0 ./etc/hiapp/
-rw-r-----     root/hiapp       52 ./etc/hiapp/hiapp.properties
drwxr-xr-x     root/root         0 ./lib
drwxr-xr-x     root/root         0 ./lib/systemd
drwxr-xr-x     root/root         0 ./lib/systemd/system
-rw-r--r--     root/root       421 ./lib/systemd/system/hiapp.service
drwxr-xr-x     root/root         0 ./opt/
drwxr-xr-x     root/root         0 ./opt/hiapp/
-rw-r--r--     root/root    378787 ./opt/hiapp/hiapp.jar
drwxr-xr-x     root/root         0 ./var/
drwxr-xr-x     root/root         0 ./var/log/
drwxr-xr-x    hiapp/root         0 ./var/log/hiapp/

The fields in the package are derived from the standard pom field where sensible.

The usernames, groups and permissions are all defaults except for the username of the owner of the /var/log/hiapp folder and the group name of the /etc/hiapp/hiapp.properties file.

preinst

The preinst Debain maintainer script that creates the hiapp user contains:

#!/bin/sh
set -e

USER='hiapp'
HOMEDIR='/opt/hiapp'

case "$1" in
  install)

  # Add user if it doesn't already exists
  if ! getent passwd ${USER} >/dev/null 2>&1
  then
    useradd --system --user-group --home-dir ${HOMEDIR} --shell /sbin/nologin ${USER}
  fi
esac

exit 0

systemd service file

The systemd service file example:

[Unit]
Description=Say Hi server

[Service]
ExecStart=java -jar /opt/hiapp/hiapp.jar
User=hiapp
TimeoutSec=120
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target