Added deployment docs (#228)

* Added deployment docs

* Fix lint

---------

Co-authored-by: Karl Ludwig Weise <ludwig@ludwigweise.de>
This commit is contained in:
Karl Ludwig Weise
2026-03-11 11:58:59 +01:00
committed by GitHub
co-authored by Karl Ludwig Weise
parent c710142295
commit 010855efa8
3 changed files with 72 additions and 55 deletions
+1 -25
View File
@@ -1,27 +1,14 @@
# Production Caddyfile for appointment booking application
# Replace your-domain.com with your actual domain
# Replace your-admin-domain.com with your actual admin domain
{
on_demand_tls {
ask http://app:3000/api/public/domains
burst 5
interval 60s
}
}
:443 {
reverse_proxy app:3000
# Security headers
header {
-Server
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'"
}
encode gzip
log {
@@ -41,17 +28,6 @@
your-admin-domain.com {
reverse_proxy app:3000
# Security headers
header {
-Server
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'"
}
encode gzip
log {
+42 -30
View File
@@ -1,9 +1,8 @@
services:
postgres:
image: postgres:16-alpine
container_name: open-reception-postgres
container_name: postgres
restart: unless-stopped
user: postgres
environment:
POSTGRES_DB_FILE: /run/secrets/postgres_db
POSTGRES_USER_FILE: /run/secrets/postgres_user
@@ -15,7 +14,6 @@ services:
- postgres_password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d:ro
networks:
- open-reception-internal
healthcheck:
@@ -24,10 +22,10 @@ services:
"CMD-SHELL",
"pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)",
]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
interval: 5s
timeout: 3s
retries: 10
start_period: 60s
security_opt:
- no-new-privileges:true
cap_drop:
@@ -44,23 +42,25 @@ services:
read_only: true
app:
image: openreception/open-reception:${VERSION:-latest}
container_name: open-reception-app
# use specific version here to watch for breaking changes
image: openreception/open-reception:latest
container_name: app
restart: unless-stopped
user: "1001:1001"
environment:
NODE_ENV: production
SMTP_HOST: /run/secrets/smtp_host
SMTP_PORT: /run/secrets/smtp_port
SMTP_SECURE: /run/secrets/smtp_secure
SMTP_USER: /run/secrets/smtp_user
SMTP_PASS: /run/secrets/smtp_pass
SMTP_FROM_NAME: /run/secrets/smtp_from_name
SMTP_FROM_EMAIL: /run/secrets/smtp_from_email
secrets:
- postgres_db
- postgres_user
- postgres_password
- smtp_host
- smtp_port
- smtp_secure
- smtp_user
- smtp_pass
- smtp_from_name
- smtp_from_email
- jwt_secret
depends_on:
postgres:
condition: service_healthy
@@ -71,8 +71,8 @@ services:
["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
retries: 5
start_period: 60s
security_opt:
- no-new-privileges:true
cap_drop:
@@ -85,26 +85,30 @@ services:
export POSTGRES_USER=$$(cat /run/secrets/postgres_user)
export POSTGRES_PASSWORD=$$(cat /run/secrets/postgres_password)
export DATABASE_URL=\"postgres://$$POSTGRES_USER:$$POSTGRES_PASSWORD@postgres:5432/$$POSTGRES_DB\"
export SMTP_HOST=$$(cat /run/secrets/smtp_host)
export SMTP_PORT=$$(cat /run/secrets/smtp_port)
export SMTP_SECURE=$$(cat /run/secrets/smtp_secure)
export SMTP_USER=$$(cat /run/secrets/smtp_user)
export SMTP_PASS=$$(cat /run/secrets/smtp_pass)
export SMTP_FROM_NAME=$$(cat /run/secrets/smtp_from_name)
export SMTP_FROM_EMAIL=$$(cat /run/secrets/smtp_from_email)
export JWT_SECRET=$$(cat /run/secrets/jwt_secret)
exec node build/index.js
"
read_only: true
caddy:
image: caddy:2-alpine
container_name: open-reception-caddy
image: caddy:2
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
- caddy-data:/data"
networks:
- open-reception-internal
depends_on:
app:
condition: service_healthy
security_opt:
- no-new-privileges:true
cap_drop:
@@ -119,10 +123,10 @@ secrets:
file: ./secrets/postgres_user.txt
postgres_password:
file: ./secrets/postgres_password.txt
smtp_port:
file: ./secrets/smtp_port.txt
smtp_host:
file: ./secrets/smtp_host.txt
smtp_port:
file: ./secrets/smtp_port.txt
smtp_secure:
file: ./secrets/smtp_secure.txt
smtp_user:
@@ -133,14 +137,22 @@ secrets:
file: ./secrets/smtp_from_name.txt
smtp_from_email:
file: ./secrets/smtp_from_email.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
volumes:
postgres_data:
driver: local
caddy_data:
driver: local
caddy_config:
driver_opts:
type: none
o: bind
device: /opt/openreception/postgres
caddy-data:
driver: local
driver_opts:
type: "none"
o: "bind"
device: "/opt/openreception/caddy/data"
networks:
open-reception-internal:
+29
View File
@@ -0,0 +1,29 @@
# Deploy OpenReception to a single server
This guide will lead you through setting up OpenReception on linux a server of your choice.
> Too complicated? Managed Hosting is available at [open-reception.com](https://open-reception.com).
## Requirements
This setup requires
- shell access to a root server
- docker with docker compose installed
- a small server with 2 cores and 2gb of ram should get you started
## Recommendations/ Considerations
- Update your operating system on a regular basis. Use automatic security updates like `unattended-upgrades` for the very short term issues.
- Encrypt the drive where your database is stored to prevent data theft by just pulling the hard drive. You can use `luks`.
- Protect access with `fail2ban`, `ufw`, `crowdsec`, proper user permissions and other best-practices.
- Make regular backups of your database and test them regularly. You can use `restic`.
- Monitor your server loads and logs over time to detect peak usages (with insufficient ram or cpu power) and malicious activities.
## Setup
1. Use our [production docker-compose example](../docker-compose.prod.yml)
1. Use our [Caddyfile example](../Caddyfile)
1. Adjust the settings in these two files above to your needs.
1. Run `docker-compose up -d` or `docker compose up -d` depending on your docker installation.
1. Proceed to secure your instance by opening your admin domain in a browser.