From 784572a8bb0aa94646abf9324579c658c68200f7 Mon Sep 17 00:00:00 2001 From: Kaspar Rosin Date: Mon, 24 Mar 2025 09:50:28 +0200 Subject: [PATCH 1/2] Add nginx template --- 2-docker-nginx-with-database/.env.example | 7 ++ 2-docker-nginx-with-database/.gitignore | 6 + .../docker-compose.yml | 104 ++++++++++++++++++ .../laravel.env.example | 46 ++++++++ 2-docker-nginx-with-database/nginx/nginx.conf | 12 ++ 5 files changed, 175 insertions(+) create mode 100644 2-docker-nginx-with-database/.env.example create mode 100644 2-docker-nginx-with-database/.gitignore create mode 100644 2-docker-nginx-with-database/docker-compose.yml create mode 100644 2-docker-nginx-with-database/laravel.env.example create mode 100644 2-docker-nginx-with-database/nginx/nginx.conf diff --git a/2-docker-nginx-with-database/.env.example b/2-docker-nginx-with-database/.env.example new file mode 100644 index 0000000..9554aae --- /dev/null +++ b/2-docker-nginx-with-database/.env.example @@ -0,0 +1,7 @@ +APP_DOMAIN=your-domain.com +DB_DATABASE=solidtime +DB_USERNAME=solidtime +FORWARD_APP_PORT=8000 +FORWARD_DB_PORT=5432 +DB_PASSWORD=randompassword +SOLIDTIME_IMAGE_TAG=latest diff --git a/2-docker-nginx-with-database/.gitignore b/2-docker-nginx-with-database/.gitignore new file mode 100644 index 0000000..552e336 --- /dev/null +++ b/2-docker-nginx-with-database/.gitignore @@ -0,0 +1,6 @@ +/logs +!/logs/.gitkeep +/app-storage +!/app-storage/.gitkeep +.env +laravel.env diff --git a/2-docker-nginx-with-database/docker-compose.yml b/2-docker-nginx-with-database/docker-compose.yml new file mode 100644 index 0000000..475750e --- /dev/null +++ b/2-docker-nginx-with-database/docker-compose.yml @@ -0,0 +1,104 @@ +services: + app: + restart: always + image: "solidtime/solidtime:${SOLIDTIME_IMAGE_TAG:-latest}" + user: "1000:1000" + networks: + - internal + volumes: + - "app-storage:/var/www/html/storage" + - "./logs:/var/www/html/storage/logs" + - "./app-storage:/var/www/html/storage/app" + environment: + CONTAINER_MODE: http + healthcheck: + test: [ "CMD-SHELL", "curl --fail http://localhost:8000/health-check/up || exit 1" ] + env_file: + - laravel.env + depends_on: + - database + scheduler: + restart: always + image: "solidtime/solidtime:${SOLIDTIME_IMAGE_TAG:-latest}" + user: "1000:1000" + networks: + - internal + volumes: + - "app-storage:/var/www/html/storage" + - "./logs:/var/www/html/storage/logs" + - "./app-storage:/var/www/html/storage/app" + environment: + CONTAINER_MODE: scheduler + healthcheck: + test: [ "CMD-SHELL", "supervisorctl status scheduler:scheduler_00" ] + env_file: + - laravel.env + depends_on: + - database + queue: + restart: always + image: "solidtime/solidtime:${SOLIDTIME_IMAGE_TAG:-latest}" + user: "1000:1000" + networks: + - internal + volumes: + - "app-storage:/var/www/html/storage" + - "./logs:/var/www/html/storage/logs" + - "./app-storage:/var/www/html/storage/app" + environment: + CONTAINER_MODE: worker + WORKER_COMMAND: "php /var/www/html/artisan queue:work" + healthcheck: + test: [ "CMD-SHELL", "supervisorctl status worker:worker_00" ] + env_file: + - laravel.env + depends_on: + - database + database: + restart: always + image: 'postgres:15' +# ports: +# - '${FORWARD_DB_PORT:-5432}:5432' + environment: + PGPASSWORD: '${DB_PASSWORD:-secret}' + POSTGRES_DB: '${DB_DATABASE}' + POSTGRES_USER: '${DB_USERNAME}' + POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' + volumes: + - 'database-storage:/var/lib/postgresql/data' + networks: + - internal + healthcheck: + test: + - CMD + - pg_isready + - '-q' + - '-d' + - '${DB_DATABASE}' + - '-U' + - '${DB_USERNAME}' + retries: 3 + timeout: 5s + gotenberg: + image: gotenberg/gotenberg:8 + networks: + - internal + healthcheck: + test: [ "CMD", "curl", "--silent", "--fail", "http://localhost:3000/health" ] + nginx: + image: "nginx:latest" + restart: always + ports: + - "80:80" + volumes: + - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro + networks: + - internal + depends_on: + - app + +networks: + internal: +volumes: + database-storage: + app-storage: diff --git a/2-docker-nginx-with-database/laravel.env.example b/2-docker-nginx-with-database/laravel.env.example new file mode 100644 index 0000000..be7560d --- /dev/null +++ b/2-docker-nginx-with-database/laravel.env.example @@ -0,0 +1,46 @@ +APP_NAME="solidtime" +VITE_APP_NAME="solidtime" +APP_ENV="production" +APP_DEBUG="false" +APP_URL="http://your-domain.com" +APP_FORCE_HTTPS="false" +TRUSTED_PROXIES="0.0.0.0/0,2000:0:0:0:0:0:0:0/3" + +# Authentication +APP_KEY="" +PASSPORT_PRIVATE_KEY="" +PASSPORT_PUBLIC_KEY="" +SUPER_ADMINS="" + +# Logging +LOG_CHANNEL="stderr_daily" +LOG_LEVEL="debug" + +# Database +DB_CONNECTION="pgsql" +DB_HOST="database" +DB_PORT="5432" +DB_SSLMODE="require" +DB_DATABASE="solidtime" +DB_USERNAME="solidtime" +DB_PASSWORD="randompassword" + +# Mail +MAIL_MAILER="smtp" +MAIL_HOST="" +MAIL_PORT="" +MAIL_ENCRYPTION="tls" +MAIL_FROM_ADDRESS="no-reply@your-domain.com" +MAIL_FROM_NAME="solidtime" +MAIL_USERNAME="" +MAIL_PASSWORD="" + +# Queue +QUEUE_CONNECTION="database" + +# File storage +FILESYSTEM_DISK="local" +PUBLIC_FILESYSTEM_DISK="public" + +# Services +GOTENBERG_URL="http://gotenberg:3000" diff --git a/2-docker-nginx-with-database/nginx/nginx.conf b/2-docker-nginx-with-database/nginx/nginx.conf new file mode 100644 index 0000000..3757320 --- /dev/null +++ b/2-docker-nginx-with-database/nginx/nginx.conf @@ -0,0 +1,12 @@ +server { + listen 80; + server_name localhost; + + location / { + proxy_pass http://app:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} From df3478e472b765adc6d0980360aebb778f82f3f3 Mon Sep 17 00:00:00 2001 From: Kaspar Rosin Date: Tue, 18 Nov 2025 16:59:56 +0200 Subject: [PATCH 2/2] Add ssl configuration --- .../docker-compose.yml | 16 +++++- 2-docker-nginx-with-database/nginx/nginx.conf | 7 ++- .../nginx/ssl.conf.template | 21 +++++++ 2-docker-nginx-with-database/readme.md | 56 +++++++++++++++++++ 2-docker-nginx-with-database/webroot/.gitkeep | 2 + 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 2-docker-nginx-with-database/nginx/ssl.conf.template create mode 100644 2-docker-nginx-with-database/readme.md create mode 100644 2-docker-nginx-with-database/webroot/.gitkeep diff --git a/2-docker-nginx-with-database/docker-compose.yml b/2-docker-nginx-with-database/docker-compose.yml index 475750e..2199e38 100644 --- a/2-docker-nginx-with-database/docker-compose.yml +++ b/2-docker-nginx-with-database/docker-compose.yml @@ -89,16 +89,30 @@ services: image: "nginx:latest" restart: always ports: + - "443:443" - "80:80" volumes: - - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro + - ./nginx:/etc/nginx/conf.d:ro + - certs:/etc/letsencrypt + - ./webroot:/var/www/html networks: - internal depends_on: - app + certbot: + image: certbot/certbot + restart: unless-stopped + volumes: + - certs:/etc/letsencrypt + - ./webroot:/var/www/html + entrypoint: > + /bin/sh -c 'while true; do certbot renew; sleep 12h; done' + networks: + - internal networks: internal: volumes: database-storage: app-storage: + certs: diff --git a/2-docker-nginx-with-database/nginx/nginx.conf b/2-docker-nginx-with-database/nginx/nginx.conf index 3757320..2933b64 100644 --- a/2-docker-nginx-with-database/nginx/nginx.conf +++ b/2-docker-nginx-with-database/nginx/nginx.conf @@ -1,6 +1,11 @@ server { listen 80; - server_name localhost; + server_name _; + root /var/www/html; + + location /.well-known/acme-challenge/ { + try_files $uri =404; + } location / { proxy_pass http://app:8000; diff --git a/2-docker-nginx-with-database/nginx/ssl.conf.template b/2-docker-nginx-with-database/nginx/ssl.conf.template new file mode 100644 index 0000000..aec9f06 --- /dev/null +++ b/2-docker-nginx-with-database/nginx/ssl.conf.template @@ -0,0 +1,21 @@ +# Move this file to ssl.conf and replace solidtime.example.com with your domain +# after obtaining certificates with certbot. + +server { + listen 443 ssl http2; + server_name solidtime.example.com; + + ssl_certificate /etc/letsencrypt/live/solidtime.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/solidtime.example.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + location / { + proxy_pass http://app:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + diff --git a/2-docker-nginx-with-database/readme.md b/2-docker-nginx-with-database/readme.md new file mode 100644 index 0000000..8488ee5 --- /dev/null +++ b/2-docker-nginx-with-database/readme.md @@ -0,0 +1,56 @@ +# Example: Docker + Nginx + Let's Encrypt + +This example shows how to run solidtime with Docker, Nginx, and PostgreSQL. The stack starts on HTTP so Let's Encrypt can verify the domain, then switches to HTTPS once the first certificate is issued. + +## Prerequisites + +- [Docker](https://docs.docker.com/engine/install/) +- Public DNS record pointing your domain to the host running this compose stack + +## Installation + +1. Copy the example files and adjust the environment variables to your needs + +```bash +cp laravel.env.example laravel.env +cp .env.example .env +``` +Refer to the [Self-Hosting Docker guide](https://docs.solidtime.io/self-hosting/guides/docker#1-choose-the-example-that-fits-your-needs-the-best) for details on configuring these files and the broader deployment flow. + +2. (Only with Linux/Docker Engine) Correct the permissions of the `app-storage` and `logs` directories. + +```bash +chown -R 1000:1000 app-storage logs +``` + +3. Start the services. + +```bash +docker compose up -d +``` + +4. Request the first Let's Encrypt certificate. Replace the domain and email with your own values. + +```bash +docker compose run --rm certbot certonly \ + --webroot -w /var/www/html \ + --domain solidtime.example.com \ + --email you@example.com \ + --agree-tos --non-interactive +``` + +5. Copy the SSL template, update the domain placeholders in `nginx/ssl.conf`, then restart Nginx. + +```bash +cp nginx/ssl.conf.template nginx/ssl.conf +docker compose restart nginx +``` + +6. Start certbot so renewals run automatically every 12 hours. + +```bash +docker compose up -d certbot +``` + +To enforce HTTPS after verifying the certificate, update the `/` location in `nginx/nginx.conf` to `return 301 https://$host$request_uri;`. + diff --git a/2-docker-nginx-with-database/webroot/.gitkeep b/2-docker-nginx-with-database/webroot/.gitkeep new file mode 100644 index 0000000..139597f --- /dev/null +++ b/2-docker-nginx-with-database/webroot/.gitkeep @@ -0,0 +1,2 @@ + +