Compare commits

...

77 Commits
v5.17 ... v7.11

Author SHA1 Message Date
Kroese
abd30b9d91 feat: Detect Windows and MacOS (#726) 2024-05-11 22:11:11 +02:00
Kroese
c86408cbd6 fix: Additional pass-through mounts (#722) 2024-05-08 23:23:17 +02:00
Kroese
1f51974c48 fix: Set download timeout (#719) 2024-05-04 17:24:21 +02:00
Kroese
29f4cde296 feat: Show download percentage (#718) 2024-05-04 16:34:30 +02:00
Kroese
c4a0035062 feat: Display RAM amount warning (#717) 2024-05-03 11:18:20 +02:00
Kroese
6724ddbd7d feat: Check the amount of RAM available (#716) 2024-05-02 20:21:21 +02:00
Kroese
8d8ed63122 docs: Disk pass-through (#715) 2024-05-01 11:57:56 +02:00
Kroese
6f4ea81907 feat: New disk pass-through method (#714) 2024-05-01 00:13:26 +02:00
Kroese
6d162744ec feat: Improved networking (#712) 2024-04-30 00:30:44 +02:00
Kroese
145b4aab5b docs: Update issue templates (#708) 2024-04-26 16:53:15 +02:00
Kroese
2e4eb56d0b fix: Curl error on Chinese mirror (#707) 2024-04-26 16:32:08 +02:00
Kroese
39c019193e fix: Curl error on Chinese mirror (#706) 2024-04-26 16:30:30 +02:00
Kroese
faec563b4a feat: Display kernel version (#704) 2024-04-26 13:59:51 +02:00
Kroese
9840f8e07a feat: Support ecryptfs filesystem (#703) 2024-04-26 06:04:48 +02:00
Kroese
3a5895fa0f build: Remove armv7 support (#702) 2024-04-26 04:16:46 +02:00
Kroese
1bac5c8a7f feat: Print system info (#701) 2024-04-25 14:31:49 +02:00
Kroese
dd76c60e2a fix: CPU detection (#697) 2024-04-22 16:48:41 +02:00
Kroese
ac78cc7dc5 feat: Display system info on boot (#696) 2024-04-22 16:29:23 +02:00
Kroese
66ac2d2002 docs: Update issue template (#692) 2024-04-17 19:03:17 +02:00
Kroese
0bd099d704 docs: Update issue templates (#691) 2024-04-17 18:32:43 +02:00
Kroese
d2dac3cfb4 docs: Add issue templates (#690) 2024-04-17 18:14:51 +02:00
Kroese
e81dc0f31d fix: Verify files are not empty (#689) 2024-04-16 15:35:35 +02:00
Kroese
5015597183 fix: Ignore empty MAC address (#688) 2024-04-13 23:33:17 +02:00
Kroese
64e2af9fa2 fix: Continue if file is missing (#682) 2024-04-08 09:54:42 +02:00
Kroese
debb4b69fc fix: Continue when range request fails (#680) 2024-04-08 04:53:30 +02:00
Kroese
c6d3dda171 docs: Readme (#677) 2024-04-07 01:59:50 +02:00
Kroese
7c0693c2ff build: Update qemu-host to v2.04 (#670) 2024-03-31 05:24:54 +02:00
Kroese
76355d4857 fix: TUN error message (#669) 2024-03-31 04:57:56 +02:00
Kroese
404aaadefc build: Dockerfile (#663) 2024-03-25 16:49:25 +01:00
Kroese
be027e10be fix: Disable IPv6 in Nginx (#662) 2024-03-25 13:53:30 +01:00
Kroese
1c8cad92f8 fix: Disable kernel networking in bridge mode (#656) 2024-03-12 01:50:43 +01:00
Kroese
fabb8ea3b7 docs: Readme (#650) 2024-02-28 20:43:27 +01:00
Kroese
2ee4abca54 docs: Docker run command (#647) 2024-02-28 08:51:55 +01:00
Kroese
5896928030 feat: Persistant MAC address (#646) 2024-02-28 08:40:00 +01:00
Kroese
8652544982 docs: Readme (#638) 2024-02-19 21:32:22 +01:00
Kroese
a70338ec3c feat: Print filesystem on error (#635) 2024-02-17 05:56:40 +01:00
Kroese
a84878abfc fix: Detect Mac Journal filesystem (#634) 2024-02-17 03:55:30 +01:00
Kroese
8421a391b7 fix: Prevent re-entry during shutdown (#633) 2024-02-16 16:03:37 +01:00
Kroese
f9340ec3d6 docs: Readme (#630) 2024-02-10 00:33:21 +01:00
Kroese
0cca9c5f83 feat: Disable CoW check on XFS (#629) 2024-02-09 23:53:18 +01:00
Kroese
13d60b7f47 build: Notify after build (#628) 2024-02-09 14:45:38 +01:00
Kroese
f74771a9cc fix: Convert MAC address to uppercase (#627) 2024-02-08 17:33:11 +01:00
Kroese
f24ba41930 fix: Convert dashes in custom MAC addresses (#626) 2024-02-08 17:03:30 +01:00
Kroese
f412580a4a feat: Add DNS entry for container (#624) 2024-02-07 22:26:29 +01:00
Kroese
5cde1b4438 feat: Set process name (#623) 2024-02-07 13:04:29 +01:00
Kroese
7cfb57b1bc docs: Readme (#621) 2024-02-05 16:18:13 +01:00
Kroese
a478b58f97 feat: Set KVM tick policy (#620) 2024-02-05 12:09:12 +01:00
Kroese
8297f4f880 fix: Support CPU's without SSE4 (#619) 2024-02-05 07:41:47 +01:00
Kroese
4c67343d33 feat: Enable L3 cache and multi-threaded TCG (#618) 2024-02-04 19:25:22 +01:00
Kroese
53cc6998f0 fix: CPU features 2024-02-02 22:44:43 +01:00
Kroese
d857d71e0d fix: Merge drive function (#614) 2024-02-01 11:05:33 +01:00
Kroese
003c2766ce docs: Readme (#613) 2024-01-31 04:28:24 +01:00
Kroese
78594098cc feat: Disable CoW check on ZFS (#612) 2024-01-31 03:54:40 +01:00
Kroese
3c31bc91e4 feat: Generate unique MAC address (#611) 2024-01-30 04:46:44 +01:00
Kroese
72141bab7a build: Lint Dockerfile (#610) 2024-01-29 11:51:28 +01:00
Kroese
bc52463aa4 fix: Process signal faster (#609) 2024-01-29 05:54:22 +01:00
Kroese
9fa68908a9 feat: Show download progress (#608) 2024-01-29 05:40:06 +01:00
Kroese
740dbec1b1 build: Exclude web folder (#607) 2024-01-29 02:29:05 +01:00
Kroese
440d203730 fix: Stylesheet (#606) 2024-01-29 02:27:04 +01:00
Kroese
1a83c67e2c feat: Font smoothing (#605) 2024-01-29 02:01:51 +01:00
Kroese
34a707a2a5 docs: Readme (#603) 2024-01-27 19:51:26 +01:00
Kroese
cabb2cdfc9 docs: Readme (#602) 2024-01-27 19:10:43 +01:00
Kroese
dc52ccf172 docs: Readme (#601) 2024-01-27 19:06:10 +01:00
Kroese
bdd7fec3c3 fix: Space after URL (#600) 2024-01-27 02:01:27 +01:00
Kroese
bd8b03d089 docs: Readme (#599) 2024-01-26 06:29:15 +01:00
Kroese
a10588b0ce fix: Check dnsmasq (#598) 2024-01-26 02:19:31 +01:00
renovate[bot]
3503b86e12 chore(deps): update peter-evans/dockerhub-description action to v4 (#597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-25 17:05:28 +01:00
Kroese
9e124980cd fix: Disk message (#596) 2024-01-25 17:02:50 +01:00
Kroese
675aa5e122 docs: Readme (#595) 2024-01-23 21:49:18 +01:00
Kroese
2a62d4e938 feat: Display console arguments (#594) 2024-01-23 19:32:15 +01:00
Kroese
9cbb51cc86 feat: Display QEMU version (#593) 2024-01-23 19:29:07 +01:00
Kroese
7790f81d15 fix: Trap exit code (#592) 2024-01-23 18:46:47 +01:00
Kroese
fdbff4879b fix: Incorrect path (#591) 2024-01-23 03:06:29 +01:00
Kroese
739e679a66 feat: Check for SHM (#590) 2024-01-23 03:04:47 +01:00
Kroese
0dea507d85 feat: Shorter messages (#588) 2024-01-23 00:15:11 +01:00
Kroese
4f524c47d8 docs: Readme (#587) 2024-01-22 03:24:00 +01:00
Kroese
0c74201eb4 feat: CPU flags (#586) 2024-01-21 20:52:53 +01:00
26 changed files with 810 additions and 311 deletions

View File

@@ -6,7 +6,10 @@
.gitmodules .gitmodules
Dockerfile Dockerfile
Dockerfile.archive Dockerfile.archive
compose.yml
compose.yaml
docker-compose.yml docker-compose.yml
docker-compose.yaml
*.md *.md

64
.github/ISSUE_TEMPLATE/BUG_REPORT.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: "\U0001F41E Bug Report"
description: Create a report to help us improve the container
title: "[Bug]: "
labels: ["bug"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: input
id: cpu
attributes:
label: Machine specifications
description: The processor and RAM amount in your machine.
placeholder: e.g. Intel N5105 / 16 GB
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
description: The Linux distribution and kernel version as shown by `uname -a`.
placeholder: e.g. Ubuntu 24.04 / Kernel 6.8.0-22-generic
validations:
required: true
- type: input
id: docker
attributes:
label: Docker version
description: The Docker version as shown by `docker -v`.
placeholder: e.g. Docker version 26.0.1, build d260a54
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: A clear and concise description of the problem.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The Docker compose file (or otherwise `run` command).
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The Docker logfile of the container.
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots of the problem.
validations:
required: false

View File

@@ -0,0 +1,44 @@
name: "\U0001F680 Feature request"
description: Suggest an idea for improving the container
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: checkboxes
attributes:
label: Is there an existing feature request for this?
description: Please search to see if the feature request already exists.
options:
- label: I have searched the existing feature requests
required: true
- type: textarea
id: problem
attributes:
label: Is your proposal related to a problem?
description: |
Provide a clear and concise description of what the problem is.
For example, "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like.
description: |
Provide a clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered.
description: |
Let us know about other solutions you've tried or researched.
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional context
description: |
Is there anything else you can add about the proposal?
You might want to link to related issues here, if you haven't already.

26
.github/ISSUE_TEMPLATE/QUESTION.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: "? Question"
description: General questions about the container
title: "[Question]: "
labels: ["question"]
body:
- type: checkboxes
attributes:
label: Is your question not already answered in the FAQ?
description: Please read the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md) carefully to avoid asking duplicate questions.
options:
- label: I made sure the question is not listed in the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md).
required: true
- type: checkboxes
attributes:
label: Is this a general question and not a technical issue?
description: For technical issues you must use the [bug report](https://github.com/vdsm/virtual-dsm/issues/new?assignees=&labels=bug&projects=&template=BUG_REPORT.yml&title=%5BBug%5D%3A+) form instead. It contains all the right fields (system info, logfiles, etc.) we need in order to be able to help you.
options:
- label: I am sure my question is not about a technical issue.
required: true
- type: textarea
id: question
attributes:
label: Question
description: What's the question you have about the container?
validations:
required: true

View File

@@ -8,6 +8,10 @@ on:
paths-ignore: paths-ignore:
- '**/*.md' - '**/*.md'
- '**/*.yml' - '**/*.yml'
- '**/*.js'
- '**/*.css'
- '**/*.html'
- 'web/**'
- '.gitignore' - '.gitignore'
- '.dockerignore' - '.dockerignore'
- '.github/**' - '.github/**'
@@ -74,7 +78,7 @@ jobs:
context: . context: .
push: true push: true
provenance: false provenance: false
platforms: linux/amd64,linux/arm64,linux/arm platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}
@@ -99,3 +103,15 @@ jobs:
url: ${{ secrets.GITLAB_URL }} url: ${{ secrets.GITLAB_URL }}
token: ${{ secrets.GITLAB_TOKEN }} token: ${{ secrets.GITLAB_TOKEN }}
username: ${{ secrets.GITLAB_USERNAME }} username: ${{ secrets.GITLAB_USERNAME }}
-
name: Send mail
uses: action-pack/send-mail@v1
with:
to: ${{secrets.MAILTO}}
from: Github Actions <${{secrets.MAILTO}}>
connection_url: ${{secrets.MAIL_CONNECTION}}
subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed
body: |
The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully!
See https://github.com/${{ github.repository }}/actions for more information.

View File

@@ -7,8 +7,18 @@ jobs:
name: shellcheck name: shellcheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 -
- name: Run ShellCheck name: Checkout
uses: actions/checkout@v4
-
name: Run ShellCheck
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@master
env: env:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028 SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
-
name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
ignore: DL3008,DL3003,DL3006
failure-threshold: warning

View File

@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- -
name: Docker Hub Description name: Docker Hub Description
uses: peter-evans/dockerhub-description@v3 uses: peter-evans/dockerhub-description@v4
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}

View File

@@ -3,6 +3,7 @@ on:
pull_request: pull_request:
paths: paths:
- '**/*.sh' - '**/*.sh'
- 'Dockerfile'
- '.github/workflows/test.yml' - '.github/workflows/test.yml'
- '.github/workflows/check.yml' - '.github/workflows/check.yml'

View File

@@ -1,4 +1,4 @@
FROM qemux/qemu-host as builder FROM qemux/qemu-host:2.04 as builder
# FROM golang as builder # FROM golang as builder
# WORKDIR / # WORKDIR /
@@ -14,9 +14,9 @@ ARG DEBCONF_NOWARNINGS "yes"
ARG DEBIAN_FRONTEND "noninteractive" ARG DEBIAN_FRONTEND "noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN "true" ARG DEBCONF_NONINTERACTIVE_SEEN "true"
RUN if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \ RUN if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi && \
&& apt-get update \ apt-get update && \
&& apt-get --no-install-recommends -y install \ apt-get --no-install-recommends -y install \
jq \ jq \
tini \ tini \
curl \ curl \
@@ -37,11 +37,11 @@ RUN if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \
ca-certificates \ ca-certificates \
netcat-openbsd \ netcat-openbsd \
qemu-system-x86 \ qemu-system-x86 \
"$extra" \ "$extra" && \
&& apt-get clean \ apt-get clean && \
&& unlink /etc/nginx/sites-enabled/default \ unlink /etc/nginx/sites-enabled/default && \
&& sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf \ sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf && \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY ./src /run/ COPY ./src /run/
COPY ./web /var/www/ COPY ./web /var/www/

View File

@@ -5,12 +5,8 @@ services:
image: vdsm/virtual-dsm:latest image: vdsm/virtual-dsm:latest
environment: environment:
DISK_SIZE: "16G" DISK_SIZE: "16G"
RAM_SIZE: "1G"
CPU_CORES: "1"
devices: devices:
- /dev/kvm - /dev/kvm
device_cgroup_rules:
- 'c *:* rwm'
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
ports: ports:

277
readme.md
View File

@@ -1,6 +1,6 @@
<h1 align="center">Virtual DSM<br /> <h1 align="center">Virtual DSM<br />
<div align="center"> <div align="center">
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /> <a href="https://github.com/vdsm/virtual-dsm"><img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /></a>
</div> </div>
<div align="center"> <div align="center">
@@ -11,18 +11,17 @@
</div></h1> </div></h1>
Virtual DSM in a docker container. Virtual DSM in a Docker container.
## Features ## Features
- Multiple disks - Multiple disks
- KVM acceleration - KVM acceleration
- GPU pass-through
- Upgrades supported - Upgrades supported
## Usage ## Usage
Via `docker-compose.yml` Via Docker Compose:
```yaml ```yaml
version: "3" version: "3"
@@ -44,198 +43,200 @@ services:
stop_grace_period: 2m stop_grace_period: 2m
``` ```
Via `docker run` Via Docker CLI:
```bash ```bash
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 vdsm/virtual-dsm docker run -it --rm --name dsm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 120 vdsm/virtual-dsm
``` ```
## FAQ ## FAQ
* ### How do I use it? * ### How do I use it?
Very simple! These are the steps: Very simple! These are the steps:
- Start the container and get some coffee. - Start the container and connect to [port 5000](http://localhost:5000) using your web browser.
- Connect to [port 5000](http://localhost:5000) of the container in your web browser. - Wait until DSM is ready, choose an username and password, and you will be taken to the desktop.
Enjoy your brand new machine, and don't forget to star this repo!
- Wait until DSM is ready, choose an username and password, and you will be taken to the desktop. * ### How do I change the storage location?
- Enjoy your brand new machine, and don't forget to star this repo! To change the storage location, include the following bind mount in your compose file:
* ### How do I change the size of the disk? ```yaml
volumes:
- /var/dsm:/storage
```
To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity: Replace the example path `/var/dsm` with the desired storage folder.
* ### How do I change the size of the disk?
```yaml To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
environment:
DISK_SIZE: "128G"
```
This can also be used to resize the existing disk to a larger capacity without any data loss.
* ### How do I change the storage location? ```yaml
environment:
DISK_SIZE: "128G"
```
This can also be used to resize the existing disk to a larger capacity without any data loss.
To change the storage location, include the following bind mount in your compose file: * ### How do I create a growable disk?
```yaml By default, the entire capacity of the disk is reserved in advance.
volumes:
- /var/dsm:/storage
```
Replace the example path `/var/dsm` with the desired storage folder. To create a growable disk that only allocates space that is actually used, add the following environment variable:
* ### How do I create a growable disk? ```yaml
environment:
DISK_FMT: "qcow2"
```
By default, the entire capacity of the disk is reserved in advance. Please note that this may reduce the write performance of the disk.
To create a growable disk that only allocates space that is actually used, add the following environment variable:
```yaml
environment:
DISK_FMT: "qcow2"
```
Please note that this may reduce the write performance of the disk.
* ### How do I add multiple disks? * ### How do I add multiple disks?
To create additional disks, modify your compose file like this: To create additional disks, modify your compose file like this:
```yaml ```yaml
environment: environment:
DISK2_SIZE: "32G" DISK2_SIZE: "32G"
DISK3_SIZE: "64G" DISK3_SIZE: "64G"
volumes: volumes:
- /home/example:/storage2 - /home/example:/storage2
- /mnt/data/example:/storage3 - /mnt/data/example:/storage3
``` ```
* ### How do I pass-through a disk? * ### How do I pass-through a disk?
It is possible to pass-through disk devices directly by adding them to your compose file in this way: It is possible to pass-through disk devices directly by adding them to your compose file in this way:
```yaml ```yaml
environment: devices:
DEVICE2: "/dev/sda" - /dev/disk/by-uuid/12345-12345-12345-12345-12345:/disk2
DEVICE3: "/dev/sdb" - /dev/disk/by-uuid/45678-45678-45678-45678-45678:/disk3
devices: ```
- /dev/sda
- /dev/sdb
```
Please note that the device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume. Make sure to bind the disk via its UUID (obtainable via `lsblk -o name,uuid`) instead of its name (`/dev/sdc`), to prevent ever binding the wrong disk when the drive letters happen to change.
Do NOT use this feature with the goal of sharing files from the host, they will all be lost without warning when DSM creates the volume. Please note that the device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume.
* ### How do I increase the amount of CPU or RAM? Do NOT use this feature with the goal of sharing files from the host, they will all be lost without warning when DSM creates the volume.
By default, a single CPU core and 1 GB of RAM are allocated to the container. * ### How do I increase the amount of CPU or RAM?
To increase this, add the following environment variables: By default, a single CPU core and 1 GB of RAM are allocated to the container.
```yaml If there arises a need to increase this, add the following environment variables:
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
* ### How do I verify if my system supports KVM? ```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
To verify if your system supports KVM, run the following commands: * ### How do I verify if my system supports KVM?
```bash To verify if your system supports KVM, run the following commands:
sudo apt install cpu-checker
sudo kvm-ok
```
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS. ```bash
sudo apt install cpu-checker
sudo kvm-ok
```
* ### How do I assign an individual IP address to the container? If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS.
By default, the container uses bridge networking, which shares the IP address with the host. * ### How do I assign an individual IP address to the container?
If you want to assign an individual IP address to the container, you can create a macvlan network as follows: By default, the container uses bridge networking, which shares the IP address with the host.
```bash If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
Once you have created the network, change your compose file to look as follows: ```bash
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
```yaml Once you have created the network, change your compose file to look as follows:
services:
dsm:
container_name: dsm
..<snip>..
networks:
vdsm:
ipv4_address: 192.168.0.100
networks: ```yaml
vdsm: services:
external: true dsm:
``` container_name: dsm
..<snip>..
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default. networks:
vdsm:
ipv4_address: 192.168.0.100
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround. networks:
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
* ### How can DSM acquire an IP address from my router? Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices. * ### How can DSM acquire an IP address from my router?
To enable this feature, add the following lines to your compose file: After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
```yaml To enable this mode, add the following lines to your compose file:
environment:
DHCP: "Y"
device_cgroup_rules:
- 'c *:* rwm'
```
Please note that even if you don't want DHCP, it's still recommended to enable this feature, as it prevents NAT issues and increases performance by using a `macvtap` interface. In that case, just set a static IP from the DSM control panel after you enabled this mode. ```yaml
environment:
DHCP: "Y"
devices:
- /dev/vhost-net
device_cgroup_rules:
- 'c *:* rwm'
```
* ### How do I pass-through the GPU? Please note that even if you don't need DHCP, it's still recommended to enable this mode, as it prevents NAT issues and increases performance by using a `macvtap` interface. You can just set a static IP from the DSM control panel afterwards.
To pass-through your Intel GPU, add the following lines to your compose file: * ### How do I pass-through the GPU?
```yaml To pass-through your Intel GPU, add the following lines to your compose file:
environment:
GPU: "Y"
devices:
- /dev/dri
```
This can be used to enable the facial recognition function in Synology Photos for example. ```yaml
environment:
GPU: "Y"
devices:
- /dev/dri
```
* ### How do I install a specific version of vDSM? This can be used to enable the facial recognition function in Synology Photos for example.
By default, version 7.2 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows: * ### How do I install a specific version of vDSM?
```yaml By default, version 7.2 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows:
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
With this method, it is even possible to switch between different versions while keeping all your file data intact. ```yaml
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
* ### What are the differences compared to the standard DSM? With this method, it is even possible to switch between different versions while keeping all your file data intact.
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses. * ### What are the differences compared to the standard DSM?
* ### Is this project legal?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project would be considered legal. There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this project on an official Synology NAS, as any other use will be a violation of their terms and conditions. * ### Is this project legal?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project would be considered legal.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this container on an official Synology NAS, as any other use will be a violation of their terms and conditions.
## Stars
[![Stars](https://starchart.cc/vdsm/virtual-dsm.svg?variant=adaptive)](https://starchart.cc/vdsm/virtual-dsm)
## Disclaimer ## Disclaimer
@@ -247,5 +248,5 @@ Only run this container on Synology hardware, any other use is not permitted by
[Build]: https://github.com/vdsm/virtual-dsm/actions/workflows/build.yml/badge.svg [Build]: https://github.com/vdsm/virtual-dsm/actions/workflows/build.yml/badge.svg
[Size]: https://img.shields.io/docker/image-size/vdsm/virtual-dsm/latest?color=066da5&label=size [Size]: https://img.shields.io/docker/image-size/vdsm/virtual-dsm/latest?color=066da5&label=size
[Pulls]: https://img.shields.io/docker/pulls/kroese/virtual-dsm.svg?style=flat&label=pulls&logo=docker [Pulls]: https://img.shields.io/docker/pulls/vdsm/virtual-dsm.svg?style=flat&label=pulls&logo=docker
[Version]: https://img.shields.io/docker/v/vdsm/virtual-dsm/latest?arch=amd64&sort=semver&color=066da5 [Version]: https://img.shields.io/docker/v/vdsm/virtual-dsm/latest?arch=amd64&sort=semver&color=066da5

View File

@@ -1,13 +1,16 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
: "${NETWORK:="Y"}"
[ -f "/run/shm/qemu.end" ] && echo "QEMU is shutting down.." && exit 1 [ -f "/run/shm/qemu.end" ] && echo "QEMU is shutting down.." && exit 1
[ ! -f "/run/shm/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0 [ ! -s "/run/shm/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0
[[ "$NETWORK" != [Yy1]* ]] && echo "Networking is disabled.." && exit 0
file="/run/shm/dsm.url" file="/run/shm/dsm.url"
address="/run/shm/qemu.ip" address="/run/shm/qemu.ip"
[ ! -f "$file" ] && echo "DSM has not enabled networking yet.." && exit 1 [ ! -s "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
location=$(<"$file") location=$(<"$file")

View File

@@ -2,9 +2,9 @@
set -Eeuo pipefail set -Eeuo pipefail
DEF_OPTS="-nodefaults -boot strict=on" DEF_OPTS="-nodefaults -boot strict=on"
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g') RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
CPU_OPTS="-cpu $CPU_MODEL -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1" CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
MAC_OPTS="-machine type=q35,usb=off,dump-guest-core=off,hpet=off${KVM_OPTS}" MAC_OPTS="-machine type=q35,usb=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4" DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom" DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c" DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
@@ -12,4 +12,18 @@ DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS" ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS"
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ') ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
# Check available memory as the very last step
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
AVAIL_GB=$(( (RAM_AVAIL + 1073741823)/1073741824 ))
if (( (RAM_WANTED + 500000000) > RAM_AVAIL )); then
error "Your configured RAM_SIZE of $WANTED_GB GB is higher than the $AVAIL_GB GB of memory available, please set a lower value."
exit 17
fi
if (( (RAM_WANTED + 1450000000) > RAM_AVAIL )); then
warn "your configured RAM_SIZE of $WANTED_GB GB is much too close to the $AVAIL_GB GB of memory available, please set a lower value."
fi
return 0 return 0

View File

@@ -13,8 +13,8 @@ set -Eeuo pipefail
BOOT="$STORAGE/$BASE.boot.img" BOOT="$STORAGE/$BASE.boot.img"
SYSTEM="$STORAGE/$BASE.system.img" SYSTEM="$STORAGE/$BASE.system.img"
[ ! -f "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81 [ ! -s "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81
[ ! -f "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82 [ ! -s "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
DISK_OPTS="\ DISK_OPTS="\
-object iothread,id=io2 \ -object iothread,id=io2 \
@@ -80,13 +80,23 @@ getSize() {
isCow() { isCow() {
local FS=$1 local FS=$1
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then if [[ "${FS,,}" == "btrfs" ]]; then
return 0 return 0
fi fi
return 1 return 1
} }
supportsDirect() {
local FS=$1
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
return 1
fi
return 0
}
createDisk() { createDisk() {
local DISK_FILE=$1 local DISK_FILE=$1
local DISK_SPACE=$2 local DISK_SPACE=$2
@@ -112,8 +122,8 @@ createDisk() {
fi fi
fi fi
MSG="Creating a $DISK_TYPE $DISK_DESC image in $DISK_FMT format with a size of $DISK_SPACE..." html "Creating a $DISK_DESC image..."
info "$MSG" && html "$MSG" info "Creating a $DISK_SPACE $DISK_TYPE $DISK_DESC image in $DISK_FMT format..."
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)" local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
@@ -266,8 +276,8 @@ convertDisk() {
fi fi
fi fi
MSG="Converting $DISK_DESC to $DST_FMT, please wait until completed..." html "Converting $DISK_DESC to $DST_FMT..."
info "$MSG" && html "$MSG" info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
local CONV_FLAGS="-p" local CONV_FLAGS="-p"
local DISK_PARAM="$DISK_ALLOC" local DISK_PARAM="$DISK_ALLOC"
@@ -306,8 +316,8 @@ convertDisk() {
fi fi
fi fi
MSG="Conversion of $DISK_DESC to $DST_FMT completed succesfully!" html "Conversion of $DISK_DESC completed..."
info "$MSG" && html "$MSG" info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
return 0 return 0
} }
@@ -329,6 +339,10 @@ checkFS () {
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!" info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
fi fi
if ! supportsDirect "$FS"; then
info "Warning: the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then if isCow "$FS"; then
if [ -f "$DISK_FILE" ]; then if [ -f "$DISK_FILE" ]; then
FA=$(lsattr "$DISK_FILE") FA=$(lsattr "$DISK_FILE")
@@ -341,17 +355,39 @@ checkFS () {
return 0 return 0
} }
addDisk () { createDevice () {
local DISK_ID=$1 local DISK_ID=$1
local DISK_BASE=$2 local DISK_FILE=$2
local DISK_EXT=$3 local DISK_INDEX=$3
local DISK_DESC=$4 local DISK_ADDRESS=$4
local DISK_SPACE=$5 local DISK_FMT=$5
local DISK_INDEX=$6 local DISK_IO=$6
local DISK_ADDRESS=$7 local DISK_CACHE=$7
local DISK_FMT=$8
local result="-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on"
result="$result \
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
echo "$result"
return 0
}
addDisk () {
local DISK_BASE=$1
local DISK_EXT=$2
local DISK_DESC=$3
local DISK_SPACE=$4
local DISK_INDEX=$5
local DISK_ADDRESS=$6
local DISK_FMT=$7
local DISK_IO=$8
local DISK_CACHE=$9
local DISK_ID="userdata$DISK_INDEX"
local DISK_FILE="$DISK_BASE.$DISK_EXT" local DISK_FILE="$DISK_BASE.$DISK_EXT"
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE OPTS
DIR=$(dirname "$DISK_FILE") DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0 [ ! -d "$DIR" ] && return 0
@@ -371,7 +407,12 @@ addDisk () {
FS=$(stat -f -c %T "$DIR") FS=$(stat -f -c %T "$DIR")
checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $? checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $?
if ! [ -f "$DISK_FILE" ] ; then if ! supportsDirect "$FS"; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
if ! [ -s "$DISK_FILE" ] ; then
if [[ "${DISK_FMT,,}" != "raw" ]]; then if [[ "${DISK_FMT,,}" != "raw" ]]; then
PREV_FMT="raw" PREV_FMT="raw"
@@ -380,12 +421,12 @@ addDisk () {
fi fi
PREV_EXT=$(fmt2ext "$PREV_FMT") PREV_EXT=$(fmt2ext "$PREV_FMT")
if [ -f "$DISK_BASE.$PREV_EXT" ] ; then if [ -s "$DISK_BASE.$PREV_EXT" ] ; then
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $? convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
fi fi
fi fi
if [ -f "$DISK_FILE" ]; then if [ -s "$DISK_FILE" ]; then
CUR_SIZE=$(getSize "$DISK_FILE") CUR_SIZE=$(getSize "$DISK_FILE")
@@ -399,29 +440,26 @@ addDisk () {
fi fi
DISK_OPTS="$DISK_OPTS \ OPTS=$(createDevice "$DISK_ID" "$DISK_FILE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE")
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \ DISK_OPTS="$DISK_OPTS $OPTS"
-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
return 0 return 0
} }
addDevice () { addDevice () {
local DISK_ID=$1 local DISK_DEV=$1
local DISK_DEV=$2 local DISK_DESC=$2
local DISK_DESC=$3 local DISK_INDEX=$3
local DISK_INDEX=$4 local DISK_ADDRESS=$4
local DISK_ADDRESS=$5 local DISK_ID="userdata$DISK_INDEX"
[ -z "$DISK_DEV" ] && return 0 [ -z "$DISK_DEV" ] && return 0
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55 [ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
DISK_OPTS="$DISK_OPTS \ local OPTS
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \ OPTS=$(createDevice "$DISK_ID" "$DISK_DEV" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE")
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \ DISK_OPTS="$DISK_OPTS $OPTS"
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
return 0 return 0
} }
@@ -489,28 +527,38 @@ DISK4_FILE="/storage4/data4"
: "${DEVICE3:=""}" : "${DEVICE3:=""}"
: "${DEVICE4:=""}" : "${DEVICE4:=""}"
[ -z "$DEVICE" ] && [ -b "/disk1" ] && DEVICE="/disk1"
[ -z "$DEVICE2" ] && [ -b "/disk2" ] && DEVICE2="/disk2"
[ -z "$DEVICE3" ] && [ -b "/disk3" ] && DEVICE3="/disk3"
[ -z "$DEVICE4" ] && [ -b "/disk4" ] && DEVICE4="/disk4"
[ -z "$DEVICE" ] && [ -b "/dev/disk1" ] && DEVICE="/dev/disk1"
[ -z "$DEVICE2" ] && [ -b "/dev/disk2" ] && DEVICE2="/dev/disk2"
[ -z "$DEVICE3" ] && [ -b "/dev/disk3" ] && DEVICE3="/dev/disk3"
[ -z "$DEVICE4" ] && [ -b "/dev/disk4" ] && DEVICE4="/dev/disk4"
if [ -n "$DEVICE" ]; then if [ -n "$DEVICE" ]; then
addDevice "userdata" "$DEVICE" "device" "3" "0xc" || exit $? addDevice "$DEVICE" "device" "3" "0xc" || exit $?
else else
addDisk "userdata" "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" || exit $? addDisk "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi fi
if [ -n "$DEVICE2" ]; then if [ -n "$DEVICE2" ]; then
addDevice "userdata2" "$DEVICE2" "device2" "4" "0xd" || exit $? addDevice "$DEVICE2" "device2" "4" "0xd" || exit $?
else else
addDisk "userdata2" "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" || exit $? addDisk "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi fi
if [ -n "$DEVICE3" ]; then if [ -n "$DEVICE3" ]; then
addDevice "userdata3" "$DEVICE3" "device3" "5" "0xe" || exit $? addDevice "$DEVICE3" "device3" "5" "0xe" || exit $?
else else
addDisk "userdata3" "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" || exit $? addDisk "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi fi
if [ -n "$DEVICE4" ]; then if [ -n "$DEVICE4" ]; then
addDevice "userdata4" "$DEVICE4" "device4" "6" "0xf" || exit $? addDevice "$DEVICE4" "device4" "6" "0xf" || exit $?
else else
addDisk "userdata4" "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "6" "0xf" "$DISK_FMT" || exit $? addDisk "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "6" "0xf" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi fi
html "Initialized disks successfully..." html "Initialized disks successfully..."

View File

@@ -15,7 +15,8 @@ if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
fi fi
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga $VGA" DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128"
DISPLAY_OPTS="$DISPLAY_OPTS -vga $VGA"
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri [ ! -d /dev/dri ] && mkdir -m 755 /dev/dri

View File

@@ -18,11 +18,13 @@ cd /run
trap - ERR trap - ERR
info "Booting ${APP}..."
[[ "$DEBUG" == [Yy1]* ]] && echo "Arguments: $ARGS" && echo
if [[ "$CONSOLE" == [Yy]* ]]; then if [[ "$CONSOLE" == [Yy]* ]]; then
exec qemu-system-x86_64 ${ARGS:+ $ARGS} exec qemu-system-x86_64 ${ARGS:+ $ARGS}
fi fi
[[ "$DEBUG" == [Yy1]* ]] && info "$VERS" && echo "Arguments: $ARGS" && echo
{ qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || : { qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || :
(( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15 (( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15
@@ -30,4 +32,5 @@ terminal
tail -fn +0 "$QEMU_LOG" 2>/dev/null & tail -fn +0 "$QEMU_LOG" 2>/dev/null &
cat "$QEMU_TERM" 2>/dev/null & wait $! || : cat "$QEMU_TERM" 2>/dev/null & wait $! || :
sleep 1 && finish 0 sleep 1 & wait $!
finish 0

View File

@@ -5,6 +5,7 @@ set -Eeuo pipefail
if [ -f "$STORAGE/dsm.ver" ]; then if [ -f "$STORAGE/dsm.ver" ]; then
BASE=$(<"$STORAGE/dsm.ver") BASE=$(<"$STORAGE/dsm.ver")
[ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057"
else else
# Fallback for old installs # Fallback for old installs
BASE="DSM_VirtualDSM_42962" BASE="DSM_VirtualDSM_42962"
@@ -12,14 +13,14 @@ fi
if [ -n "$URL" ]; then if [ -n "$URL" ]; then
BASE=$(basename "$URL" .pat) BASE=$(basename "$URL" .pat)
if [ ! -f "$STORAGE/$BASE.system.img" ]; then if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat) BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}" : "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g') BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g')
fi fi
fi fi
if [[ -f "$STORAGE/$BASE.boot.img" ]] && [[ -f "$STORAGE/$BASE.system.img" ]]; then if [[ -s "$STORAGE/$BASE.boot.img" ]] && [[ -s "$STORAGE/$BASE.system.img" ]]; then
return 0 # Previous installation found return 0 # Previous installation found
fi fi
@@ -65,7 +66,15 @@ if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!" info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
fi fi
if [[ "${FS,,}" != "fat"* && "${FS,,}" != "vfat"* && "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "msdos"* ]]; then if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
info "Warning: the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if [[ "${FS,,}" == "fat"* || "${FS,,}" == "vfat"* || "${FS,,}" == "msdos"* ]]; then
error "Unable to install on $FS filesystems, please use a different filesystem for /storage." && exit 61
fi
if [[ "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "unknown"* ]]; then
TMP="$STORAGE/tmp" TMP="$STORAGE/tmp"
else else
TMP="/tmp/dsm" TMP="/tmp/dsm"
@@ -102,29 +111,48 @@ fi
ROOT="Y" ROOT="Y"
RDC="$STORAGE/dsm.rd" RDC="$STORAGE/dsm.rd"
if [ ! -f "$RDC" ]; then if [ ! -s "$RDC" ]; then
MSG="Downloading installer..." MSG="Downloading installer..."
PRG="Downloading installer ([P])..."
info "Install: $MSG" && html "$MSG" info "Install: $MSG" && html "$MSG"
RD="$TMP/rd.gz" RD="$TMP/rd.gz"
SIZE=5394188
POS="65627648-71021835" POS="65627648-71021835"
VERIFY="b4215a4b213ff5154db0488f92c87864" VERIFY="b4215a4b213ff5154db0488f92c87864"
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat" LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
{ curl -r "$POS" -sfk -S -o "$RD" "$LOC"; rc=$?; } || : rm -f "$RD"
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60 rm -f "$RDC"
/run/progress.sh "$RD" "$SIZE" "$PRG" &
{ curl -r "$POS" -sfk --connect-timeout 10 -S -o "$RD" "$LOC"; rc=$?; } || :
SUM=$(md5sum "$RD" | cut -f 1 -d " ") fKill "progress.sh"
if (( rc != 0 )); then
if (( rc != 22 )) && (( rc != 56 )); then
error "Failed to download $LOC, reason: $rc" && exit 60
fi
SUM="skip"
else
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
fi
if [ "$SUM" != "$VERIFY" ]; then if [ "$SUM" != "$VERIFY" ]; then
PAT="/install.pat" PAT="/install.pat"
rm "$RD" SIZE=379637760
rm -f "$RD"
rm -f "$PAT" rm -f "$PAT"
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || : html "$MSG"
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60 /run/progress.sh "$PAT" "$SIZE" "$PRG" &
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --timeout=10 --show-progress "$PROGRESS"; rc=$?; } || :
fKill "progress.sh"
(( rc != 0 )) && error "Failed to download $LOC , reason: $rc" && exit 60
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")" tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
rm "$PAT" rm "$PAT"
@@ -138,14 +166,14 @@ fi
if [ -f "$RDC" ]; then if [ -f "$RDC" ]; then
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || : { xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
(( rc != 1 )) && error "Failed to unxz $RDC, reason $rc" && exit 91 (( rc != 1 )) && error "Failed to unxz $RDC on $FS, reason $rc" && exit 91
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || : { (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
if (( rc != 0 )); then if (( rc != 0 )); then
ROOT="N" ROOT="N"
{ (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || : { (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || :
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92 (( rc != 0 )) && error "Failed to extract $RDC on $FS, reason $rc" && exit 92
fi fi
rm -rf /run/extract && mkdir -p /run/extract rm -rf /run/extract && mkdir -p /run/extract
@@ -175,23 +203,33 @@ fi
rm -rf "$TMP" && mkdir -p "$TMP" rm -rf "$TMP" && mkdir -p "$TMP"
info "Install: Downloading $BASE.pat..." info "Install: Downloading $BASE.pat..."
html "Install: Downloading DSM from Synology..."
MSG="Downloading DSM..."
PRG="Downloading DSM ([P])..."
html "$MSG"
PAT="/$BASE.pat" PAT="/$BASE.pat"
rm -f "$PAT" rm -f "$PAT"
SIZE=0
[[ "$URL" == *"DSM_VirtualDSM_69057.pat" ]] && SIZE=363837333
if [[ "$URL" == "file://"* ]]; then if [[ "$URL" == "file://"* ]]; then
cp "${URL:7}" "$PAT" cp "${URL:7}" "$PAT"
else else
{ wget "$URL" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || : /run/progress.sh "$PAT" "$SIZE" "$PRG" &
(( rc != 0 )) && error "Failed to download $URL, reason: $rc" && exit 69
{ wget "$URL" -O "$PAT" -q --no-check-certificate --timeout=10 --show-progress "$PROGRESS"; rc=$?; } || :
fKill "progress.sh"
(( rc != 0 )) && error "Failed to download $URL , reason: $rc" && exit 69
fi fi
[ ! -f "$PAT" ] && error "Failed to download $URL" && exit 69 [ ! -s "$PAT" ] && error "Failed to download $URL" && exit 69
SIZE=$(stat -c%s "$PAT") SIZE=$(stat -c%s "$PAT")
@@ -228,7 +266,7 @@ MSG="Preparing system partition..."
info "Install: $MSG" && html "$MSG" info "Install: $MSG" && html "$MSG"
BOOT=$(find "$TMP" -name "*.bin.zip") BOOT=$(find "$TMP" -name "*.bin.zip")
[ ! -f "$BOOT" ] && error "The PAT file contains no boot image." && exit 67 [ ! -s "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
BOOT=$(echo "$BOOT" | head -c -5) BOOT=$(echo "$BOOT" | head -c -5)
unzip -q -o "$BOOT".zip -d "$TMP" unzip -q -o "$BOOT".zip -d "$TMP"
@@ -249,11 +287,11 @@ if ! touch "$SYSTEM"; then
error "Could not create file $SYSTEM for the system disk." && exit 98 error "Could not create file $SYSTEM for the system disk." && exit 98
fi fi
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then if [[ "${FS,,}" == "btrfs" ]]; then
{ chattr +C "$SYSTEM"; } || : { chattr +C "$SYSTEM"; } || :
FA=$(lsattr "$SYSTEM") FA=$(lsattr "$SYSTEM")
if [[ "$FA" != *"C"* ]]; then if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem (returned $FA)" error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem."
fi fi
fi fi
@@ -289,15 +327,15 @@ IDB="$TMP/indexdb"
PKG="$TMP/packages" PKG="$TMP/packages"
HDP="$TMP/synohdpack_img" HDP="$TMP/synohdpack_img"
[ ! -f "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64 [ ! -s "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
mv "$HDA.tgz" "$HDA.txz" mv "$HDA.tgz" "$HDA.txz"
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/" [ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"* rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
[ -f "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/" [ -s "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/"
if [ -f "$IDB.txz" ]; then if [ -s "$IDB.txz" ]; then
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb/" INDEX_DB="$MOUNT/usr/syno/synoman/indexdb/"
mkdir -p "$INDEX_DB" mkdir -p "$INDEX_DB"
tar xpfJ "$IDB.txz" --absolute-names -C "$INDEX_DB" tar xpfJ "$IDB.txz" --absolute-names -C "$INDEX_DB"

View File

@@ -3,8 +3,10 @@ set -Eeuo pipefail
# Docker environment variables # Docker environment variables
: "${MAC:=""}"
: "${DHCP:="N"}" : "${DHCP:="N"}"
: "${MAC:="02:11:32:AA:BB:CC"}" : "${NETWORK:="Y"}"
: "${HOST_PORTS:=""}"
: "${VM_NET_DEV:=""}" : "${VM_NET_DEV:=""}"
: "${VM_NET_TAP:="dsm"}" : "${VM_NET_TAP:="dsm"}"
@@ -23,17 +25,23 @@ ADD_ERR="Please add the following setting to your container:"
configureDHCP() { configureDHCP() {
# Create a macvtap network for the VM guest # Create the necessary file structure for /dev/vhost-net
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
fi
# Create a macvtap network for the VM guest
{ ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge ; rc=$?; } || : { ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge ; rc=$?; } || :
if (( rc != 0 )); then if (( rc != 0 )); then
error "Cannot create macvtap interface. Please make sure the network type is 'macvlan' and not 'ipvlan'," error "Cannot create macvtap interface. Please make sure that the network type is 'macvlan' and not 'ipvlan',"
error "and that the NET_ADMIN capability has been added to the container: --cap-add NET_ADMIN" && exit 16 error "that your kernel is recent (>4) and supports it, and that the container has the NET_ADMIN capability set." && exit 16
fi fi
while ! ip link set "$VM_NET_TAP" up; do while ! ip link set "$VM_NET_TAP" up; do
info "Waiting for address to become available..." info "Waiting for MAC address $VM_NET_MAC to become available..."
sleep 2 sleep 2
done done
@@ -80,16 +88,37 @@ configureDNS() {
# Set DNS server and gateway # Set DNS server and gateway
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1" DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
# Add DNS entry for container
DNSMASQ_OPTS="$DNSMASQ_OPTS --address=/host.lan/${VM_NET_IP%.*}.1"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
[[ "$DEBUG" == [Yy1]* ]] && set -x [[ "$DEBUG" == [Yy1]* ]] && set -x
$DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
error "Failed to start dnsmasq, reason: $?" && exit 29
fi
{ set +x; } 2>/dev/null { set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo [[ "$DEBUG" == [Yy1]* ]] && echo
return 0 return 0
} }
getPorts() {
local list=$1
[ -z "$list" ] && echo "" && return 0
if [[ "$list" != *","* ]]; then
echo " ! --dport $list"
else
echo " -m multiport ! --dports $list"
fi
return 0
}
configureNAT() { configureNAT() {
# Create the necessary file structure for /dev/net/tun # Create the necessary file structure for /dev/net/tun
@@ -101,21 +130,23 @@ configureNAT() {
fi fi
if [ ! -c /dev/net/tun ]; then if [ ! -c /dev/net/tun ]; then
error "TUN device missing. $ADD_ERR --cap-add NET_ADMIN" && exit 25 error "TUN device missing. $ADD_ERR --device /dev/net/tun --cap-add NET_ADMIN" && exit 25
fi fi
# Check port forwarding flag # Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 ; rc=$?; } || : { sysctl -w net.ipv4.ip_forward=1 > /dev/null; rc=$?; } || :
if (( rc != 0 )); then if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24 error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
fi fi
fi fi
local tables="The 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
local tuntap="The 'tun' kernel module is not available. Try this command: 'sudo modprobe tun' or run the container with 'privileged: true'."
# Create a bridge with a static IP for the VM guest # Create a bridge with a static IP for the VM guest
VM_NET_IP='20.20.20.21' VM_NET_IP='20.20.20.21'
[[ "$DEBUG" == [Yy1]* ]] && set -x
{ ip link add dev dockerbridge type bridge ; rc=$?; } || : { ip link add dev dockerbridge type bridge ; rc=$?; } || :
@@ -126,15 +157,17 @@ configureNAT() {
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
while ! ip link set dockerbridge up; do while ! ip link set dockerbridge up; do
info "Waiting for address to become available..." info "Waiting for IP address to become available..."
sleep 2 sleep 2
done done
# QEMU Works with taps, set tap to the bridge created # QEMU Works with taps, set tap to the bridge created
ip tuntap add dev "$VM_NET_TAP" mode tap if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then
error "$tuntap" && exit 31
fi
while ! ip link set "$VM_NET_TAP" up promisc on; do while ! ip link set "$VM_NET_TAP" up promisc on; do
info "Waiting for tap to become available..." info "Waiting for TAP to become available..."
sleep 2 sleep 2
done done
@@ -144,22 +177,27 @@ configureNAT() {
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE exclude=$(getPorts "$HOST_PORTS")
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp -j DNAT --to "$VM_NET_IP"
if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE; then
error "$tables" && exit 30
fi
# shellcheck disable=SC2086
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$VM_NET_IP"
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP" iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
if (( KERNEL > 4 )); then if (( KERNEL > 4 )); then
# Hack for guest VMs complaining about "bad udp checksums in 5 packets" # Hack for guest VMs complaining about "bad udp checksums in 5 packets"
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill || true iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill > /dev/null 2>&1 || true
fi fi
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0" NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || : if [ -c /dev/vhost-net ]; then
(( rc == 0 )) && NET_OPTS="$NET_OPTS,vhost=on,vhostfd=40" { exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS="$NET_OPTS,vhost=on,vhostfd=40"
fi
configureDNS configureDNS
@@ -168,22 +206,28 @@ configureNAT() {
closeNetwork() { closeNetwork() {
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" == [Yy1]* ]]; then if [[ "$DHCP" == [Yy1]* ]]; then
# Shutdown nginx # Shutdown nginx
nginx -s stop 2> /dev/null nginx -s stop 2> /dev/null
fWait "nginx" fWait "nginx"
fi
[[ "$NETWORK" != [Yy1]* ]] && return 0
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" == [Yy1]* ]]; then
ip link set "$VM_NET_TAP" down || true ip link set "$VM_NET_TAP" down || true
ip link delete "$VM_NET_TAP" || true ip link delete "$VM_NET_TAP" || true
else else
local pid="/var/run/dnsmasq.pid" local pid="/var/run/dnsmasq.pid"
[ -f "$pid" ] && pKill "$(<"$pid")" [ -s "$pid" ] && pKill "$(<"$pid")"
ip link set "$VM_NET_TAP" down promisc off || true ip link set "$VM_NET_TAP" down promisc off || true
ip link delete "$VM_NET_TAP" || true ip link delete "$VM_NET_TAP" || true
@@ -196,6 +240,23 @@ closeNetwork() {
return 0 return 0
} }
checkOS() {
local name
local os=""
name=$(uname -a)
[[ "${name,,}" == *"darwin"* ]] && os="MacOS"
[[ "${name,,}" == *"microsoft"* ]] && os="Windows"
if [ -n "$os" ]; then
error "You are using Docker Desktop for $os which does not support macvlan, please revert to bridge networking!"
return 1
fi
return 0
}
getInfo() { getInfo() {
if [ -z "$VM_NET_DEV" ]; then if [ -z "$VM_NET_DEV" ]; then
@@ -209,14 +270,26 @@ getInfo() {
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27 error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
fi fi
if [ -z "$VM_NET_MAC" ]; then
local file="$STORAGE/dsm.mac"
[ -s "$file" ] && VM_NET_MAC=$(<"$file")
if [ -z "$VM_NET_MAC" ]; then
# Generate MAC address based on Docker container ID in hostname
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
echo "${VM_NET_MAC^^}" > "$file"
fi
fi
VM_NET_MAC="${VM_NET_MAC^^}"
VM_NET_MAC="${VM_NET_MAC//-/:}" VM_NET_MAC="${VM_NET_MAC//-/:}"
if [[ ${#VM_NET_MAC} == 12 ]]; then if [[ ${#VM_NET_MAC} == 12 ]]; then
m="$VM_NET_MAC" m="$VM_NET_MAC"
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}" VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi fi
if [[ ${#VM_NET_MAC} != 17 ]]; then if [[ ${#VM_NET_MAC} != 17 ]]; then
error "Invalid mac address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28 error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
fi fi
GATEWAY=$(ip r | grep default | awk '{print $3}') GATEWAY=$(ip r | grep default | awk '{print $3}')
@@ -230,25 +303,30 @@ getInfo() {
# Configure Network # Configure Network
# ###################################### # ######################################
if [ ! -c /dev/vhost-net ]; then if [[ "$NETWORK" != [Yy1]* ]]; then
if mknod /dev/vhost-net c 10 238; then NET_OPTS=""
chmod 660 /dev/vhost-net return 0
fi
fi fi
getInfo getInfo
html "Initializing network..." html "Initializing network..."
if [[ "$DEBUG" == [Yy1]* ]]; then if [[ "$DEBUG" == [Yy1]* ]]; then
info "Container IP is $IP with gateway $GATEWAY on interface $VM_NET_DEV" && echo info "Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC"
[ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf
echo
fi
if [[ "$IP" == "172.17."* ]]; then
warn "your container IP starts with 172.17.* which will cause conflicts when you install the Container Manager package inside DSM!"
fi fi
if [[ "$DHCP" == [Yy1]* ]]; then if [[ "$DHCP" == [Yy1]* ]]; then
! checkOS && exit 19
if [[ "$GATEWAY" == "172."* ]]; then if [[ "$GATEWAY" == "172."* ]]; then
if [[ "$DEBUG" != [Yy1]* ]]; then warn "your gateway IP starts with 172.* which is often a sign that you are not on a macvlan network (required for DHCP)!"
error "You can only enable DHCP while the container is on a macvlan network!" && exit 26
fi
fi fi
# Configuration for DHCP IP # Configuration for DHCP IP
@@ -259,6 +337,10 @@ if [[ "$DHCP" == [Yy1]* ]]; then
else else
if [[ "$GATEWAY" != "172."* ]]; then
! checkOS && exit 19
fi
# Shutdown nginx # Shutdown nginx
nginx -s stop 2> /dev/null nginx -s stop 2> /dev/null
fWait "nginx" fWait "nginx"

View File

@@ -10,10 +10,11 @@ API_HOST="127.0.0.1:2210"
QEMU_TERM="" QEMU_TERM=""
QEMU_PORT=7100 QEMU_PORT=7100
QEMU_TIMEOUT=50 QEMU_TIMEOUT=50
QEMU_PID="/run/shm/qemu.pid" QEMU_DIR="/run/shm"
QEMU_LOG="/run/shm/qemu.log" QEMU_PID="$QEMU_DIR/qemu.pid"
QEMU_OUT="/run/shm/qemu.out" QEMU_LOG="$QEMU_DIR/qemu.log"
QEMU_END="/run/shm/qemu.end" QEMU_OUT="$QEMU_DIR/qemu.out"
QEMU_END="$QEMU_DIR/qemu.end"
if [[ "$KVM" == [Nn]* ]]; then if [[ "$KVM" == [Nn]* ]]; then
API_TIMEOUT=$(( API_TIMEOUT*2 )) API_TIMEOUT=$(( API_TIMEOUT*2 ))
@@ -34,7 +35,9 @@ finish() {
local pid local pid
local reason=$1 local reason=$1
if [ -f "$QEMU_PID" ]; then touch "$QEMU_END"
if [ -s "$QEMU_PID" ]; then
pid=$(<"$QEMU_PID") pid=$(<"$QEMU_PID")
echo && error "Forcefully terminating QEMU process, reason: $reason..." echo && error "Forcefully terminating QEMU process, reason: $reason..."
@@ -43,7 +46,7 @@ finish() {
while isAlive "$pid"; do while isAlive "$pid"; do
sleep 1 sleep 1
# Workaround for zombie pid # Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break [ ! -s "$QEMU_PID" ] && break
done done
fi fi
@@ -62,7 +65,7 @@ terminal() {
local dev="" local dev=""
if [ -f "$QEMU_OUT" ]; then if [ -s "$QEMU_OUT" ]; then
local msg local msg
msg=$(<"$QEMU_OUT") msg=$(<"$QEMU_OUT")
@@ -98,7 +101,6 @@ terminal() {
_graceful_shutdown() { _graceful_shutdown() {
local cnt=0
local code=$? local code=$?
local pid url response local pid url response
@@ -112,7 +114,7 @@ _graceful_shutdown() {
touch "$QEMU_END" touch "$QEMU_END"
echo && info "Received $1 signal, sending shutdown command..." echo && info "Received $1 signal, sending shutdown command..."
if [ ! -f "$QEMU_PID" ]; then if [ ! -s "$QEMU_PID" ]; then
echo && error "QEMU PID file does not exist?" echo && error "QEMU PID file does not exist?"
finish "$code" && return "$code" finish "$code" && return "$code"
fi fi
@@ -144,6 +146,8 @@ _graceful_shutdown() {
fi fi
local cnt=0
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
! isAlive "$pid" && break ! isAlive "$pid" && break
@@ -154,7 +158,7 @@ _graceful_shutdown() {
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)" [[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)"
# Workaround for zombie pid # Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break [ ! -s "$QEMU_PID" ] && break
done done
@@ -167,6 +171,7 @@ _graceful_shutdown() {
MON_OPTS="\ MON_OPTS="\
-pidfile $QEMU_PID \ -pidfile $QEMU_PID \
-name $PROCESS,process=$PROCESS,debug-threads=on \
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay" -monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
if [[ "$CONSOLE" != [Yy]* ]]; then if [[ "$CONSOLE" != [Yy]* ]]; then

View File

@@ -2,6 +2,9 @@
set -Eeuo pipefail set -Eeuo pipefail
: "${DHCP:="N"}" : "${DHCP:="N"}"
: "${NETWORK:="Y"}"
[[ "$NETWORK" != [Yy1]* ]] && exit 0
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n" >&2; } info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n" >&2; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; } error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; }
@@ -18,7 +21,7 @@ resp_err="Guest returned an invalid response:"
curl_err="Failed to connect to guest: curl error" curl_err="Failed to connect to guest: curl error"
jq_err="Failed to parse response from guest: jq error" jq_err="Failed to parse response from guest: jq error"
while [ ! -f "$file" ] while [ ! -s "$file" ]
do do
# Check if not shutting down # Check if not shutting down
@@ -27,7 +30,7 @@ do
sleep 3 sleep 3
[ -f "$shutdown" ] && exit 1 [ -f "$shutdown" ] && exit 1
[ -f "$file" ] && break [ -s "$file" ] && break
# Retrieve network info from guest VM # Retrieve network info from guest VM
{ json=$(curl -m 20 -sk "$url"); rc=$?; } || : { json=$(curl -m 20 -sk "$url"); rc=$?; } || :
@@ -101,3 +104,5 @@ info "-----------------------------------------------------------"
info " You can now login to DSM at $msg" info " You can now login to DSM at $msg"
info "-----------------------------------------------------------" info "-----------------------------------------------------------"
echo "" >&2 echo "" >&2
exit 0

View File

@@ -5,10 +5,11 @@ set -Eeuo pipefail
: "${KVM:="Y"}" : "${KVM:="Y"}"
: "${HOST_CPU:=""}" : "${HOST_CPU:=""}"
: "${CPU_MODEL:="host"}" : "${CPU_FLAGS:=""}"
: "${CPU_FEATURES:="+ssse3,+sse4.1,+sse4.2"}" : "${CPU_MODEL:=""}"
: "${DEF_MODEL:="qemu64"}"
[ "$ARCH" != "amd64" ] && KVM="N" [[ "${ARCH,,}" != "amd64" ]] && KVM="N"
if [[ "$KVM" != [Nn]* ]]; then if [[ "$KVM" != [Nn]* ]]; then
@@ -20,7 +21,8 @@ if [[ "$KVM" != [Nn]* ]]; then
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(no write access)" KVM_ERR="(no write access)"
else else
if ! grep -q -e vmx -e svm /proc/cpuinfo; then flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(vmx/svm disabled)" KVM_ERR="(vmx/svm disabled)"
fi fi
fi fi
@@ -28,39 +30,75 @@ if [[ "$KVM" != [Nn]* ]]; then
if [ -n "$KVM_ERR" ]; then if [ -n "$KVM_ERR" ]; then
KVM="N" KVM="N"
error "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance." if [[ "$OSTYPE" =~ ^darwin ]]; then
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)." warn "you are using MacOS which has no KVM support, this will cause a major loss of performance."
[[ "$DEBUG" != [Yy1]* ]] && exit 88 else
if grep -qi Microsoft /proc/version; then
warn "you are using Windows 10 which has no KVM support, this will cause a major loss of performance."
else
error "KVM acceleration not available $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)."
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi
fi fi
fi fi
if [[ "$KVM" != [Nn]* ]]; then if [[ "$KVM" != [Nn]* ]]; then
KVM_OPTS=",accel=kvm -enable-kvm" CPU_FEATURES="kvm=on,l3-cache=on"
KVM_OPTS=",accel=kvm -enable-kvm -global kvm-pit.lost_tick_policy=discard"
if ! grep -qE '^flags.* (sse4_2)' /proc/cpuinfo; then if ! grep -qw "sse4_2" <<< "$flags"; then
error "Your host CPU does not have the SSE4.2 instruction set that Virtual DSM requires to boot." info "Your CPU does not have the SSE4 instruction set that Virtual DSM requires, it will be emulated..."
error "Disable KVM by setting KVM=N to emulate a compatible CPU, at the cost of performance." [ -z "$CPU_MODEL" ] && CPU_MODEL="$DEF_MODEL"
[[ "$DEBUG" != [Yy1]* ]] && exit 89 CPU_FEATURES="$CPU_FEATURES,+ssse3,+sse4.1,+sse4.2"
fi
if [ -z "$CPU_MODEL" ]; then
CPU_MODEL="host"
CPU_FEATURES="$CPU_FEATURES,migratable=no"
fi fi
else else
KVM_OPTS="" KVM_OPTS=""
CPU_FEATURES="l3-cache=on"
if [[ "$CPU_MODEL" == "host"* ]]; then if [[ "$ARCH" == "amd64" ]]; then
KVM_OPTS=" -accel tcg,thread=multi"
fi
if [ -z "$CPU_MODEL" ]; then
if [[ "$ARCH" == "amd64" ]]; then if [[ "$ARCH" == "amd64" ]]; then
CPU_MODEL="max,$CPU_FEATURES" CPU_MODEL="max"
CPU_FEATURES="$CPU_FEATURES,migratable=no"
else else
CPU_MODEL="qemu64,$CPU_FEATURES" CPU_MODEL="$DEF_MODEL"
fi fi
fi fi
CPU_FEATURES="$CPU_FEATURES,+ssse3,+sse4.1,+sse4.2"
fi
if [ -z "$CPU_FLAGS" ]; then
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES"
fi
else
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL,$CPU_FLAGS"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS"
fi
fi fi
if [ -z "$HOST_CPU" ]; then if [ -z "$HOST_CPU" ]; then
HOST_CPU=$(lscpu | grep 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g') HOST_CPU=$(lscpu | grep -m 1 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi fi
if [ -n "$HOST_CPU" ]; then if [ -n "$HOST_CPU" ]; then

38
src/progress.sh Normal file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -Eeuo pipefail
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
file="$1"
total="$2"
body=$(escape "$3")
info="/run/shm/msg.html"
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
while true
do
if [ -s "$file" ]; then
bytes=$(du -sb "$file" | cut -f1)
if (( bytes > 1000 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]]; then
size=$(numfmt --to=iec --suffix=B "$bytes" | sed -r 's/([A-Z])/ \1/')
else
size=$(printf '%.1f\n' "$((bytes*100*100/total))e-2")
size="$size%"
fi
echo "${body//(\[P\])/($size)}"> "$info"
fi
fi
sleep 1 & wait $!
done

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n"; } info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; } error () { printf "%b%s%b" "\E[1;31m " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: $1" "\E[0m\n" >&2; } warn () { printf "%b%s%b" "\E[1;31m " "Warning: ${1:-}" "\E[0m\n" >&2; }
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
@@ -12,7 +12,6 @@ trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
echo " Starting $APP for Docker v$(</run/version)..." echo " Starting $APP for Docker v$(</run/version)..."
echo " For support visit $SUPPORT" echo " For support visit $SUPPORT"
echo
# Docker environment variables # Docker environment variables
@@ -28,17 +27,30 @@ echo
# Helper variables # Helper variables
PROCESS="${APP,,}"
PROCESS="${PROCESS// /-}"
STORAGE="/storage" STORAGE="/storage"
INFO="/dev/shm/msg.html" INFO="/run/shm/msg.html"
PAGE="/run/shm/index.html" PAGE="/run/shm/index.html"
TEMPLATE="/var/www/index.html" TEMPLATE="/var/www/index.html"
FOOTER1="$APP for Docker v$(</run/version)" FOOTER1="$APP for Docker v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>" FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
KERNEL=$(uname -r | cut -b 1) SYS=$(uname -r)
MINOR=$(uname -r | cut -d '.' -f2) HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1)
MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture) ARCH=$(dpkg --print-architecture)
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1) CPU=$(lscpu | grep -m 1 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
# Check system
if [ ! -d "/dev/shm" ]; then
error "Directory /dev/shm not found!" && exit 14
else
[ ! -d "/run/shm" ] && ln -s /dev/shm /run/shm
fi
# Check folder # Check folder
@@ -46,12 +58,37 @@ if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13 error "Storage folder ($STORAGE) not found!" && exit 13
fi fi
if [ ! -d "/run/shm" ]; then # Check filesystem
if [ -d "/dev/shm" ]; then FS=$(stat -f -c %T "$STORAGE")
ln -s /dev/shm /run/shm
else if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
error "Folder /dev/shm not found!" && exit 14 DISK_IO="threads"
fi DISK_CACHE="writeback"
fi
# Read memory
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
RAM_WANTED=$(numfmt --from=iec "$RAM_SIZE")
AVAIL_GB=$(( (RAM_AVAIL + 1073741823)/1073741824 ))
TOTAL_GB=$(( (RAM_TOTAL + 1073741823)/1073741824 ))
WANTED_GB=$(( (RAM_WANTED + 1073741823)/1073741824 ))
# Print system info
SYS="${SYS/-generic/}"
FS="${FS/ext2\/ext3/ext4}"
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
echo " CPU: ${CPU} | RAM: $AVAIL_GB/$TOTAL_GB GB | DISK: $SPACE_GB GB (${FS}) | HOST: ${SYS}..."
echo
# Check memory
if (( (RAM_WANTED + 500000000) > RAM_AVAIL )); then
error "Your configured RAM_SIZE of $WANTED_GB GB is higher than the $AVAIL_GB GB of memory available, please set a lower value."
exit 17
fi fi
# Cleanup files # Cleanup files

View File

@@ -9,6 +9,21 @@ set -Eeuo pipefail
: "${HOST_MODEL:=""}" : "${HOST_MODEL:=""}"
: "${GUEST_SERIAL:=""}" : "${GUEST_SERIAL:=""}"
if [ -n "$HOST_MAC" ]; then
HOST_MAC="${HOST_MAC//-/:}"
if [[ ${#HOST_MAC} == 12 ]]; then
m="$HOST_MAC"
HOST_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#HOST_MAC} != 17 ]]; then
error "Invalid HOST_MAC address: '$HOST_MAC', should be 12 or 17 digits long!" && exit 28
fi
fi
HOST_ARGS=() HOST_ARGS=()
HOST_ARGS+=("-cpu=$CPU_CORES") HOST_ARGS+=("-cpu=$CPU_CORES")
HOST_ARGS+=("-cpu_arch=$HOST_CPU") HOST_ARGS+=("-cpu_arch=$HOST_CPU")

View File

@@ -1,7 +1,14 @@
body { body {
color: white; color: white;
background-color: #125bdb; background-color: #125bdb;
font-family: Verdana, Arial, sans-serif; font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: Verdana, Geneva, sans-serif;
}
#info {
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.25);
} }
#content { #content {
@@ -17,6 +24,7 @@ footer {
height: 40px; height: 40px;
text-align: center; text-align: center;
color: #0c8aeb; color: #0c8aeb;
text-shadow: 0 0 1px #0c8aeb;
} }
#empty { #empty {
@@ -33,8 +41,13 @@ a:visited {
footer a:link, footer a:link,
footer a:visited, footer a:visited,
footer a:active { color: #0c8aeb; } footer a:active {
footer a:hover { color: #73e6ff; } color: #0c8aeb;
}
footer a:hover {
color: #73e6ff;
}
.loading:after { .loading:after {
content: " ."; content: " .";

View File

@@ -1,8 +1,6 @@
server { server {
listen 80; listen 80;
listen [::]:80;
listen 5000 default_server; listen 5000 default_server;
listen [::]:5000 default_server;
autoindex on; autoindex on;
tcp_nodelay on; tcp_nodelay on;