Setting Up Docker
Docker Compose Pre-requisites
- Make sure Docker and Docker compose is installed, if not use this script
- Creating required folders to use this setup as template for future changes.
1
|
mkdir -p ${HOME}/docker/traefik/letsencrypt
|
- Create required files
1
2
3
4
|
touch ${HOME}/docker/docker-compose.yml
touch ${HOME}/docker/.env
touch ${HOME}/docker/traefik/letsencrypt/acme.json
sudo chmod 600 ${HOME}/docker/traefik/letsencrypt/acme.json
|
- create network
1
|
docker network create traefik_webgateway
|
SetUp Traefik
- Update
${HOME}/docker/.env
file
1
2
3
4
5
6
|
TZ=Europe/Paris
LETSENCRYPT_PATH=/root/docker/traefik/letsencrypt
# BW_CONFIG
BW_CONFIG=/root/docker/bitwarden/data
BW_ADMIN_TOKEN=YOUR_TOKEN_GENERATED_USING_openssl
|
Paste the output of openssl rand -base64 48
for the value of BW_ADMIN_TOKEN
- Update
${HOME}/docker/docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
version: "3.3"
networks:
traefik:
external:
name: traefik_webgateway
services:
traefik:
image: "traefik:v2.3"
container_name: traefik
restart: always
command:
- --entrypoints.web.address=:80
- --providers.docker.exposedByDefault=false
# - --log.level=DEBUG
# - --api.insecure # Don't do that in production
- --api
- --entrypoints.websecure.address=:443
- --certificatesresolvers.myresolver.acme.httpchallenge=true
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
# - --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesresolvers.myresolver.acme.email=YOUR_EMAIL
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
# - "8081:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "${LETSENCRYPT_PATH}:/letsencrypt"
labels:
#### set core configs
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`YOUR_DOMAIN`)" # && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.traefik.service=api@internal"
# - "traefik.http.routers.traefik.entrypoints=web"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=myresolver"
- "traefik.http.routers.traefik.middlewares=authtraefik"
- "traefik.http.middlewares.authtraefik.basicauth.users=user:$$apr1$$q8eZFHjF$$Fvmkk//V6Btlaf2i/ju5n/" # user/password
# global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
networks:
- traefik
|
BitWarden Setup
Pre-requisites
- Create required folders
1
|
mkdir -p ${HOME}/docker/bitwarden
|
Setup Bitwarden docker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
version: "3.3"
services:
bitwarden:
image: bitwardenrs/server:latest
container_name: bitwarden
restart: always
volumes:
- ${BW_CONFIG}:/data
environment:
- ADMIN_TOKEN=${BW_ADMIN_TOKEN}
- WEBSOCKET_ENABLED=true
networks:
- traefik
labels:
- traefik.enable=true
# Entry Point for https
- traefik.http.routers.bwd.rule=Host(`YOUR_DOMAIN`)
- traefik.http.routers.bwd.service=bitwarden-service
- traefik.http.services.bitwarden-service.loadbalancer.server.port=80
- "traefik.http.routers.bwd.entrypoints=websecure"
- "traefik.http.routers.bwd.tls=true"
- "traefik.http.routers.bwd.tls.certresolver=myresolver"
# websocket
- traefik.http.routers.bwd-ws.rule=Host(`YOUR_DOMAIN`) && Path(`/notifications/hub`)
- traefik.http.routers.bwd-ws.service=bitwarden-ws
- traefik.http.services.bitwarden-ws.loadbalancer.server.port=3012
- "traefik.http.routers.bwd-ws.entrypoints=websecure"
- "traefik.http.routers.bwd-ws.tls=true"
- "traefik.http.routers.bwd-ws.tls.certresolver=myresolver"
# middlewares
- "traefik.http.middlewares.bwd-ws=bw-stripPrefix"
- "traefik.http.middlewares.bw-stripPrefix.stripprefix.prefixes=/notifications/hub"
- "traefik.http.middlewares.bw-stripPrefix.stripprefix.forceSlash=false"
|
Bitwarden Backup
Pre-requisites
- Create required folders and files
1
2
3
4
5
|
mkdir -p ${HOME}/docker/bitwarden/backup/archives
mkdir -p ${HOME}/docker/bitwarden/backup/logs
touch ${HOME}/docker/bitwarden/backup/backup.conf
touch ${HOME}/docker/bitwarden/backup/backup.sh
chmod +x ${HOME}/docker/bitwarden/backup/backup.sh
|
- Update
${HOME}/docker/bitwarden/backup/backup.sh
with the following content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#!/bin/bash
set -ex
# Use the value of the corresponding environment variable, or the
# default if none exists.
: ${BITWARDEN_ROOT:="${HOME}/docker/bitwarden"}
: ${SQLITE3:="/usr/bin/sqlite3"}
: ${RCLONE:="/usr/bin/rclone"}
DATA_DIR="data"
BACKUP_ROOT="${BITWARDEN_ROOT}/backup"
BACKUP_DIR_NAME="bitwarden-$(date '+%Y%m%d-%H%M')"
BACKUP_DIR_PATH="${BACKUP_ROOT}/${BACKUP_DIR_NAME}"
BACKUP_FILE_DIR="archives"
BACKUP_FILE_NAME="${BACKUP_DIR_NAME}.tar.xz"
BACKUP_FILE_PATH="${BACKUP_ROOT}/${BACKUP_FILE_DIR}/${BACKUP_FILE_NAME}"
DB_FILE="db.sqlite3"
source "${BACKUP_ROOT}"/backup.conf
cd "${BITWARDEN_ROOT}"
mkdir -p "${BACKUP_DIR_PATH}"
# Back up the database using the Online Backup API (https://www.sqlite.org/backup.html)
# as implemented in the SQLite CLI. However, if a call to sqlite3_backup_step() returns
# one of the transient errors SQLITE_BUSY or SQLITE_LOCKED, the CLI doesn't retry the
# backup step; instead, it simply stops the backup and returns an error. This is unlikely,
# but to minimize the possibility of a failed backup, implement a retry mechanism here.
max_tries=10
tries=0
until ${SQLITE3} "file:${DATA_DIR}/${DB_FILE}?mode=ro" ".backup '${BACKUP_DIR_PATH}/${DB_FILE}'"; do
if (( ++tries >= max_tries )); then
echo "Aborting after ${max_tries} failed backup attempts..."
exit 1
fi
echo "Backup failed. Retry #${tries}..."
rm -f "${BACKUP_DIR_PATH}/${DB_FILE}"
sleep 1
done
sudo cp -a "${DATA_DIR}"/{attachments,config.json,rsa_key.*} "${BACKUP_DIR_PATH}"
tar -cJf "${BACKUP_FILE_PATH}" -C "${BACKUP_ROOT}" "${BACKUP_DIR_NAME}"
rm -rf "${BACKUP_DIR_PATH}"
md5sum "${BACKUP_FILE_PATH}"
sha1sum "${BACKUP_FILE_PATH}"
for dest in "${RCLONE_DESTS[@]}"; do
${RCLONE} -vv sync --exclude .gitignore "${BACKUP_ROOT}/${BACKUP_FILE_DIR}" "${dest}"
done
|
Backup to Google Drive
Install rclone and sq
1
2
|
curl https://rclone.org/install.sh | sudo bash
sudo apt install sqlite3 -y
|
rclone setup
- setup rclone with Google Drive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# rclone config
2021/03/17 15:57:26 NOTICE: Config file "/root/.config/rclone/rclone.conf" not found - using defaults
No remotes found - make a new one
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
15 / Google Drive
\ "drive"
Storage> 15
** See help for drive backend at: https://rclone.org/drive/ **
Google Application Client Id
Setting your own is recommended.
See https://rclone.org/drive/#making-your-own-client-id for how to create your own.
If you leave this blank, it will use an internal key which is low performance.
Enter a string value. Press Enter for the default ("").
client_id> <YOUR_ID>.apps.googleusercontent.com
OAuth Client Secret
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_secret> <YOUR_SECRET>
Scope that rclone should use when requesting access from drive.
Enter a string value. Press Enter for the default ("").
Choose a number from below, or type in your own value
1 / Full access all files, excluding Application Data Folder.
\ "drive"
2 / Read-only access to file metadata and file contents.
\ "drive.readonly"
/ Access to files created by rclone only.
3 | These are visible in the drive website.
| File authorization is revoked when the user deauthorizes the app.
\ "drive.file"
/ Allows read and write access to the Application Data folder.
4 | This is not visible in the drive website.
\ "drive.appfolder"
/ Allows read-only access to file metadata but
5 | does not allow any access to read or download file content.
\ "drive.metadata.readonly"
scope> 3
ID of the root folder
Leave blank normally.
Fill in to access "Computers" folders (see docs), or for rclone to use
a non root folder as its starting point.
Enter a string value. Press Enter for the default ("").
root_folder_id>
Service Account Credentials JSON file path
Leave blank normally.
Needed only if you want use SA instead of interactive login.
Leading `~` will be expanded in the file name as will environment variables such as `${RCLONE_CONFIG_DIR}`.
Enter a string value. Press Enter for the default ("").
service_account_file>
Edit advanced config? (y/n)
y) Yes
n) No (default)
y/n>
Remote config
Use auto config?
* Say Y if not sure
* Say N if you are working on a remote or headless machine
y) Yes (default)
n) No
y/n> n
Please go to the following link: https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=.....
Log in and authorize rclone for access
Enter verification code> YOUR_VERIFICATION_CODE
Configure this as a Shared Drive (Team Drive)?
y) Yes
n) No (default)
y/n>
--------------------
[gdrive]
type = drive
client_id = YOUR_CLIENT_ID
client_secret = YOUR_CLIENT_SECRET
scope = drive.file
token = YOUR_TOKEN
--------------------
y) Yes this is OK (default)
e) Edit this remote
d) Delete this remote
y/e/d>
Current remotes:
Name Type
==== ====
gdrive drive
e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q>q
|
- check the remote
1
2
|
# rclone listremotes
gdrive:
|
- update
${HOME}/docker/bitwarden/backup/backup.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!sh
# GPG_CIPHER_ALGO=AES128
# GPG_PASSPHRASE='hunter2'
RCLONE_DESTS=(
# https://rclone.org/drive/
# https://rclone.org/drive/#making-your-own-client-id
# / Access to files created by rclone only.
# 3 | These are visible in the drive website.
# | File authorization is revoked when the user deauthorizes the app.
# \ "drive.file"
gdrive:bitwarden_rs_bkp
)
|
Backup Cron scheduler
1
2
3
4
|
5 3 * * * ${HOME}/docker/bitwarden/backup/backup.sh >${HOME}/docker/bitwarden/backup/logs/backup-$(date '+\%Y\%m\%d-\%H\%M').log 2>&1
5 4 * * * find "${HOME}/docker/bitwarden/backup/archives" -name 'bitwarden-*.tar.*' -mtime +14 -delete
5 4 * * * find "${HOME}/docker/bitwarden/backup/logs" -name '*.log' -mtime +14 -delete
|
Full Compose File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
version: "3.3"
networks:
traefik:
external:
name: traefik_webgateway
services:
traefik:
image: "traefik:v2.3"
container_name: traefik
restart: always
command:
- --entrypoints.web.address=:80
- --providers.docker.exposedByDefault=false
# - --log.level=DEBUG
# - --api.insecure # Don't do that in production
- --api
- --entrypoints.websecure.address=:443
- --certificatesresolvers.myresolver.acme.httpchallenge=true
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
# - --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesresolvers.myresolver.acme.email=YOUR_EMAIL
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
# - "8081:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "${LETSENCRYPT_PATH}:/letsencrypt"
labels:
#### set core configs
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`YOUR_DOMAIN`)" # && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.traefik.service=api@internal"
# - "traefik.http.routers.traefik.entrypoints=web"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=myresolver"
- "traefik.http.routers.traefik.middlewares=authtraefik"
- "traefik.http.middlewares.authtraefik.basicauth.users=user:$$apr1$$q8eZFHjF$$Fvmkk//V6Btlaf2i/ju5n/" # user/password
# global redirect to https
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
# middleware redirect
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
networks:
- traefik
bitwarden:
image: bitwardenrs/server:latest
container_name: bitwarden
restart: always
volumes:
- ${BW_CONFIG}:/data
environment:
- ADMIN_TOKEN=${BW_ADMIN_TOKEN}
- WEBSOCKET_ENABLED=true
networks:
- traefik
labels:
- traefik.enable=true
# Entry Point for https
- traefik.http.routers.bwd.rule=Host(`YOUR_DOMAIN`)
- traefik.http.routers.bwd.service=bitwarden-service
- traefik.http.services.bitwarden-service.loadbalancer.server.port=80
- "traefik.http.routers.bwd.entrypoints=websecure"
- "traefik.http.routers.bwd.tls=true"
- "traefik.http.routers.bwd.tls.certresolver=myresolver"
# websocket
- traefik.http.routers.bwd-ws.rule=Host(`YOUR_DOMAIN`) && Path(`/notifications/hub`)
- traefik.http.routers.bwd-ws.service=bitwarden-ws
- traefik.http.services.bitwarden-ws.loadbalancer.server.port=3012
- "traefik.http.routers.bwd-ws.entrypoints=websecure"
- "traefik.http.routers.bwd-ws.tls=true"
- "traefik.http.routers.bwd-ws.tls.certresolver=myresolver"
# middlewares
- "traefik.http.middlewares.bwd-ws=bw-stripPrefix"
- "traefik.http.middlewares.bw-stripPrefix.stripprefix.prefixes=/notifications/hub"
- "traefik.http.middlewares.bw-stripPrefix.stripprefix.forceSlash=false"
|