Skip to content

Commit 0d2dc70

Browse files
committed
chore: synchronize configurations and documentation
1 parent 7d70b7e commit 0d2dc70

4 files changed

Lines changed: 116 additions & 177 deletions

File tree

Dockerfile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# ╔═══════════════════════════════════════════════════════════════════════════╗
2-
# ║ Fly.io Deployment ║
3-
# ║ https://github.com/webees/gotify ║
2+
# ║ Gotify Deployment ║
43
# ╚═══════════════════════════════════════════════════════════════════════════╝
5-
FROM ghcr.io/gotify/server:2.8
4+
FROM ghcr.io/gotify/server:latest
65

76
# ── Build Args ────────────────────────────────────────────────────────────────
87
ARG TARGETARCH
@@ -14,7 +13,6 @@ ENV WORKDIR=/app \
1413
TZ="Asia/Shanghai" \
1514
OVERMIND_PROCFILE=/Procfile \
1615
OVERMIND_CAN_DIE=crontab \
17-
# Gotify settings
1816
GOTIFY_SERVER_PORT=8080 \
1917
GOTIFY_SERVER_TRUSTEDPROXIES='["127.0.0.1"]'
2018

@@ -63,6 +61,6 @@ RUN apt update && apt install -y --no-install-recommends \
6361
&& apt -y autoremove \
6462
&& rm -rf /var/lib/apt/lists/*
6563

66-
# Clear base image entrypoint to allow Overmind to manage processes
64+
# ── Startup ───────────────────────────────────────────────────────────────────
6765
ENTRYPOINT []
6866
CMD ["overmind", "start"]

README.md

Lines changed: 49 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![Fly.io](https://img.shields.io/badge/Fly.io-Deploy-purple?style=for-the-badge&logo=flydotio)](https://fly.io)
44
[![Docker](https://img.shields.io/badge/Docker-ghcr.io-blue?style=for-the-badge&logo=docker)](https://ghcr.io/webees/gotify)
5-
[![Gotify](https://img.shields.io/badge/Gotify-v2.6-green?style=for-the-badge)](https://github.com/gotify/server)
5+
[![Gotify](https://img.shields.io/badge/Gotify-Latest-green?style=for-the-badge)](https://github.com/gotify/server)
66
[![License](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](LICENSE)
77

88
> Production-ready Gotify on Fly.io with Caddy reverse proxy, Overmind process manager, and automated Restic backups to Cloudflare R2.
@@ -12,11 +12,11 @@
1212
| Component | Description |
1313
| :--- | :--- |
1414
| **Gotify** | Self-hosted push notification server |
15-
| **Caddy** | Automatic HTTPS, security headers, Cloudflare IP forwarding |
16-
| **Overmind** | Tmux-based process manager (graceful restarts) |
17-
| **Supercronic** | Cron daemon for containers |
18-
| **Restic** | Encrypted incremental backups with retention policy |
19-
| **msmtp** | Email notifications on backup failures |
15+
| **Caddy** | Reverse proxy with security headers and IP forwarding |
16+
| **Overmind** | Process manager for robust service orchestration |
17+
| **Supercronic** | Cron daemon for automated tasks |
18+
| **Restic** | Encrypted incremental backups to S3/R2 |
19+
| **msmtp** | Email notifications for system alerts |
2020

2121
## 🏗️ Architecture
2222

@@ -45,36 +45,41 @@
4545

4646
## 🚀 Quick Start
4747

48-
### 1. Create App & Volume
48+
### 1. Initialize Application
4949

5050
```bash
51+
# Login to Fly.io
5152
fly auth login
53+
54+
# Create application
5255
fly apps create gotify
56+
57+
# Import secrets from .env
5358
cat .env | fly secrets import
59+
60+
# Create storage volume
5461
fly volumes create app_data --region hkg --size 1
55-
fly deploy
56-
fly ssh console
5762
```
5863

59-
### 2. Configure Secrets
64+
### 2. Required Secrets Configuration
6065

6166
```bash
62-
# Required: Cloudflare R2 backup
63-
fly secrets set RESTIC_PASSWORD="your-password"
64-
fly secrets set RESTIC_REPOSITORY="s3:your-account-id.r2.cloudflarestorage.com/gotify"
65-
fly secrets set AWS_ACCESS_KEY_ID="your-r2-access-key"
66-
fly secrets set AWS_SECRET_ACCESS_KEY="your-r2-secret-key"
67+
# Domain configuration (Multiple domains: "a.com b.com")
68+
fly secrets set CADDY_DOMAINS="gotify.example.com"
6769

68-
# Optional: Custom domains (default: :80)
69-
fly secrets set CADDY_DOMAINS="gotify.example.com:80"
70+
# Restic / S3 backup settings
71+
fly secrets set RESTIC_PASSWORD="your-secure-password"
72+
fly secrets set RESTIC_REPOSITORY="s3:your-account-id.r2.cloudflarestorage.com/gotify"
73+
fly secrets set AWS_ACCESS_KEY_ID="your-r2-id"
74+
fly secrets set AWS_SECRET_ACCESS_KEY="your-r2-key"
7075

71-
# Optional: Email notifications
76+
# SMTP notification settings
7277
fly secrets set SMTP_HOST="smtp.gmail.com"
7378
fly secrets set SMTP_PORT="587"
74-
fly secrets set SMTP_FROM="your@email.com"
75-
fly secrets set SMTP_TO="notify@email.com"
76-
fly secrets set SMTP_USERNAME="your@email.com"
77-
fly secrets set SMTP_PASSWORD="app-password"
79+
fly secrets set SMTP_FROM="sender@example.com"
80+
fly secrets set SMTP_TO="admin@example.com"
81+
fly secrets set SMTP_USERNAME="sender@example.com"
82+
fly secrets set SMTP_PASSWORD="app-specific-password"
7883
```
7984

8085
### 3. Deploy
@@ -83,105 +88,46 @@ fly secrets set SMTP_PASSWORD="app-password"
8388
fly deploy
8489
```
8590

86-
## 🛠️ Management
87-
88-
### Fly CLI
91+
## 🛠️ Management & Operations
8992

90-
> Use `-a <app-name>` to specify app when not in project directory.
93+
### Deployment CLI
9194

9295
```bash
93-
# SSH into container
94-
fly ssh console
95-
fly ssh console -a gotify
96-
97-
# View logs
98-
fly logs
99-
fly logs -a gotify
100-
101-
# Deploy
102-
fly deploy
103-
fly deploy -a gotify
104-
105-
# Manage secrets
106-
fly secrets list -a gotify
107-
fly secrets set KEY=value -a gotify
108-
109-
# App status
110-
fly status -a gotify
111-
fly apps list
112-
113-
# Scale & restart
114-
fly scale count 1 -a gotify
115-
fly apps restart gotify
96+
fly status # Check application status
97+
fly logs # View real-time logs
98+
fly ssh console # Access container shell
99+
fly apps restart # Restart all instances
116100
```
117101

118-
### Backup Commands (via SSH)
102+
### Backup Operations (via SSH)
119103

120104
```bash
121105
/restic.sh backup # Run manual backup
122106
/restic.sh snapshots # List all snapshots
123-
/restic.sh restore <id> # Restore from snapshot
107+
/restic.sh restore <id> # Restore from specific snapshot
108+
/restic.sh test # Test email notifications
124109
```
125110

126-
### View Logs (via SSH)
111+
### Log Inspection
127112

128113
```bash
129-
cat /var/log/restic/*.log # Backup logs
130-
tail -f /var/log/msmtp.log # Email logs
114+
cat /var/log/restic/*.log # Check backup logs
115+
tail -f /var/log/msmtp.log # Monitor email logs
131116
```
132117

133-
## 📁 Configuration
134-
135-
| File | Purpose |
136-
| :--- | :--- |
137-
| `config/Caddyfile` | Reverse proxy, security headers |
138-
| `config/Procfile` | Process definitions for Overmind |
139-
| `config/crontab` | Backup schedule (default: hourly) |
140-
| `scripts/restic.sh` | Backup script with email alerts |
141-
142-
## 🔒 Security
143-
144-
- **HSTS**: Strict-Transport-Security enabled
145-
- **XSS Protection**: X-XSS-Protection header
146-
- **Clickjacking**: X-Frame-Options DENY
147-
- **MIME Sniffing**: X-Content-Type-Options nosniff
148-
- **No Indexing**: X-Robots-Tag noindex, nofollow
149-
- **Cloudflare**: CF-Connecting-IP forwarded as X-Real-IP
118+
## 🔐 Security Headers
150119

151-
## 📊 Backup Retention
152-
153-
| Period | Kept |
154-
| :--- | :--- |
155-
| Daily | 7 |
156-
| Weekly | 4 |
157-
| Monthly | 3 |
158-
| Yearly | 3 |
159-
160-
## 🔧 Environment Variables
161-
162-
| Variable | Required | Description |
163-
| :--- | :--- | :--- |
164-
| `CADDY_DOMAINS` || Caddy domains (default: `:80`) |
165-
| `RESTIC_PASSWORD` || Encryption password for backups |
166-
| `RESTIC_REPOSITORY` || R2 URL: `s3:<account-id>.r2.cloudflarestorage.com/<bucket>` |
167-
| `AWS_ACCESS_KEY_ID` || Cloudflare R2 Access Key ID |
168-
| `AWS_SECRET_ACCESS_KEY` || Cloudflare R2 Secret Access Key |
169-
| `SMTP_HOST` || SMTP server for notifications |
170-
| `SMTP_PORT` || SMTP port (default: 587) |
171-
| `SMTP_FROM` || Sender email address |
172-
| `SMTP_TO` || Recipient for backup alerts |
173-
| `SMTP_USERNAME` || SMTP authentication user |
174-
| `SMTP_PASSWORD` || SMTP authentication password |
175-
176-
## 📚 References
177-
178-
- [Gotify Documentation](https://gotify.net/docs/)
179-
- [Gotify GitHub](https://github.com/gotify/server)
120+
The Caddy configuration automatically applies the following security posture:
121+
- **HSTS**: `Strict-Transport-Security` (1 year)
122+
- **Clickjacking**: `X-Frame-Options DENY`
123+
- **MIME Sniffing**: `X-Content-Type-Options nosniff`
124+
- **XSS Protection**: `X-XSS-Protection 1; mode=block`
125+
- **Privacy**: `Referrer-Policy strict-origin-when-cross-origin`
126+
- **Indexing**: `X-Robots-Tag noindex, nofollow`
180127

181128
## 📝 License
182129

183-
MIT
130+
Distributed under the [MIT License](LICENSE).
184131

185132
---
186-
187-
Made with ❤️ for 🔔
133+
🚀 Optimized for Fly.io by **[WeBees](https://github.com/webees)**

config/Caddyfile

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
admin off
99
persist_config off
1010

11+
# Trust Fly.io private networking for accurate IP parsing
1112
servers {
1213
trusted_proxies static private_ranges
1314
}
@@ -27,41 +28,43 @@
2728
}
2829

2930
# Domain Access Control
30-
@outside_domain {
31-
expression `{env.CADDY_DOMAINS} != ""`
32-
not host {$CADDY_DOMAINS:placeholder}
31+
@allowed_domain {
32+
# If CADDY_DOMAINS is not set, allow all
33+
expression {env.CADDY_DOMAINS} == ""
34+
# Or if the host matches the allowed list
35+
host {$CADDY_DOMAINS}
3336
}
34-
handle @outside_domain {
35-
respond "Access Denied: Domain not allowed" 403
36-
}
37-
38-
# Main Reverse Proxy Logic
39-
handle {
40-
encode zstd gzip
4137

42-
# Harden security posture
43-
header {
44-
# Infrastructure protection
45-
Strict-Transport-Security "max-age=31536000;"
46-
X-Content-Type-Options "nosniff"
47-
X-Frame-Options "DENY"
48-
X-XSS-Protection "1; mode=block"
38+
# Deny everything else if CADDY_DOMAINS is set
39+
handle @allowed_domain {
40+
# Main Reverse Proxy Logic
41+
handle {
42+
encode zstd gzip
4943

50-
# Privacy & Anti-tracking
51-
Referrer-Policy "strict-origin-when-cross-origin"
52-
Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
53-
X-Robots-Tag "noindex, nofollow"
44+
# Harden security posture
45+
header {
46+
Strict-Transport-Security "max-age=31536000;"
47+
X-Content-Type-Options "nosniff"
48+
X-Frame-Options "DENY"
49+
X-XSS-Protection "1; mode=block"
50+
Referrer-Policy "strict-origin-when-cross-origin"
51+
Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
52+
X-Robots-Tag "noindex, nofollow"
53+
-Server
54+
-X-Powered-By
55+
-Last-Modified
56+
}
5457

55-
# Hide sensitive headers
56-
-Server
57-
-X-Powered-By
58-
-Last-Modified
58+
# Proxy to the application backend
59+
reverse_proxy 127.0.0.1:8080 {
60+
header_up X-Real-IP {http.request.header.Fly-Client-IP}
61+
header_up X-Forwarded-For {http.request.header.Fly-Client-IP}
62+
}
5963
}
64+
}
6065

61-
# Proxy to the application backend
62-
reverse_proxy 127.0.0.1:8080 {
63-
header_up X-Real-IP {http.request.header.Fly-Client-IP}
64-
header_up X-Forwarded-For {http.request.header.Fly-Client-IP}
65-
}
66+
# Fallback for denied domains
67+
handle {
68+
respond "Access Denied: Domain not allowed" 403
6669
}
6770
}

0 commit comments

Comments
 (0)