Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brasofilo/3101cd95bf218b63569319f6ab44a464 to your computer and use it in GitHub Desktop.
Save brasofilo/3101cd95bf218b63569319f6ab44a464 to your computer and use it in GitHub Desktop.
VPS Nextcloud Installation - Single Node Swarm, Portainer, Traefik LB
version: '3.7'
services:
mysql:
image: mariadb:10.3.5
networks:
- default
environment:
MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
MYSQL_DATABASE: $DB_NAME
MYSQL_USER: $DB_USER
MYSQL_PASSWORD: $DB_PASSWORD
TZ: "Europe/Berlin"
volumes:
- /swarm/volumes/nextcloud/mysql:/var/lib/mysql
logging:
options:
max-size: '100m'
max-file: '10'
driver: json-file
deploy:
resources:
limits:
cpus: '1'
memory: 1000M
mode: replicated
nextcloud:
image: nextcloud:18
restart: always
volumes:
- /swarm/volumes/nextcloud/data:/var/www/html/data
- /swarm/volumes/nextcloud/custom_apps:/var/www/html/custom_apps
- /swarm/volumes/nextcloud/themes:/var/www/html/themes
- /swarm/volumes/nextcloud/config:/var/www/html/config
networks:
- default
- Traefik_traefik-net
deploy:
labels:
- 'traefik.port=80'
- 'traefik.docker.network=Traefik_traefik-net'
- 'traefik.frontend.redirect.permanent=true'
- 'traefik.frontend.redirect.regex=cloud.[YOUR_DOMAIN]/.well-known/(cal|card)dav'
- 'traefik.frontend.redirect.replacement=cloud.[YOUR_DOMAIN].de/remote.php/dav/'
- 'traefik.frontend.rule=Host:cloud.[YOUR_DOMAIN]'
mode: replicated
update_config:
order: start-first
networks:
Traefik_traefik-net:
external: true
version: '3.7'
services:
portainer:
image: portainer/portainer:latest
ports:
- "9000:9000"
networks:
- portainer-net
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /swarm/volumes/portainer/data:/data
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
command: -H unix:///var/run/docker.sock
networks:
portainer-net:
version: '3.7'
services:
traefik:
image: traefik:1.7
command:
- "--docker"
- "--docker.swarmmode"
ports:
- mode: host
protocol: tcp
published: 80
target: 80
- mode: host
protocol: tcp
published: 443
target: 443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /swarm/volumes/traefik/traefik.toml:/etc/traefik/traefik.toml
- /swarm/volumes/traefik/acme.json:/opt/acme.json
- /swarm/volumes/traefik/logs/:/opt/logs/
logging:
options:
max-size: '100m'
max-file: '10'
driver: json-file
networks:
traefik-net:
aliases:
- traefik_proxy
logrotate:
image: sequenceiq/logrotate
volumes:
- type: bind
source: /swarm/volumes/traefik/logs/
target: /opt/logs/
environment:
LOGROTATE_LOGFILES: /opt/logs/*.json
LOGROTATE_FILESIZE: 20M
LOGROTATE_FILENUM: 20000
CRON_EXPR: "0 * * * *"
logging:
options:
max-size: '2m'
max-file: '1'
driver: json-file
networks:
- traefik-net
networks:
traefik-net:
logLevel = "INFO"
InsecureSkipVerify = true
defaultEntryPoints = ["http","https"]
[accessLog]
filePath = "/opt/logs/access.json"
format = "json"
[accessLog.fields]
defaultMode = "drop"
[accessLog.fields.names]
"BackendName" = "keep"
"RequestAddr" = "keep"
"RequestPath" = "keep"
"RequestMethod" = "keep"
"OriginStatus" = "keep"
"OriginContentSize" = "keep"
"ClientHost" = "keep"
[accessLog.fields.headers]
defaultMode = "drop"
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
minVersion = "VersionTLS12"
[docker]
watch = true
domain = "docker.localhost"
swarmMode = true
network = "Traefik_traefik-net"
[acme]
email = "cert@[YOUR_PRIVATE_DOMAIN]"
storage = "/opt/acme.json"
entryPoint = "https"
acmeLogging=true
# add as many entries below, for which you want free letsencrypt certificates.
# The given domain need to be publicly accacable and have a DNS entry pointed to your VPS.
[[acme.domains]]
main = "cloud.yourdomain.com"
[[acme.domains]]
main = "maybeanothersubdomain.yourdomain.com"
[acme.httpChallenge]
entryPoint = "http"

VPS - first setup

(change placeholder, noticeable by sqare brackets)

1. Get lastest Updates

You want to start up-to-date:

apt update
apt upgrade
apt dist-upgrade

2. add user, change passwords

Add a user for security, so you dont have to work with the root user (optional)

# add new user and add it to the sudo group
adduser [YOUR_USERNAME]
usermod -aG sudo [YOUR_USERNAME]
# Change root password
passwd

# logout and log back in with your new user
exit

3. generate SSH Keys

Generate SSH keys, so you can authenticate yourself with a key instead of a password. Improves your security, as you can disable password authentication completely.

Execute this on your VPS:

ssh-keygen

Execute this on your local command line:

ssh-copy-id [YOUR_USERNAME]@[YOUR_VPS_IP]

4. disable password authentication

sudo nano /etc/ssh/sshd_config
# uncomment following lines in the file and add your username from step 2:

PermitRootLogin no
PasswordAuthentication no
AllowUsers [YOUR_USERNAME]
Protocol 2

5. set hostname

Yout probably want to set your own hostname for the machine. Chooce what you like:

sudo hostnamectl set-hostname [YOUR_NEW_HOSTNAME]

6. install requiered packages

This is my own set of packages, you can change your list as you like:

sudo apt install tmux tree htop traceroute nmap bc colordiff net-tools \
  apt-transport-https ca-certificates curl software-properties-common git \
  cifs-utils gcc ncdu jq make iperf sqlite3 php7.2-cli ufw gnupg-agent moreutils

7. enable a firewall (we use ufw)

sudo ufw allow 22/tcp
sudo ufw show added
sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 9000/tcp
sudo ufw allow 443/tcp

8. install Docker

# add repository gpg key 
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# add repository
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# install docker tools
sudo apt install docker-ce docker-ce-cli containerd.io

# add docker user, add your user to docker group (from step 2)
sudo groupadd docker
sudo usermod -aG docker [YOUR_USERNAME]

9. add mount directory

Some of docker containers will need permanent storage. I like grouping all mount directories in their own subdirectory. Create them:

sudo mkdir -p /swarm/volumes
sudo chown -R [YOUR_USERNAME]:[YOUR_USERNAME] /swarm
# make subdirectories for your first docker services:
mkdir -p  /swarm/volumes/portainer/data
mkdir -p  /swarm/volumes/traefik/logs
mkdir -p  /swarm/volumes/nextcloud/{config,custom_apps,data,themes,mysql}

10. init docker swarm

you want to install a single node docker swarm:

docker swarm init

11. deploy portainer

for easier deployment of your docker services, you can install portainer:

cd /swarm/volumes/portainer
nano stack-compose.yml

In the opening editor (nano), copy the content of the gist file services_portainer_stack-compose.yml and save the file.

after that, run:

docker stack deploy --compose-file stack-compose.yml Portainer

After the stack is deployed, you should be able to open portainer over http://[YOUR_VPS_IP_OR_DOMAIN]:9000 and go through installation.

12. deploy traefik

Add the traefik configuration file:

cd /swarm/volumes/traefik
nano traefik.toml

In the opening editor (nano), copy the content of the gist file services_traefik_traefik.toml and save the file.

Now, deploy the traefik load-balancer over the portainer interface: go to the portainer web interface (from step 11), go to "stacks" and click "add new stack". Name the Stack "Traefik" and copy the content of services_traefik_stack-compose.yml into the editor field. Wait for it to download the docker images and to start.

13. deploy Nextcloud

last, deploy Nextcloud over the portainer web interface: go to the portainer web interface (from step 11), go to "stacks" and click "add new stack". Name the Stack "Nextcloud" and copy the content of services_nextcloud_stack-compose.yml into the editor field. Below the editor, click 4x on the grey button "add environment variable". You need to add following variables, listed with " key - value ":

key value
DB_ROOT_PASSWORD [GENERATE_A_STRONG_PASSWORD_AND_PASTE_IT_HERE]
DB_PASSWORD [GENERATE_ANOTHER_STRONG_PASSWORD_AND_PASTE_IT_HERE]
DB_NAME nextcloud
DB_USER nextcloud

then, click "deploy".

Wait for the services to start, this could take a moment.

After that, you should be able to navigate to https://cloud.yourdomain.com and go through nextcloud installation steps. Below the admin credentials, expand "storage and database" to select your database as "mysql/mariadb": Use your values from the previously set environment variables. Replace the database-host "localhost" with "mysql".

14. all done, start clouding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment