Skip to content

Commit

Permalink
Merge pull request #184 from sbs20/staging
Browse files Browse the repository at this point in the history
Installer; Non privileged docker; Localisation (fr)
  • Loading branch information
sbs20 authored Apr 12, 2021
2 parents 4f6b1e9 + 01aa6b4 commit 6a47fa6
Show file tree
Hide file tree
Showing 13 changed files with 530 additions and 247 deletions.
39 changes: 22 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,32 @@ RUN apt-get update \
tesseract-ocr \
&& sed -i 's/policy domain="coder" rights="none" pattern="PDF"/policy domain="coder" rights="read | write" pattern="PDF"'/ /etc/ImageMagick-6/policy.xml

COPY --from=builder "$APP_DIR/dist" "$APP_DIR/"

RUN npm install --production

# This goes into /etc/sane.d/net.conf
ENV SANED_NET_HOSTS=""

# This gets added to /etc/sane.d/airscan.conf
ENV AIRSCAN_DEVICES=""

# This directs scanserv not to bother querying `scanimage -L`
ENV SCANIMAGE_LIST_IGNORE=""
# Create a known user
RUN useradd -u 2001 -ms /bin/bash scanservjs

# This gets added to scanservjs/server/config.js:devices
ENV DEVICES=""

# Override OCR language
ENV OCR_LANG=""
ENV \
# This goes into /etc/sane.d/net.conf
SANED_NET_HOSTS="" \
# This gets added to /etc/sane.d/airscan.conf
AIRSCAN_DEVICES="" \
# This directs scanserv not to bother querying `scanimage -L`
SCANIMAGE_LIST_IGNORE="" \
# This gets added to scanservjs/server/config.js:devices
DEVICES="" \
# Override OCR language
OCR_LANG=""

# Copy entry point
COPY run.sh /run.sh
RUN ["chmod", "+x", "/run.sh"]
ENTRYPOINT [ "/run.sh" ]

# Copy the code and install
COPY --from=builder "$APP_DIR/dist" "$APP_DIR/"
RUN npm install --production

# Change the ownership of config and data since we need to write there
RUN chown -R scanservjs:scanservjs config data /etc/sane.d/net.conf /etc/sane.d/airscan.conf
USER scanservjs

EXPOSE 8080
103 changes: 9 additions & 94 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ complicated installation.
* Configurable overrides for all defaults as well as filters and formats
* Multipage scanning (with collation for double sided scans)
* Light and dark mode
* **NEW**: International translations: Czech, German, Italian, Spanish (**help
requested**)
* **NEW**: International translations: Czech, French, German, Italian, Mandarin,
Spanish (**help requested**)

It supports any
[SANE compatible devices](http://www.sane-project.org/sane-supported-devices.html).
Expand All @@ -43,74 +43,18 @@ Copyright 2016-2021 [Sam Strachan](https://github.com/sbs20)
* Linux host (or VM with necessary pass-through e.g. USB)
* Software sane-utils, ImageMagick, Tesseract (optional) and nodejs

## Installation notes
For an easy docker-based install (assuming that SANE supports your scanner
out-of-the-box on Debian) use the following commands:
## Installation

```console
docker pull sbs20/scanservjs:latest
docker rm --force scanservjs-container 2> /dev/null
docker run -d -p 8080:8080 -v /var/run/dbus:/var/run/dbus --restart unless-stopped --name scanservjs-container --privileged sbs20/scanservjs:latest
```

scanservjs will now be accessible from `http://$host:8080/`

* ⚠ By default, configuration and scanned images are stored within the container
and will be lost if you recreate it. If you want to map your scanned images
then specify the volume mapping option `-v /local/path/:/app/data/output/`
* ⚠ The docker image is amd64 only - and will not work on ARM devices such as
the Raspberry Pi. Please follow the manual installation process in these
cases
*`--privileged` is required for the container to access the host's devices,
to allow it to talk to the scanner. The best way to do this is to map the
actual USB ports. Run `sudo sane-find-scanner -q` and you will get a result
like
`found USB scanner (vendor=0x04a9 [Canon], product=0x220d [CanoScan], chip=LM9832/3) at libusb:001:003`.
This translates to `/dev/bus/usb/001/003`. In turn the docker argument would
be `--device=/dev/bus/usb/001/003:/dev/bus/usb/001/003`. However, oftentimes,
there are [reports](#66) that devices change address across reboots which
complicates matters.
* ⚠ Driverless-mode scanning (using airscan over IPP-USB) seems to result in
problems. If anyone has ideas why (perhaps something additional needs sharing
from host to guest) then suggestions are welcome. What seems to work well as
an alternative is
[network-sharing the scanner](https://github.com/sbs20/scanservjs/issues/129#issuecomment-800226184)
on the host and referencing that within the guest.

If you want to install the latest staging branch (this may contain newer code)

```console
docker pull sbs20/scanservjs:staging
docker rm --force scanservjs-container 2> /dev/null
docker run -d -p 8080:8080 -v /var/run/dbus:/var/run/dbus --restart unless-stopped --name scanservjs-container --privileged sbs20/scanservjs:staging
```

More installation options:

* [Manual installation notes](docs/install.md)
* [Manual installation](docs/install.md)
* [Docker installation](docs/docker.md)
* [Development notes](docs/development.md)
* [Configuring the scanner and SANE](docs/sane.md)

## Environment variables

* `SANED_NET_HOSTS`: If you want to use a
[SaneOverNetwork](https://wiki.debian.org/SaneOverNetwork#Server_Configuration)
scanner then to perform the equivalent of adding hosts to
`/etc/sane.d/net.conf` specify a list of ip addresses separated by semicolons
in the `SANED_NET_HOSTS` environment variable.
* `AIRSCAN_DEVICES`: If you want to specifically add `sane-airscan` devices to
your `/etc/sane.d/airscan.conf` then use the `AIRSCAN_DEVICES` environment
variable (semicolon delimited).
* `DELIMITER`: if you need to inlcude semi-colons (`;`) in your environment
variables, this allows you to choose an alternative delimiter.
* `DEVICES`: Force add devices use `DEVICES` (semicolon delimited)
* `SCANIMAGE_LIST_IGNORE`: To force ignore `scanimage -L`

## Configuration and device override
If you want to override some specific configuration setting then you can do so
within `./config/config.local.js`. Take a copy of `./config/config.default.js`
and override the sections you want. Using docker you will need to map the volume
using `-v /my/local/path/:/app/config/` then create a file in your directory
using `-v /my/local/path:/app/config` then create a file in your directory
called `config.local.js`. See [example source](./server/config/config.local.js)
for more options.

Expand Down Expand Up @@ -155,38 +99,6 @@ module.exports = {
};
```

## Airscan
[sane-airscan](https://github.com/alexpevzner/sane-airscan) uses Avahi /
Zeroconf / Bonjour to discover devices on the local network. If you are running
docker you will want to share dbus to make it work
(`-v /var/run/dbus:/var/run/dbus`).

## Example docker run

### Use airscan and a locally detected scanner
This should support most use cases

```console
docker run -d -p 8080:8080 \
-v /var/run/dbus:/var/run/dbus \
--name scanservjs-container --privileged scanservjs-image
```

### Complicated
Add two net hosts to sane, use airscan to connect to two remote scanners, don't
use `scanimage -L`, force a list of devices and override the OCR language

```console
docker run -d -p 8080:8080 \
-e SANED_NET_HOSTS="10.0.100.30;10.0.100.31" \
-e AIRSCAN_DEVICES='"Canon MFD" = "http://192.168.0.10/eSCL";"EPSON MFD" = "http://192.168.0.11/eSCL"' \
-e SCANIMAGE_LIST_IGNORE=true \
-e DEVICES="net:10.0.100.30:plustek:libusb:001:003;net:10.0.100.31:plustek:libusb:001:003;airscan:e0:Canon TR8500 series;airscan:e1:EPSON Cool Series" \
-e OCR_LANG="fra" \
-v /var/run/dbus:/var/run/dbus \
--name scanservjs-container --privileged scanservjs-image
```

## Why?
This is yet another scanimage-web-front-end. Why? It originally started as an
adaptation of phpsane - just to make everything a bit newer, give it a refresh
Expand All @@ -198,6 +110,9 @@ and it's been a labour of love ever since.
## Acknowledgements
* This project owes its genesis to
[phpsane](http://sourceforge.net/projects/phpsane/)
* [Everyone](https://github.com/sbs20/scanservjs/graphs/contributors) who has
filed issues, tested, fixed issues, added translations and helped over the
years. Thank you!

## More about SANE
* http://www.sane-project.org/
164 changes: 164 additions & 0 deletions docs/docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Running scanservjs under docker

## Quickstart

Get the image

```sh
docker pull sbs20/scanservjs:latest
```

Run it

```sh
docker rm --force scanservjs-container 2> /dev/null
docker run -d \
-p 8080:8080 \
-v /var/run/dbus:/var/run/dbus \
--restart unless-stopped \
--name scanservjs-container \
--privileged sbs20/scanservjs:latest
```

## General notes

* ⚠ By default, configuration and scanned images are stored within the container
and will be lost if you recreate it. If you want to map your scanned images
then see mapping section below
* ⚠ The docker image is amd64 only - and will not work on ARM devices such as
the Raspberry Pi. Please follow the manual installation process in these
cases

## Accessing hardware

Docker is great for certain tasks. But it's less ideal for situations where the
container needs to access the host hardware. The "simple" solution is to run
with `--privileged` but that gives your container full root access to the host -
you're putting a lot of trust in the container. In short, best not.

Depending on your setup you have a number of options.

* If your scanner is connected by USB to the host then you can map the device.
The best way to do this is to map the actual USB ports.
* Run `sudo sane-find-scanner -q` and you will get a result like
`found USB scanner (vendor=0x04a9 [Canon], product=0x220d [CanoScan], chip=LM9832/3) at libusb:001:003`.
* Or run `lsusb` which gives you
`Bus 001 Device 003: ID 04a9:220d Canon, Inc. CanoScan N670U/N676U/LiDE 20`.
* Both translate to `/dev/bus/usb/001/003`.
* The docker argument would be
`--device=/dev/bus/usb/001/003:/dev/bus/usb/001/003`

* If your scanner is driverless over the network, then
[sane-airscan](https://github.com/alexpevzner/sane-airscan) should be able to
figure it out - but it uses Avahi / Zeroconf / Bonjour to discover devices on
the local network. You will want to share dbus to make it work
(`-v /var/run/dbus:/var/run/dbus`).

* If your container is running inside a VM you may find that the USB device id
is [unstable](https://github.com/sbs20/scanservjs/issues/66) and changes
between boots. In these cases, you will probably find it easier to share the
scanner over the network on the host.

* Driverless-mode scanning (using airscan over IPP-USB) seems to result in
problems. If anyone has ideas why (perhaps something additional needs sharing
from host to guest) then suggestions are welcome.

* If you need proprietary drivers for your scanner then the best solution is
either to create your own docker image based on the scanservjs one and add it
in that way, or to install the drivers on the host and share it over the
network. Adding more backends to the docker container feels wrong and will add
cruft for many users who don't need it.

* The best fallback position for many cases is simply to
[share the host scanner over the network](https://github.com/sbs20/scanservjs/issues/129#issuecomment-800226184)
and referencing that within the guest. This means that the docker container is
just running the app.

## Mapping volumes

There are two volumes you may wish to map:

* The scanned images: use `-v /local/path/scans:/app/data/output`
* Configuration overrides: use `-v /local/path/cfg:/app/config`

## User and group mapping

The docker image which is created now runs under a non-privileged user account
with a UID of `2001`. If you attempt to run as a user other than `2001` or `0`
(e.g. `-u 1000`) then the process inside the container will no longer have
access to some of the things it needs to and it will fail. Most of the time you
won't care about the user, but if you're mapping volumes for either config or
data, then it may matter.

The solution in most cases is either to
* change the group of the container to a known group on the host e.g.
`-u 2001:1000`. This will keep the user correct (`2001`) but change the group
(`1000`)
* create a corresponding user on the host e.g.
`useradd -u 2001 -ms /bin/bash scanservjs`
* change the host volume permissions e.g. `chmod 777 local-volume`

## Environment variables

* `SANED_NET_HOSTS`: If you want to use a
[SaneOverNetwork](https://wiki.debian.org/SaneOverNetwork#Server_Configuration)
scanner then to perform the equivalent of adding hosts to
`/etc/sane.d/net.conf` specify a list of ip addresses separated by semicolons
in the `SANED_NET_HOSTS` environment variable.
* `AIRSCAN_DEVICES`: If you want to specifically add `sane-airscan` devices to
your `/etc/sane.d/airscan.conf` then use the `AIRSCAN_DEVICES` environment
variable (semicolon delimited).
* `DELIMITER`: if you need to inlcude semi-colons (`;`) in your environment
variables, this allows you to choose an alternative delimiter.
* `DEVICES`: Force add devices use `DEVICES` (semicolon delimited)
* `SCANIMAGE_LIST_IGNORE`: To force ignore `scanimage -L`

## Examples

### Mapped USB device with mapped volumes

```sh
docker run -d \
-p 8080:8080 \
-v $HOME/scan-data:/app/data/output \
-v $HOME/scan-cfg:/app/config \
--device /dev/bus/usb/001/003:/dev/bus/usb/001/003 \
--name scanservjs-container scanservjs-image
```

### Use airscan and a locally detected scanner
This should support most use cases

```sh
docker run -d -p 8080:8080 \
-v /var/run/dbus:/var/run/dbus \
--name scanservjs-container scanservjs-image
```

### A bit of everything
Add two net hosts to sane, use airscan to connect to two remote scanners, don't
use `scanimage -L`, force a list of devices, override the OCR language and run
in privileged mode

```sh
docker run -d -p 8080:8080 \
-e SANED_NET_HOSTS="10.0.100.30;10.0.100.31" \
-e AIRSCAN_DEVICES='"Canon MFD" = "http://192.168.0.10/eSCL";"EPSON MFD" = "http://192.168.0.11/eSCL"' \
-e SCANIMAGE_LIST_IGNORE=true \
-e DEVICES="net:10.0.100.30:plustek:libusb:001:003;net:10.0.100.31:plustek:libusb:001:003;airscan:e0:Canon TR8500 series;airscan:e1:EPSON Cool Series" \
-e OCR_LANG="fra" \
-v /var/run/dbus:/var/run/dbus \
--name scanservjs-container --privileged scanservjs-image
```

## Staging builds

These may be less stable, but also have upcoming features.

If you want to install the latest staging branch (this may contain newer code)

```sh
docker pull sbs20/scanservjs:staging
docker rm --force scanservjs-container 2> /dev/null
docker run -d -p 8080:8080 -v /var/run/dbus:/var/run/dbus --restart unless-stopped --name scanservjs-container --privileged sbs20/scanservjs:staging
```
25 changes: 17 additions & 8 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,29 @@ The easiest way to run is with Docker. But it's still possible to setup
manually.

## Manual Steps
* Get [SANE installed and working](./sane.md) and check permissions etc.
* Get nodejs and npm installed (You will need an up to date version of npm, you
may need to run `npm install npm@latest -g`)
* Download the latest release of scanserv, extract it and run `install.sh`

## tl;dr; (Debian 10)
* If you don't already have your scanner working, then you need to get
[SANE installed and working](./sane.md) and check permissions etc. Your
scanner can be attached to a different server / device if you're using saned.
* If you're using a debian based distro then you can just use the installer
script. But please note that this will install dependecies and needs to run as
root:
```sh
curl -s https://raw.githubusercontent.com/sbs20/scanservjs/master/server/bin/installer.sh | sudo bash -s -- -a
```
* If you're using another distro, then for the time being you either need to
manually run the steps in the install script or use docker.
## Download and install
If you don't fancy running a script directly from `curl` then you can manually
download the package and then run the installer inside.

```
sudo apt install -y nodejs npm sane-utils imagemagick curl
sudo npm install npm@latest -g
wget -O ~/scanservjs.tar.gz $(curl -s https://api.github.com/repos/sbs20/scanservjs/releases/latest | grep browser_download_url | cut -d '"' -f 4)
mkdir scanservjs
tar -xf scanservjs.tar.gz -C ./scanservjs/
sudo ./scanservjs/install.sh
sudo ./scanservjs/installer.sh -i
rm scanservjs.tar.gz
rm -r scanservjs
```
Expand Down
Loading

0 comments on commit 6a47fa6

Please sign in to comment.