Portable, Server independent, Docker-based code to get the zorg Websites and Services up, running, and hosted.
Table of Contents
- git installation
- Docker installation
- π Folder structure setup
- πΎ Docker images
- 𧬠Docker networking
- Manage general services
- π·οΈ Docker services -> profiles mapping
- π©Ί Resource usage & services health
- π Update all Docker images
- π§ͺ Debugging Docker Services
- π₯ Firewall ports configuration
- π The
/zorg-docker/resources-directory & files - π logrotate handling
- πΏ Import/export SQL-dumps with MariaDB
Install git for your OS.
Following the official installation instructions for Docker.
Tip
On Ubuntu it's advised against installing via snap, as this may cause compatibility issues!
For all Hosts (subdomains) on the main Domain, the correspoinding DNS A-records with IP must be set up.
Example A-records
mail.domain.ch. 600 IN MX 178.nn.nn.nn
*.domain.ch. 600 IN A 178.nn.nn.nn
www.domain.ch. 600 IN A 178.nn.nn.nn
dockerstatus.domain.ch. 600 IN A 178.nn.nn.nnOn production a proper setup with pointing DNS for the root domain to the server's IP-address, this should not be necessary. But locally with a dummy domain, the domain & hostnames must be added to the /etc/hosts-file:
Example `hosts`-entries
(adjust as per your .env settings)
127.0.0.1 zdocker.dev
127.0.0.1 status.zdocker.dev
127.0.0.1 www.zdocker.dev
127.0.0.1 db.zdocker.dev
127.0.0.1 ftp.zdocker.dev
127.0.0.1 irc.zdocker.dev
127.0.0.1 pw.zdocker.dev
127.0.0.1 smtp.zdocker.dev
127.0.0.1 quake.zdocker.devIn general make sure to work from the project root directory:
cd /srv/<my-website>/<host>
Creat the a folder structure on your host machine that reflects the following:
Important
This is just a proposal, folder structures & names can be different!
βββ www <-- (Your project root directory)
β
βββ zorg-docker/ <-- Pulled Git repository (repo)
β
βββ .env <-- Copy & adjust ".env.example" from repo
βββ docker-compose.yml <-- Symbolic-linked ./zorg-docker/docker-compose.yml
βββ docker-update.sh <-- Symbolic-linked ./zorg-docker/docker-update.sh
β
βββ reverseproxy/ <-- (Optional) To further customize OWASP WAF rules or IP-Whitelist. Ref in .env
βΒ Β βββ owasp-coraza-waf.yaml
|
βββ website/ <-- zorg Website configs & data
β βββ .env <-- .env file for Website
β βββ apache.conf <-- Copy & adjust "website/apache/example.conf" from repo
β β βββ data/ <-- Website /data/ folder & files
β βΒ Β βββ files/ (user generated content for zorg website)
β βΒ Β βββ gallery/
β βΒ Β βββ tauschboerse/
β β βββ ...
β βββ cronjobs/
β βΒ Β βββ cronjobs.crontab <-- Copy & adjust "website/php/example.crontab" from repo
β βββ sendmail/
β Β Β βββ msmtprc <-- Copy & adjust "website/sendmail/example-msmtprc" from repo
β
βββ mailserver/ <-- (Optional) To further customize Postfix SMTP. Reference in .env
βΒ Β βββ postfix-main.cf
|
βββ irc/
βΒ Β βββ anope-configs/ <-- Copy & adjust "irc/anope-example-sensitive-includes" from repo
β βΒ Β βββ sensitive-channels.conf
β βΒ Β βββ sensitive-mail.conf
β βΒ Β βββ sensitive-networkinfo.conf
β βΒ Β βββ sensitive-nicknames.conf
β βΒ Β βββ sensitive-operators.conf
β βΒ Β βββ sensitive-serverinfo.conf
β βΒ Β βββ sensitive-uplink.conf
β βΒ Β βββ services.motd
βΒ Β βββ ircd-configs/ <-- Copy & adjust "irc/unrealircd-example-sensitive-includes" from repo
β βββ ircd.motd
β βββ sensitive-admin.conf
β βββ sensitive-history.conf
β βββ sensitive-me.conf
β βββ sensitive-network.conf
β βββ sensitive-operators.conf
β βββ sensitive-server.conf
β βββ sensitive-servicelink.conf
β βββ ssl/
β
βββ code-docu/
βΒ Β βββ code/ <-- (Optional) Git clone of github.com/zorgch/zorg-code.git. Reference in .env
βΒ Β βββ docu/ <-- (Optional) Reference in .env
βΒ Β βββ phpdoc.xml <-- (Optional)
β
βββ keepass/ <-- Reference in .env Only AFTER sftp started: put kdbx file here.
β
βββ quake3-baseq3/ <-- Reference in .env
βΒ βββ q3config_server.cfg <-- Copy & adjust "quake3/example-server.cfg" from repo
βΒ Β βββ pak0.pk3 <-- From a local licensed Quake3 installation
βΒ Β βββ pak1-8.pk3 <-- Can be obtained at: https://ioquake3.org/extras/patch-data/
β
βββ logs/ <-- Reference in .env
βββ website/ <-- Sub-directories MUST also be created manually!
β βββ apache/
β βββ php/
β βββ sendmail/
β βββ website/
βββ reverseproxy-owasp/
βββ mariadb/
βββ mailserver-smtp/
βββ irc-server/ <-- β οΈ Requires: sudo chown -R 1000:1000
βββ sftp/
βββ quake3-server/
Here's an overview of the underlaying Docker images used for the Docker Services, in order to provide quick access to their documentation & configuration how-to's.
Click to show list
| Service | Docker image | Link |
|---|---|---|
sslcerts |
alpine/mkcert |
GitHub |
dashboard |
portainer/portainer-ce |
Docs |
reverseproxy+ owasp-coraza-waf@file |
traefikcoraza-http-wasm-traefik |
Docs GitHub |
website |
php |
Docker Hub |
db |
mariadb |
Docs |
db-manager |
adminer |
Docs |
postfix-smtp |
mailserver/docker-mailserver |
Docs |
irc |
c0dy/unrealircd-anope |
Docker Hub |
irc-quizbot |
python:3.12-slim |
GitHub |
irc-telegram-bridge |
bhavin192/teleirc |
Docker Hub |
stockticker |
python:3.12-slim |
GitHub |
servicealerts |
lorcas/docker-telegram-notifier |
GitHub |
sftp |
atmoz/sftp |
Docker Hub |
quake3 |
jberrenberg/quake3 |
GitHub |
phpdoc |
phpdoc/phpdoc |
Docs |
In order to not block Ports for other networking services on the server / in other Docker stacks, this Docker stack has support for HTTP, TCP (dedicated), and UDP shared networks (aka External Docker Networks).
These are optional, but highly recommended to use - in order to prevent future port conflicts. Here's a schematic overview of the networking capabilities added:
graph TD
%% Externe Netzwerke
subgraph External Networks
lb_http["loadbalance-http<br>[external/shared]"]
lb_tcp["loadbalance-tcp<br>[external/shared]"]
lb_udp["loadbalance-udp<br>[external/shared]"]
end
%% zorg Main
subgraph zorg Live
zorg[zorg services]
grid["the-grid<br>β loadbalance-http"]
superhighway["information-superhighway<br>β loadbalance-tcp"]
slipgate["slipgate-teleporter<br>β loadbalance-udp"]
zion["zion-mainframe<br>[internal only]"]
end
%% zorg Construct
subgraph zorg Construct
stack1[construct services]
stack1_http["β loadbalance-http"]
stack1_tcp["β loadbalance-tcp"]
stack1_udp["β loadbalance-udp"]
internalnet["custom-net<br>[internal only]"]
end
%% Weitere Stacks
subgraph other-stack-2
stack2[stack 2 services]
stack2_http["β loadbalance-http"]
stack2_internalnet["stack2_default<br>[internal only]"]
end
subgraph other-stack-3
stack3[stack 3 services]
stack3_tcp["β loadbalance-tcp"]
stack3_udp["β loadbalance-udp"]
end
%% Verbindungen zorg
zorg --> grid --> lb_http
zorg --> superhighway --> lb_tcp
zorg --> slipgate --> lb_udp
zorg --> zion
%% Verbindungen andere Stacks
stack1 --> stack1_http --> lb_http
stack1 --> stack1_tcp --> lb_tcp
stack1 --> stack1_udp --> lb_udp
stack1 --> internalnet
stack2 --> stack2_http --> lb_http
stack2 --> stack2_internalnet
stack3 --> stack3_tcp --> lb_tcp
stack3 --> stack3_udp --> lb_udp
git clone -b <branch-name> --depth 1 https://github.com/zorgch/zorg-docker.git ./zorg-dockerNote
See below section for how to UPDATE the cloned git repository to get its latest changes.
cp ./zorg-docker/.env.example ./.envImportant
Using your text editor of choice, adjust the .env-file to the setup of your host machine.
ln -s ./zorg-docker/docker-compose.yml ./docker-compose.ymlThese networks allow OTHER Docker Stacks and Services to connect to the same network.
docker network create loadbalance-http
docker network create loadbalance-tcp
docker network create loadbalance-udpNote
Why is this important?
A: Access to Docker Services in the Stack from other Docker Stacks and Services.
B: This is particularly important to use 1 central Reverse-Proxy to route traffic to the services in the correct Stack.
C: Conclusion of A & B means: no Port blockings of common Ports (e.g. 80 or 443) by 1 single Docker Stack!
docker compose buildSome services require self-signed certificates, this does not interfere with (also) using Let's Encrypt certificates!
Add these first using the sslcerts service:
docker compose --profile setup upNote
This requires the mailserver service to be running!
Tip
This is required when emails to a local user (alias) should be forwarded to an external email address corresponding to that alias.
docker exec -ti PROJECTNAME-mailserver setup email add info@DOMAINNAME <NEW_PASSWORD>
docker exec -ti PROJECTNAME-mailserver setup alias add <EMAILADDRESS> <RECIPIENT>
The docker-mailserver setup is required for various configurations, including for example DKIM.
docker exec -ti PROJECTNAME-mailserver setup
docker exec -ti PROJECTNAME-mailserver setup config dkim help
cd into the directory containing the locally cloned git files, and run a git pull:
cd /srv/<my-website>/<host>/zorg-docker
git pull --rebaseImportant
Check the updated Files and apply necessary changes to outdated manual copies of the same!
- Example:
Fast-forward
.env.example | 17 +++++--------
docker-compose.yml | 75 ++++++++++++++++++++++++++++++++++++-------------------
resources/irc/unrealircd/unrealircd.conf | 12 ++++-----
resources/mailserver/postfix-main.cf | 4 +--
resources/reverseproxy/middlewares-http.yaml | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
resources/reverseproxy/selfsigned-certs.yaml | 23 ++++++++---------
6 files changed, 207 insertions(+), 90 deletions(-)PRODUCTION mode β run in "detached mode" (background), without interative logging to the shell by adding the -d flag.
Start/stop all services *
docker compose --profile all up -d- Applicable services:
servicealerts,dashboard,reverseproxy,website,db,postfix-smtp,irc,irc-quizbot,irc-telegram-bridge,stockticker,sftp,quake3
Example: only the Webserver services
docker compose --profile webserver up -d- Applicable services:
servicealerts,dashboard,reverseproxy,website,db,postfix-smtp
Example 2: only the IRC services
docker compose --profile irc up -d- Applicable services:
servicealerts,dashboard,irc,irc-quizbot,irc-telegram-bridge
Example 2: only the Mailserver services
docker compose --profile mailserver up -d- Applicable services:
servicealerts,dashboard,reverseproxy,postfix-smtp
Caution
Do not take an individual service down using --profile, target it specifically instead!docker compose down stockticker
* As provisioning a KeePass KDBX via SFTP is not required for the general website hosting, the SFTP service (keepass) is separated from the overall services.
docker compose --profile keepass up -d
docker compose down sftp* Due to a potential high load on the server, the Β«Quake 3 ArenaΒ» Server (quake3) is separated from the general services.
docker compose up -d quake3
docker compose down quake3* As the code generation is only run occassionally, the phpDoc service (phpdoc) is separated from the general services.
docker compose --profile docu up
# exits automaticallyThe docker-compose.yml file uses Docker Service-profiles to group services into logical groups.
- This allows to only start / stop a certain group of services at once.
- Yet individual docker services can still be targeted individually by referencing their service name.
Some single services have their own profile, in order to prevent them from starting/stopping when using docker compose without any --profile.
Tip
Multiple profiles can be combined: docker compose --profile webserver --profile irc up -d
| Profile | Applicablae Docker Services | Example Usage |
|---|---|---|
all |
All general services | --profile all |
setup |
sslcerts postfix-smtp |
--profile setup |
status |
servicealerts dashboard reverseproxy |
--profile status |
webserver |
servicealerts dashboard reverseproxy website db db-manager postfix-smtp |
--profile webserver |
mailserver |
servicealerts dashboard reverseproxy postfix-smtp |
--profile mailserver |
irc |
servicealerts dashboard irc irc-quizbot irc-telegram-bridge |
--profile irc |
keepass |
servicealerts dashboard sftp |
--profile keepass |
quake |
servicealerts dashboard quake3 |
--profile quake |
docu |
phpdoc |
--profile docu |
| Single service | e.g. stockticker |
docker compose up -d stockticker |
This is particularly helpful to fine-tune the CPU & memory limits for the Docker services, which can be adjusted in the .env-file.
docker statsExample docker status output
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"
NAME CPU % MEM USAGE / LIMIT MEM %
zorg-reverseproxy 0.00% 69.01MiB / 1GiB 6.74%
zorg-stockticker 0.03% 70.19MiB / 1GiB 6.85%
zorg-mariadb 0.01% 133.8MiB / 4GiB 3.27%
zorg-website 0.01% 8.855MiB / 4GiB 0.22%
zorg-dashboard 0.00% 27.06MiB / 1GiB 2.64%
zorg-mailserver 0.11% 39.41MiB / 256MiB 15.39%The full-fledged Docker Management Dashboard (Portainer) can be accessed at:
https://dockerstatus.DOMAINNAME
Host can be adjusted in the.env
cd into the directory containing the docker-compose.yml (symlink), and run this shell command:
Tip
The images can be scoped to update only services within a specific Docker services profile
cd /srv/<my-website>/<host>/
for image in $(docker compose --profile all config | awk '/image:/ { print $2 }'); do docker pull "$image"; done;Alternatively, use the docker-update.sh script (can also be run via Host's cron):
cd /srv/<my-website>/<host>/
./docker-update.shCaution
Updating Docker images will NOT renew running services - they have to be rebuilt!
For DEBUGGING mode β with an interactive log output to the active shell - omit the -d flag when starting services:
docker compose --file ./website/docker-compose.yml up <-- no -d flag
Tip
Docker circumvents the Host machine's firewall β so usually NO need (or not possible) to configure the Host machine's firewall!
Ensure the Host machine's firewall is configured to expose & allow access through the required ports for different Docker Services:
Allow a port - or port range
A non-conclusive, depends on what ports: are set in the .env file.
[!IMPORTANT] Do NOT expose the default Database port
3306to the world-wide-web!
sudo ufw allow 80 # webserver/reverseproxy http
sudo ufw allow 443 # webserver/reverseproxy https
sudo ufw allow 9443/tcp # Docker dashboard (secure)
sudo ufw allow 6667/tcp # irc-Server
sudo ufw allow 6697/tcp # irc-Server (secure)
sudo ufw allow 2222/tcp # ftp-Server | NOTE: 22 reserved for ssh
sudo ufw allow 27960/udp # quake3-ServerInspect all rules - i.e. allowed ports
% sudo ufw status
Status: active
To Action From
-- ------ ----
80 ALLOW Anywhere
443 ALLOW Anywhere
587 ALLOW Anywhere
6667/tcp ALLOW Anywhere
6697/tcp ALLOW Anywhere
2222/tcp ALLOW Anywhere
27960/udp ALLOW Anywhere
80 (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
587 (v6) ALLOW Anywhere (v6)
6667/tcp (v6) ALLOW Anywhere (v6)
6697/tcp (v6) ALLOW Anywhere (v6)
2222/tcp (v6) ALLOW Anywhere (v6)
27960/udp (v6) ALLOW Anywhere (v6)Contains site specific resources that are actively mapped from the Host to some of the Docker Services. But it also contains some example files that can be used to configure the services.
Examples of example files
irc/anope-example-*&irc/unrealircd-example-*--> MUST be adaptedwebsite/apache/example.conf--> use asapache.confwebsite/php/example.crontab--> use ascrontabwebsite/sendmail/example-msmtprc--> use asmsmtprcquake3/example-autoexec.cfg--> use asautoexec.cfg
The Docker services are just writing logs to the mapped /logs-directory, but logrotate must be configured on the Host machine.
A third-party SQL Manager (e.g. on macOS use SequelAce) or CLI application is required to connect to the MariaDB service under the specified host and port.
mysql -h <db.host.domain> -P 3306 -u MYSQL_USER -p MYSQL_DATABASE < /path/to/import-dump.sqlmysqldump -h <db.host.domain> -P 3306 -u MYSQL_USER -p MYSQL_DATABASE > /path/to/save-dump.sqlCopyright (C) 2024-2025 zorg Verein https://github.com/zorgch
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
This program comes with ABSOLUTELY NO WARRANTY; for details read the README. This is free software, and you are welcome to redistribute it under certain conditions; see the LICENSE.