Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# define the path of your web application, relative to the current folder
WWW_ROOT=../data
# fewohbee configuration
# Copy this file to .env and adjust the values accordingly.
# New variables will be added automatically by update-docker.sh.

# Compose file to use. Change to docker-compose.no-ssl.yml for reverse proxy mode.
COMPOSE_FILE=docker-compose.yml

# set timezone
TZ=Europe/Berlin

# e.g. fewohbee or mydomain.tld
HOST_NAME=fewohbee
HOST_NAME=fewohbee

# mysql settings
MARIADB_ROOT_PASSWORD=<pw>
Expand All @@ -16,14 +20,10 @@ MARIADB_DATABASE=fewohbee
MYSQL_BACKUP_USER=backupuser
MYSQL_BACKUP_PASSWORD=<backuppassword>

MYSQL_BACKUP_FOLDER=../dbbackup

DOCKER_API_VERSION=1.37

# letsencrypt settings
LETSENCRYPT=false
EMAIL="<your mail address>"
# enter here all (sub-)domains which should be included in the certificate, sepearated with a whitespace e.g.: domain.tld sub1.domain.tld
# enter here all (sub-)domains which should be included in the certificate, separated with a whitespace e.g.: domain.tld sub1.domain.tld
LETSENCRYPT_DOMAINS="<domain.tld>"
# if used specify your dyndns provider, currently "desec.io" is supported
# leave empty if not used
Expand All @@ -33,11 +33,15 @@ DEDYN_TOKEN="<token>"
# Set your dedyn.io domain name here:
DEDYN_NAME="<name>"


# self signed certificate settings
SELF_SIGNED=true

# FewohBee Settings
# reverse proxy settings (docker-compose.no-ssl.yml)
# Port exposed by the web container when using docker-compose.no-ssl.yml
LISTEN_PORT=80

###> Application settings ###

LOCALE=de
FEWOHBEE_VERSION=latest
APP_ENV=prod
Expand Down Expand Up @@ -77,3 +81,5 @@ PASSKEY_ENABLED=false
# otherwise the host name of your web server must be set, e.g. https://pve
# leave this untouched when using fewohbee-dockerized
WEB_HOST=http://web:8080

###< Application settings ###
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.env
.env.app
.DS_Store
conf/nginx/server_name.active
108 changes: 85 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,99 @@
# fewohbee-dockerized

# fewohbee-dockerized
This docker compose setup is part of the [fewohbee guesthouse administration tool](https://github.com/developeregrem/fewohbee). It provides all necessary services to run fewohbee out of the box.

This docker-compose setup is part of the [guesthouse administration tool](https://github.com/developeregrem/fewohbee). fewohbee-dockerized provides all necessary software/images in order to run the guesthouse administration tool (Pensionsverwaltung) out of the box.
## Services

The setup contains:
| Service | Image | Description |
|---------|-------|-------------|
| `web` | [nginx](https://hub.docker.com/_/nginx/) | Web server |
| `php` | [fewohbee-phpfpm](https://github.com/developeregrem/fewohbee-phpfpm) | PHP 8 FPM – clones and runs the app on first start |
| `cron` | [fewohbee-phpcli](https://github.com/developeregrem/fewohbee-phpfpm) | PHP CLI for scheduled tasks |
| `db` | [mariadb](https://hub.docker.com/_/mariadb) | Database |
| `redis` | [redis](https://hub.docker.com/_/redis) | In-memory cache |
| `acme` | [fewohbee-acme](https://github.com/developeregrem/fewohbee-acme) | SSL certificate management (Let's Encrypt or self-signed) |

- [nginx](https://hub.docker.com/_/nginx/) as web server or reverse proxy
## Configuration

- [mariadb](https://hub.docker.com/_/mariadb) as database management system
All settings are stored in a single `.env` file. Use `.env.dist` as the reference template.

- [PHP 8.5-fpm-alpine](https://hub.docker.com/_/php/) with [composer](https://hub.docker.com/_/composer) which [installs](https://github.com/developeregrem/fewohbee-phpfpm) the guesthouse administration tool when the container is started.
## Setup

- [redis](https://hub.docker.com/_/redis) as in-memory cache
### Option A – Setup container (recommended, all platforms)

- ACME for letsencrypt or self-signed certificates (with automatic renew)
Works on Linux, macOS and Windows — requires only Docker.

## Installation
```sh
# Clone the repository first
git clone https://github.com/developeregrem/fewohbee-dockerized.git
cd fewohbee-dockerized

Clone the master branch of the repository.
# Linux / macOS
docker run --rm -it -v $(pwd):/config developeregrem/fewohbee-setup

````
cd /opt
git clone https://github.com/developeregrem/fewohbee-dockerized.git
cd fewohbee-dockerized
````

Run the interactive installtion script to generate the configuration file and setup the application.
# Windows PowerShell
docker run --rm -it -v ${PWD}:/config developeregrem/fewohbee-setup
```

````
chmod +x install.sh
./install.sh
````
The container asks a few questions (hostname, SSL mode, language), generates passwords and writes `.env`.

## Usage
### Option B – install.sh (Linux only)

Please refer to the documentation in the Wiki: [https://github.com/developeregrem/fewohbee/wiki/Docker-Setup](https://github.com/developeregrem/fewohbee/wiki/Docker-Setup)
A Bash script that additionally sets up optional cron jobs for database backups and automatic updates:

```sh
git clone https://github.com/developeregrem/fewohbee-dockerized.git
cd fewohbee-dockerized
chmod +x install.sh
sudo ./install.sh
```

## Starting the application

### Standard mode (with SSL)

For servers with direct internet access. Manages SSL certificates automatically via the `acme` container (self-signed or Let's Encrypt).

```sh
docker compose up -d
```

### Reverse proxy mode (no internal SSL)

For deployments behind an external reverse proxy (Traefik, Nginx Proxy Manager, Caddy, etc.) that handles SSL termination. No `acme` container — the web container serves plain HTTP.

Set `COMPOSE_FILE=docker-compose.no-ssl.yml` in `.env` (done automatically by the setup scripts when choosing `reverse-proxy`) and then:

```sh
docker compose up -d
```

Configure the exposed HTTP port via `LISTEN_PORT` in `.env` (default: `80`).

## First-run initialisation

After starting the stack, the PHP container clones the app and installs dependencies (~2 minutes). Monitor progress:

```sh
docker compose logs -f php
```

Once `ready to handle connections` appears, run once to create the first admin user:

```sh
docker compose exec --user www-data php /bin/sh -c "php fewohbee/bin/console app:first-run"
```

## Updates

```sh
chmod +x update-docker.sh
./update-docker.sh
```

The script pulls new images, restarts the stack and automatically syncs any new environment variables into `.env` and both compose files. New variables should be reviewed and adjusted after the update.

## Documentation

Full setup and configuration documentation:
[https://github.com/developeregrem/fewohbee/wiki/Docker-Setup](https://github.com/developeregrem/fewohbee/wiki/Docker-Setup)
4 changes: 4 additions & 0 deletions conf/db/create-backup-user.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
# Creates the database backup user on first database initialization.
# Runs automatically via /docker-entrypoint-initdb.d/ on first start.
mariadb -u root -p"${MARIADB_ROOT_PASSWORD}" -e "GRANT LOCK TABLES, SELECT ON *.* TO '${MYSQL_BACKUP_USER}'@'%' IDENTIFIED BY '${MYSQL_BACKUP_PASSWORD}';"
10 changes: 10 additions & 0 deletions conf/nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM nginx:mainline-alpine

COPY . /etc/nginx/conf.d/

# Remove the default nginx config (replaced by site.conf) and the runtime-generated file
RUN rm -f /etc/nginx/conf.d/default.conf \
/etc/nginx/conf.d/server_name.active \
&& chmod +x /etc/nginx/conf.d/docker-entrypoint.sh

ENTRYPOINT ["/bin/sh", "/etc/nginx/conf.d/docker-entrypoint.sh"]
48 changes: 48 additions & 0 deletions conf/nginx/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh
set -e

# Select site config based on SSL mode
if [ "${REVERSE_PROXY:-false}" = "true" ]; then
cp /etc/nginx/conf.d/site.conf.no-ssl /etc/nginx/conf.d/site.conf
fi

# Generate the active server_name config from template
envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active

if [ "${REVERSE_PROXY:-false}" != "true" ]; then
# Wait for SSL certificates to be provided by the acme container.
# On first start the certs volume is empty; acme writes the files shortly after launch.
echo "Waiting for SSL certificates ..."
while [ ! -f "/certs/fullchain.pem" ] || [ ! -f "/certs/privkey.pem" ] || [ ! -f "/certs/dhparams.pem" ]; do
sleep 2
done
echo "Certificates found, starting nginx."
fi

# Start nginx in the background so we can watch for cert changes
nginx -g 'daemon off;' &
NGINX_PID=$!

if [ "${REVERSE_PROXY:-false}" != "true" ]; then
# Record the initial cert fingerprint
CERT_HASH=$(md5sum /certs/fullchain.pem | cut -d' ' -f1)

# Watch for certificate renewal every 60 seconds and reload nginx when changed.
# This replaces the previous approach of restarting the container via the Docker socket.
while kill -0 "$NGINX_PID" 2>/dev/null; do
sleep 60
NEW_HASH=$(md5sum /certs/fullchain.pem 2>/dev/null | cut -d' ' -f1)
if [ -n "$NEW_HASH" ] && [ "$NEW_HASH" != "$CERT_HASH" ]; then
CERT_HASH="$NEW_HASH"
echo "Certificate changed, reloading nginx ..."
nginx -s reload 2>/dev/null || true
fi
done
else
# In reverse proxy mode just wait for nginx to exit
while kill -0 "$NGINX_PID" 2>/dev/null; do
sleep 60
done
fi

wait "$NGINX_PID"
4 changes: 3 additions & 1 deletion conf/nginx/site-enabled-https/01_fewohbee.snippet
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ location / {
location ~ ^/index\.php(/|$) {
root /var/www/html/fewohbee/public;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
resolver 127.0.0.11 valid=5s;
set $php_backend php:9000;
fastcgi_pass $php_backend;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
Expand Down
27 changes: 27 additions & 0 deletions conf/nginx/site.conf.no-ssl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
server_tokens off;

server {
listen 80;
listen [::]:80;
index index.html index.php;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;

root /var/www/html/fewohbee/public;

include /etc/nginx/conf.d/server_name.active;

include /etc/nginx/conf.d/snippets/header.snippet;

# app configs (PHP/FastCGI — reused from HTTPS setup)
include /etc/nginx/conf.d/site-enabled-https/*;
}

server {
# this vhost is for internal connections only (e.g. mpdf fetches images from here, see env WEB_HOST)
listen 8080;

root /var/www/html/fewohbee/public;

include /etc/nginx/conf.d/server_name.active;
}
19 changes: 0 additions & 19 deletions conf/php/conf.ini

This file was deleted.

4 changes: 0 additions & 4 deletions cron.d/cli/www-data

This file was deleted.

Loading