# Open Productive Stack ## Overview This repository contains a productive stack of open-source applications for team collaboration and communication. The stack includes: ### Core Infrastructure - **Traefik**: Edge router that handles routing and load balancing for all services - **PostgreSQL**: Relational database for applications requiring PostgreSQL - **MariaDB**: MySQL-compatible database for applications requiring MySQL - **Adminer**: Database management tool for easy database administration ### Mail - **Mailcow**: Complete mail server solution with SMTP, IMAP, antivirus, and webmail ### Collaboration Tools - **Nextcloud**: Self-hosted file sync and share platform with collaboration features - **OnlyOffice**: Online office suite for document editing and collaboration - **OpenProject**: Project management and team collaboration software - **HedgeDoc**: Collaborative markdown notes editor for team documentation ### Web Publishing - **Drupal**: Flexible content management system (CMS) for building websites All components are containerized using Docker for easy deployment, scaling, and management, creating a complete productivity environment for teams. ## Requirements You need [docker](https://docs.docker.com/get-started/get-docker/) and with [docker compose plugin](https://docs.docker.com/compose/). You may want to follow the [post installation instructions](https://docs.docker.com/engine/install/linux-postinstall/). At least 6 cores with 16GB RAM 100GB SSD would be sufficent. ## Diagnostics Run the unified diagnostics script from the repository root: ```bash ./diagnostic.sh ``` This combines the previous `diagnostic.sh` and `health_check.sh` checks. ## Mail Security ### Current Status - ✅ SPF, DKIM, DMARC configured - ✅ MTA-STS policy enforced (`https://mta-sts.nasarek.dev/.well-known/mta-sts.txt`) - ✅ TLS-RPT configured - ✅ TLS certificates valid on all mail ports - ⚠️ DNSSEC: Enable at DNS provider and ensure DS/DNSKEY are published - ⚠️ TLSA (DANE): Add records after DNSSEC is active (see `/var/deploy/scripts/README-TLSA.md`) ### TLSA Record Automation Automated TLSA record updates are available. See `/var/deploy/scripts/README-TLSA.md` for setup instructions. The automation monitors certificate changes and updates TLSA records automatically when certificates are renewed. ## Install ### Prerequisites 1) Copy the env and docker-compose.override.yml to the service directories via the script. Add your specific settings in `set-config.sh`, then: ``` ./copy_overrides.bash ``` 2) Set your env variables in `./core/.env`, `./drupal/.env`, `./gitlab/.env`, `./hedgedoc/.env`, `./onlyoffice/.env`, `./nextcloud/.env`, `./openproject/.env`. 3) Generate mailcow config ```bash cd mailcow ./geneare_config.bash ``` 4) Copy config to .env ```bash cp mailcow.conf .env ``` 5) Create infrastructure via script: ``` ./create_infra.bash ``` ### Core environment 1) Start traefik, mariadb, postgres and adminer with: ```bash docker compose -f core/docker-compose.yml up -d ``` ### Drupal 1) Set your env variables in 2) Start Drupal containers. ```bash docker compose -f drupal/docker-compose.yml up -d ``` #### Additional steps You may want to use Redis Caching. 1) add to drupal/sites/default/settings.php: ```php // Redis Configuration $settings['redis.connection']['interface'] = 'PhpRedis'; $settings['redis.connection']['host'] = 'redis'; $settings['redis.connection']['port'] = 6379; $settings['cache']['default'] = 'cache.backend.redis'; $settings['cache']['bins']['bootstrap'] = 'cache.backend.chainedfast'; $settings['cache']['bins']['discovery'] = 'cache.backend.chainedfast'; $settings['cache']['bins']['config'] = 'cache.backend.chainedfast'; ``` 4) Visit your Domain and install Drupal site. ### Gitlab 1) Start gitlab. ```bash docker compose -f gitlab/docker-compose.yml up -d ``` 2) Get your root password. ```bash sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password ``` 4) Visit you domain and log in. ### Hedgedoc 1) Start containers. ```bash docker compose -f hedgedoc/docker-compose.yml up -d ``` 2) Add your user. ```bash source hedgedoc/.env docker exec hedgedoc bin/manage_users --pass ${HEDGEDOC_USER_PASSWORD} --add ${HEDGEDOC_USER_EMAIL} ``` ### Mailcow 1) Start containers. ```bash docker compose docker-compose.yml up -d ``` 4) Visit DOMAIN/admin and log in with admin:admin. 5) Consider the post installation steps, i. e. [watchdog](https://docs.mailcow.email/de/post_installation/firststeps-authorize_watchdog_and_bounces/) [dmarc](https://docs.mailcow.email/de/post_installation/firststeps-dmarc_reporting/) [dkim](https://docs.mailcow.email/getstarted/prerequisite-dns/) (You get your dkim key when you registered your email domain in mailcow ui) ### OnylOffice 1) Start containers. ```bash docker compose -f onlyoffice/docker-compose.yml up -d ``` ### Nextcloud 1) Start OnlyOffice first! 2) Start containers. ```bash docker compose -f nextcloud/docker-compose.yml up -d ``` 3) Visit nextcloud domain and login with your .env credentials. #### Nextcloud Office with Collabora Collabora container is included for document editing. Configure via Nextcloud admin panel: 1) Install **Nextcloud Office** app from Apps menu. 2) Go to **Settings** → **Administration** → **Office**. 3) Select **"Use your own server"** and enter: `https://office.yourdomain.com`. 4) Configure WOPI allowlist with Collabora's IP: ```bash # Get Collabora IP. docker inspect nextcloud-collabora --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' # Set allowlist. docker exec -u www-data nextcloud php occ config:app:set richdocuments wopi_allowlist --value="COLLABORA_IP" # Enable local servers. docker exec -u www-data nextcloud php occ config:system:set allow_local_remote_servers --value=true --type=boolean ``` See `/var/deploy/nextcloud/COLLABORA-QUICK-SETUP.md` for details. ### Openproject 1) Start containers. ```bash docker compose -f hedgedoc/docker-compose.yml up -d ``` 2) Visit openproject domain and login with admin:admin and set new password. ## SSH over VPN (WireGuard) SSH access is secured behind a WireGuard VPN. Port 22 is only reachable from within the VPN subnet (`10.13.13.0/24`). ### Server-side setup **1. Configure `core/.env`** ```env WG_SERVERURL=your.server.hostname.or.ip WG_PEERS=laptop,phone # or a number, e.g. "3" TZ=Europe/Berlin ``` **2. Start the WireGuard container** ```bash docker compose -f core/docker-compose.yml up -d wireguard ``` Peer configs and QR codes are generated automatically in: ``` core/volumes/wireguard/config/peer_/ peer_.conf ← import this on the client peer_.png ← scan this QR code on mobile ``` **3. Apply firewall rules** Run *after* confirming the VPN works (see client setup below): ```bash sudo bash scripts/secure-ssh-vpn.sh [--dry-run] ``` This opens ports 80, 443, 25, 465, 587, 143, 993, 4190, 2424, 51820 and restricts SSH to VPN clients only. To also restrict mail client ports (IMAP, submission) to VPN: ```bash sudo bash scripts/secure-ssh-vpn.sh --mail-vpn-only ``` ### Local client setup #### Linux ```bash sudo apt install wireguard # Copy peer config from the server scp user@your-server:/var/deploy/core/volumes/wireguard/config/peer_laptop/peer_laptop.conf \ ~/.config/wireguard/wg0.conf sudo wg-quick up wg0 # Connect on boot: sudo systemctl enable wg-quick@wg0 ``` #### macOS ```bash brew install wireguard-tools # Or use the App Store app: "WireGuard" # Import peer_laptop.conf via File → Import Tunnel(s) from File ``` #### Windows Download [WireGuard for Windows](https://www.wireguard.com/install/), then: *Add Tunnel → Import tunnel(s) from file* → select `peer_laptop.conf`. #### Android / iOS Scan the QR code at `core/volumes/wireguard/config/peer_/peer_.png` with the WireGuard app. ### Verify the tunnel ```bash # On the server — check connected peers docker exec wireguard wg show # From the client — SSH should work only after connecting to VPN ssh user@10.13.13.1 ``` ## Roadmap - Tweak the core components and subservices for petter performance. - More automatisation when installing the environment. - Add more services - [ ] Matrix/Synapse + Element - Fix all the Nextcloud errors + Your web server is not properly set up to resolve `.well-known` URLs, failed on: `/.well-known/webfinger` For more details see the documentation ↗.