Skip to content
Draft
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
7 changes: 7 additions & 0 deletions 2-docker-nginx-with-database/.env.example
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions 2-docker-nginx-with-database/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/logs
!/logs/.gitkeep
/app-storage
!/app-storage/.gitkeep
.env
laravel.env
118 changes: 118 additions & 0 deletions 2-docker-nginx-with-database/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
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:
- "443:443"
- "80:80"
volumes:
- ./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:
46 changes: 46 additions & 0 deletions 2-docker-nginx-with-database/laravel.env.example
Original file line number Diff line number Diff line change
@@ -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"
17 changes: 17 additions & 0 deletions 2-docker-nginx-with-database/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
server {
listen 80;
server_name _;
root /var/www/html;

location /.well-known/acme-challenge/ {
try_files $uri =404;
}

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;
}
}
21 changes: 21 additions & 0 deletions 2-docker-nginx-with-database/nginx/ssl.conf.template
Original file line number Diff line number Diff line change
@@ -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;
}
}

56 changes: 56 additions & 0 deletions 2-docker-nginx-with-database/readme.md
Original file line number Diff line number Diff line change
@@ -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;`.

2 changes: 2 additions & 0 deletions 2-docker-nginx-with-database/webroot/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@