back to traefik
This commit is contained in:
parent
9bd9f23d9e
commit
4c2bdef32e
16 changed files with 171 additions and 60 deletions
21
.env.default
21
.env.default
|
@ -1,35 +1,42 @@
|
||||||
# ssl
|
# ssl
|
||||||
|
GANDIV5_API_KEY=xxxxxxxxxxxxxxxxx
|
||||||
LETSENCRYPT_EMAIL=root@localhost.localdomain
|
LETSENCRYPT_EMAIL=root@localhost.localdomain
|
||||||
LETSENCRYPT_GENERATE=false
|
|
||||||
# sites
|
# sites
|
||||||
DOMAIN=localhost.localdomain
|
DOMAIN=traefik.me
|
||||||
HOST_BAIKAL=baikal
|
HOST_BAIKAL=
|
||||||
HOST_BLOG=blog
|
HOST_BLOG=blog
|
||||||
HOST_DELUGE=deluge
|
HOST_DELUGE=deluge
|
||||||
HOST_DELUGE_DOWNLOAD=delugedownload
|
|
||||||
HOST_DOKUWIKI=dokuwiki
|
HOST_DOKUWIKI=dokuwiki
|
||||||
HOST_GLANCES=glances
|
HOST_GLANCES=glances
|
||||||
HOST_MAIL=mail
|
HOST_MAIL=
|
||||||
HOST_NETDATA=netdata
|
HOST_NETDATA=
|
||||||
HOST_PIGALLERY=pigallery
|
HOST_PIGALLERY=pigallery
|
||||||
HOST_PORTAINER=portainer
|
HOST_PORTAINER=portainer
|
||||||
HOST_SEAFILE=seafile
|
HOST_SEAFILE=seafile
|
||||||
HOST_SELFOSS=selfoss
|
HOST_SELFOSS=selfoss
|
||||||
HOST_SHAARLI=shaarli
|
HOST_SHAARLI=shaarli
|
||||||
|
HOST_TRAEFIK=traefik
|
||||||
HOST_WALLABAG=wallabag
|
HOST_WALLABAG=wallabag
|
||||||
HOST_WWW=www
|
HOST_WWW=www
|
||||||
|
PATH_PORTAINER=/portainer
|
||||||
|
PATH_GLANCES=/glances
|
||||||
|
PATH_DELUGE=/deluge
|
||||||
|
|
||||||
# other
|
# other
|
||||||
TZ=Europe/Paris
|
TZ=Europe/Paris
|
||||||
BASIC_AUTH=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/
|
BASIC_AUTH=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/
|
||||||
ROOT_INSTALL=/srv
|
ROOT_INSTALL=/srv
|
||||||
DB_ROOT_PASSWORD=rootpassword
|
DB_ROOT_PASSWORD=rootpassword
|
||||||
ADMIN_EMAIL=root@localdomain
|
ADMIN_EMAIL=root@localdomain
|
||||||
|
|
||||||
# torrent
|
# torrent
|
||||||
DELUGE_TORRENT_PORT=6881
|
DELUGE_TORRENT_PORT=6881
|
||||||
DOWNLOAD_HTTP_PORT=8000
|
DOWNLOAD_HTTP_PORT=8000
|
||||||
|
|
||||||
# seafile
|
# seafile
|
||||||
SEAFILE_ADMIN_PASSWORD=abc123456
|
SEAFILE_ADMIN_PASSWORD=abc123456
|
||||||
SEAFILE_REGULAR_USER=johndoe
|
SEAFILE_REGULAR_USER=johndoe
|
||||||
SEAFILE_REGULAR_PASSWORD=johnpassword
|
SEAFILE_REGULAR_PASSWORD=johnpassword
|
||||||
SEAFILE_PHOTO_LIBRARY=12345678
|
SEAFILE_PHOTO_LIBRARY=12345678
|
||||||
SEAFILE_NOTES_LIBRARY=12345678
|
SEAFILE_NOTES_LIBRARY=12345678
|
||||||
|
|
|
@ -12,9 +12,13 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- baikal_data:/var/www/baikal/Specific:rw
|
- baikal_data:/var/www/baikal/Specific:rw
|
||||||
- baikal_config:/var/www/baikal/config:rw
|
- baikal_config:/var/www/baikal/config:rw
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_HOST=${HOST_BAIKAL}.${DOMAIN}
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.baikal.rule=Host(`${HOST_BAIKAL}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.baikal.entrypoints=websecure
|
||||||
|
- traefik.http.routers.baikal.tls=true
|
||||||
|
- traefik.http.services.baikal.loadbalancer.server.port=80
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
baikal_config:
|
baikal_config:
|
||||||
baikal_data:
|
baikal_data:
|
||||||
|
|
|
@ -21,6 +21,9 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- 80
|
- 80
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_HOST=${HOST_BLOG}.${DOMAIN}
|
- traefik.enable=true
|
||||||
- LETSENCRYPT_HOST=${HOST_BLOG}.${DOMAIN}
|
- traefik.http.routers.blog.rule=Host(`${HOST_BLOG}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.blog.entrypoints=websecure
|
||||||
|
- traefik.http.routers.blog.tls=true
|
||||||
|
- traefik.http.services.blog.loadbalancer.server.port=80
|
||||||
|
|
|
@ -17,10 +17,19 @@ services:
|
||||||
- ${DELUGE_TORRENT_PORT}:${DELUGE_TORRENT_PORT}/udp
|
- ${DELUGE_TORRENT_PORT}:${DELUGE_TORRENT_PORT}/udp
|
||||||
volumes:
|
volumes:
|
||||||
- deluge_config:/config:rw
|
- deluge_config:/config:rw
|
||||||
- deluge_downloads:/downloads:rw
|
- deluge_downloads:/downloads:rw
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_HOST=${HOST_DELUGE}.${DOMAIN}
|
- traefik.enable=true
|
||||||
- VIRTUAL_PORT=8112
|
- traefik.http.routers.deluge.rule=Host(`${HOST_WWW}.${DOMAIN}`) && PathPrefix(`${PATH_DELUGE}`)
|
||||||
|
- traefik.http.routers.deluge.entrypoints=websecure
|
||||||
|
- traefik.http.routers.deluge.tls=true
|
||||||
|
- traefik.http.services.deluge.loadbalancer.server.port=8112
|
||||||
|
- traefik.http.routers.deluge.middlewares=delugeHeader,sameOriginHeader,delugeRedir,delugePStrip
|
||||||
|
- traefik.http.middlewares.delugeHeader.headers.customrequestheaders.X-Deluge-Base=${PATH_DELUGE}/
|
||||||
|
- traefik.http.middlewares.sameOriginHeader.headers.customrequestheaders.X-Frame-Options=SAMEORIGIN
|
||||||
|
- traefik.http.middlewares.delugePStrip.stripprefix.prefixes=${PATH_DELUGE}
|
||||||
|
- traefik.http.middlewares.delugeRedir.redirectregex.regex=^(.*)${PATH_DELUGE}$$
|
||||||
|
- traefik.http.middlewares.delugeRedir.redirectregex.replacement=$${1}${PATH_DELUGE}/
|
||||||
|
|
||||||
torrent:
|
torrent:
|
||||||
container_name: torrent
|
container_name: torrent
|
||||||
|
@ -32,11 +41,10 @@ services:
|
||||||
- deluge_downloads:/downloads:ro
|
- deluge_downloads:/downloads:ro
|
||||||
expose:
|
expose:
|
||||||
- 80
|
- 80
|
||||||
environment:
|
# shortcut to bypass traefik limitation
|
||||||
- HTTPS_METHOD=nohttps
|
ports:
|
||||||
- VIRTUAL_HOST=${HOST_DELUGE_DOWNLOAD}.${DOMAIN}
|
- ${DOWNLOAD_HTTP_PORT}:80
|
||||||
- LETSENCRYPT_HOST=${HOST_DELUGE_DOWNLOAD}.${DOMAIN}
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
deluge_config:
|
deluge_config:
|
||||||
deluge_downloads:
|
deluge_downloads:
|
||||||
|
|
|
@ -13,7 +13,12 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ${ROOT_INSTALL}/data/dokuwiki:/config
|
- ${ROOT_INSTALL}/data/dokuwiki:/config
|
||||||
networks:
|
networks:
|
||||||
- srv
|
- srv
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_HOST=${HOST_DOKUWIKI}.${DOMAIN}
|
- traefik.enable=true
|
||||||
- LETSENCRYPT_HOST=${HOST_DOKUWIKI}.${DOMAIN}
|
- traefik.http.routers.dokuwiki.rule=Host(`${HOST_DOKUWIKI}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.dokuwiki.entrypoints=websecure
|
||||||
|
- traefik.http.routers.dokuwiki.tls=true
|
||||||
|
- traefik.http.services.dokuwiki.loadbalancer.server.port=80
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,21 @@ services:
|
||||||
image: nicolargo/glances:3.2.3.1
|
image: nicolargo/glances:3.2.3.1
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
environment:
|
||||||
|
- GLANCES_OPT=-w
|
||||||
pid: host
|
pid: host
|
||||||
networks:
|
networks:
|
||||||
- srv
|
- srv
|
||||||
expose:
|
expose:
|
||||||
- 61208
|
- 61208
|
||||||
environment:
|
labels:
|
||||||
- GLANCES_OPT=-w
|
- traefik.enable=true
|
||||||
- VIRTUAL_PORT=61208
|
- traefik.http.routers.glances.rule=Host(`${HOST_WWW}.${DOMAIN}`) && PathPrefix(`${PATH_GLANCES}`)
|
||||||
- VIRTUAL_HOST=${HOST_GLANCES}.${DOMAIN}
|
- traefik.http.routers.glances.entrypoints=websecure
|
||||||
- LETSENCRYPT_HOST=${HOST_GLANCES}.${DOMAIN}
|
- traefik.http.routers.glances.tls=true
|
||||||
|
- traefik.http.services.glances.loadbalancer.server.port=61208
|
||||||
|
- traefik.http.routers.glances.middlewares=glancesRedir,glancesPStrip
|
||||||
|
- traefik.http.middlewares.glancesPStrip.stripprefix.prefixes=${PATH_GLANCES}
|
||||||
|
- traefik.http.middlewares.glancesRedir.redirectregex.regex=^(.*)${PATH_GLANCES}$$
|
||||||
|
- traefik.http.middlewares.glancesRedir.redirectregex.replacement=$${1}${PATH_GLANCES}/
|
||||||
|
|
||||||
|
|
0
nginx-proxy/docker-compose.nginx.yml
Executable file → Normal file
0
nginx-proxy/docker-compose.nginx.yml
Executable file → Normal file
|
@ -5,8 +5,6 @@ services:
|
||||||
container_name: pigallery2
|
container_name: pigallery2
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
VIRTUAL_HOST: ${HOST_PIGALLERY}.${DOMAIN}
|
|
||||||
LETSENCRYPT_HOST: ${HOST_PIGALLERY}.${DOMAIN}
|
|
||||||
image: bpatrik/pigallery2:1.9.0-alpine
|
image: bpatrik/pigallery2:1.9.0-alpine
|
||||||
networks:
|
networks:
|
||||||
- srv
|
- srv
|
||||||
|
@ -26,9 +24,15 @@ services:
|
||||||
cap_add:
|
cap_add:
|
||||||
- SYS_ADMIN
|
- SYS_ADMIN
|
||||||
healthcheck:
|
healthcheck:
|
||||||
disable: true
|
disable: true
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.pigallery_config.rule=Host(`${HOST_PIGALLERY}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.pigallery_config.entrypoints=websecure
|
||||||
|
- traefik.http.routers.pigallery_config.tls=true
|
||||||
|
- traefik.http.services.pigallery_config.loadbalancer.server.port=80
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pigallerydb_data:
|
pigallerydb_data:
|
||||||
pigallery_tmp:
|
pigallery_tmp:
|
||||||
pigallery_config:
|
pigallery_config:
|
||||||
|
|
|
@ -12,11 +12,17 @@ services:
|
||||||
- srv
|
- srv
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- 9000
|
- 9000
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_PORT=9000
|
- traefik.enable=true
|
||||||
- VIRTUAL_HOST=${HOST_PORTAINER}.${DOMAIN}
|
- traefik.http.routers.portainer.rule=Host(`${HOST_WWW}.${DOMAIN}`) && PathPrefix(`${PATH_PORTAINER}`)
|
||||||
- LETSENCRYPT_HOST=${HOST_PORTAINER}.${DOMAIN}
|
- traefik.http.routers.portainer.entrypoints=websecure
|
||||||
|
- traefik.http.routers.portainer.tls=true
|
||||||
|
- traefik.http.services.portainer.loadbalancer.server.port=9000
|
||||||
|
- traefik.http.routers.portainer.middlewares=portainerRedir,portainerPStrip
|
||||||
|
- traefik.http.middlewares.portainerPStrip.stripprefix.prefixes=${PATH_PORTAINER}
|
||||||
|
- traefik.http.middlewares.portainerRedir.redirectregex.regex=^(.*)${PATH_PORTAINER}$$
|
||||||
|
- traefik.http.middlewares.portainerRedir.redirectregex.replacement=$${1}${PATH_PORTAINER}/
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
portainer_data:
|
portainer_data:
|
||||||
|
|
|
@ -32,8 +32,6 @@ services:
|
||||||
SEAFILE_SERVER_HOSTNAME: ${HOST_SEAFILE}.${DOMAIN}
|
SEAFILE_SERVER_HOSTNAME: ${HOST_SEAFILE}.${DOMAIN}
|
||||||
SEAFILE_SERVER_LETSENCRYPT: "false"
|
SEAFILE_SERVER_LETSENCRYPT: "false"
|
||||||
TIME_ZONE: ${TZ}
|
TIME_ZONE: ${TZ}
|
||||||
VIRTUAL_HOST: ${HOST_SEAFILE}.${DOMAIN}
|
|
||||||
LETSENCRYPT_HOST: ${HOST_SEAFILE}.${DOMAIN}
|
|
||||||
image: seafileltd/seafile-mc:latest
|
image: seafileltd/seafile-mc:latest
|
||||||
networks:
|
networks:
|
||||||
- srv
|
- srv
|
||||||
|
@ -50,7 +48,13 @@ services:
|
||||||
privileged: true
|
privileged: true
|
||||||
cap_add:
|
cap_add:
|
||||||
- SYS_ADMIN
|
- SYS_ADMIN
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.seafile.rule=Host(`${HOST_SEAFILE}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.seafile.entrypoints=websecure
|
||||||
|
- traefik.http.routers.seafile.tls=true
|
||||||
|
- traefik.http.services.seafile.loadbalancer.server.port=80
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
seafile_db:
|
seafile_db:
|
||||||
seafile_data:
|
seafile_data:
|
||||||
|
|
|
@ -11,10 +11,12 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- 8888
|
- 8888
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_PORT=8888
|
- traefik.enable=true
|
||||||
- VIRTUAL_HOST=${HOST_SELFOSS}.${DOMAIN}
|
- traefik.http.routers.selfoss.rule=Host(`${HOST_SELFOSS}.${DOMAIN}`)
|
||||||
- LETSENCRYPT_HOST=${HOST_SELFOSS}.${DOMAIN}
|
- traefik.http.routers.selfoss.entrypoints=websecure
|
||||||
|
- traefik.http.routers.selfoss.tls=true
|
||||||
|
- traefik.http.services.selfoss.loadbalancer.server.port=8888
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
selfoss_data:
|
selfoss_data:
|
||||||
|
|
|
@ -12,10 +12,13 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
expose:
|
||||||
- 80
|
- 80
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_HOST=${HOST_SHAARLI}.${DOMAIN}
|
- traefik.enable=true
|
||||||
- LETSENCRYPT_HOST=${HOST_SHAARLI}.${DOMAIN}
|
- traefik.http.routers.shaarli.rule=Host(`${HOST_SHAARLI}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.shaarli.entrypoints=websecure
|
||||||
|
- traefik.http.routers.shaarli.tls=true
|
||||||
|
- traefik.http.services.shaarli.loadbalancer.server.port=80
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
shaarli-data:
|
shaarli-data:
|
||||||
shaarli-cache:
|
shaarli-cache:
|
||||||
|
|
0
traefik/acme.json
Normal file
0
traefik/acme.json
Normal file
52
traefik/docker-compose.traefik.yml
Executable file
52
traefik/docker-compose.traefik.yml
Executable file
|
@ -0,0 +1,52 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
container_name: traefik
|
||||||
|
image: traefik:v2.2.1
|
||||||
|
command:
|
||||||
|
- --providers.docker=true
|
||||||
|
- --providers.docker.exposedbydefault=false
|
||||||
|
- --api=true
|
||||||
|
- --entrypoints.web.address=:80
|
||||||
|
- --entrypoints.websecure.address=:443
|
||||||
|
- --certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}
|
||||||
|
- --certificatesresolvers.letsencrypt.acme.storage=/acme.json
|
||||||
|
- --certificatesResolvers.letsencrypt.acme.dnsChallenge=true
|
||||||
|
- --certificatesResolvers.letsencrypt.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53
|
||||||
|
- --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=gandiv5
|
||||||
|
- --certificatesResolvers.letsencrypt.acme.dnsChallenge.delayBeforeCheck=0
|
||||||
|
# staging server
|
||||||
|
#- --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
environment:
|
||||||
|
- GANDIV5_API_KEY=${GANDIV5_API_KEY}
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.api.rule=Host(`${HOST_TRAEFIK}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.api.entrypoints=web
|
||||||
|
- traefik.http.routers.api.entrypoints=websecure
|
||||||
|
- traefik.http.routers.api.service=api@internal
|
||||||
|
- traefik.http.routers.api.middlewares=auth
|
||||||
|
- traefik.http.middlewares.auth.basicauth.users=${BASIC_AUTH}
|
||||||
|
# request widlcard certificate
|
||||||
|
- traefik.http.routers.api.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.api.tls.domains[0].main=${DOMAIN}
|
||||||
|
- traefik.http.routers.api.tls.domains[0].sans=*.${DOMAIN}
|
||||||
|
# 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
|
||||||
|
- traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
- 443:443
|
||||||
|
expose:
|
||||||
|
- 8080
|
||||||
|
networks:
|
||||||
|
- srv
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- ${ROOT_INSTALL}/hosting/traefik/acme.json:/acme.json
|
|
@ -14,10 +14,14 @@ services:
|
||||||
- wallabag_images:/var/www/wallabag/web/assets/images:rw
|
- wallabag_images:/var/www/wallabag/web/assets/images:rw
|
||||||
environment:
|
environment:
|
||||||
- SYMFONY__ENV__DOMAIN_NAME="https://${HOST_WALLABAG}.${DOMAIN}"
|
- SYMFONY__ENV__DOMAIN_NAME="https://${HOST_WALLABAG}.${DOMAIN}"
|
||||||
- SYMFONY__ENV__FOSUSER_REGISTRATION=false
|
- SYMFONY__ENV__FOSUSER_REGISTRATION=false
|
||||||
- VIRTUAL_HOST=${HOST_WALLABAG}.${DOMAIN}
|
labels:
|
||||||
- LETSENCRYPT_HOST=${HOST_WALLABAG}.${DOMAIN}
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.wallabag.rule=Host(`${HOST_WALLABAG}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.wallabag.entrypoints=websecure
|
||||||
|
- traefik.http.routers.wallabag.tls=true
|
||||||
|
- traefik.http.services.wallabag.loadbalancer.server.port=80
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
wallabag_data:
|
wallabag_data:
|
||||||
wallabag_images:
|
wallabag_images:
|
||||||
|
|
|
@ -9,7 +9,9 @@ services:
|
||||||
- srv
|
- srv
|
||||||
expose:
|
expose:
|
||||||
- 80
|
- 80
|
||||||
environment:
|
labels:
|
||||||
- VIRTUAL_HOST=${DOMAIN},${HOST_WWW}.${DOMAIN}
|
- traefik.enable=true
|
||||||
- LETSENCRYPT_HOST=${DOMAIN},${HOST_WWW}.${DOMAIN}
|
- traefik.http.routers.www.rule=Host(`${HOST_WWW}.${DOMAIN}`)
|
||||||
|
- traefik.http.routers.www.entrypoints=websecure
|
||||||
|
- traefik.http.routers.www.tls=true
|
||||||
|
- traefik.http.services.www.loadbalancer.server.port=80
|
||||||
|
|
Loading…
Add table
Reference in a new issue