feat: Add new Portainer stacks, setup scripts, and configurations for various services including filebrowser, paperless, and firefly.

This commit is contained in:
2026-02-22 11:53:11 -05:00
commit 33ddf7705e
28 changed files with 1164 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
# Define base path
BASE="/volume1/docker/audiobookshelf"
MEDIABASE="/volume1/media"
# Create folders
mkdir -p "${BASE}/config" "${BASE}/metadata" "${MEDIABASE}/audiobooks" "${MEDIABASE}/podcasts"
# Set ownership and permissions
chmod -R 750 "${BASE}"
chmod -R 750 "${MEDIABASE}/audiobooks"
chmod -R 750 "${MEDIABASE}/podcasts"

View File

@@ -0,0 +1,19 @@
version: "3.9"
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
restart: unless-stopped
#this docker image only works with root
ports:
- "13378:80"
environment:
- TZ=America/Toronto
volumes:
- /volume1/docker/audiobookshelf/config:/config
- /volume1/docker/audiobookshelf/metadata:/metadata
- /volume1/media/audiobooks:/audiobooks
- /volume1/media/podcasts:/podcasts

View File

@@ -0,0 +1,11 @@
# Define base path
BASE="/volume1/docker/calibre-web-automated"
# Create folders
mkdir -p "${BASE}/config" "${BASE}/plugins"
# Set ownership and permissions
chown -R 1029:65538 "${BASE}"
# Set ownership and permissions
chmod -R 750 "${BASE}"

View File

@@ -0,0 +1,249 @@
[General]
DictionaryRecentSearches=generously, hordes, idiosyncrasy, taxidermy, taxidermitry, taxidermist, sacrilegious, savoury, savory, juxtaposed
LibraryRecentSearches=unsee, "Life 3.0: Being Human in the Age of Artificial Intelligence"
StoreRecentSearches=the chaos machine, the chaos, science fiction, man search for meaning, "Artemis (Andy Weir)", "Project Hail Mary (Andy Weir)", poor economics, poor ecnomics, "The New Jim Crow: Mass Incarceration in the Age of Colorblindness by Michelle Alexander | Conversation Starters (dailyBooks)", "The Ride of a Lifetime (Robert Iger)"
[ApplicationPreferences]
AIRPLANE_MODE=false
BookstoreViewVisitCount=2
BorrowDialogShown=true
CurrentLocale=en
DesktopSyncCount=2
DictionaryOpenCount=-1
DuplicateAnnotationsCleanedUp=true
EarliestChangeLog=4.13.12410
HomePageViewVisitCount=30
IntegratedBrowseDialogShown=true
IntegratedBrowseDialogTime=@Variant(\0\0\0\x10\0%\x8a:\x4\xaem\xb1\xff)
KoboPlusPromoShown=true
LargePrintMode=false
LastAffiliateSyncTime=@Variant(\0\0\0\x10\0%\x8d|\0\xf2\x8d<\x2)
LastAuthorsListSorter_authorList_=sortByFirstName()
LastFTEStep=LOGIN
LastLibrarySorter_articles_filterByArticles%28%29=sortByDateAdded()
LastLibrarySorter_author_filterByAuthor%28Brian%20Christian%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Brian%20W.%20Kernighan%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28David%20Graeber%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Ethan%20Siegel%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Jason%20Fung%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Kevin%20Horsley%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Monty%20Lyman%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Nassim%20Nicholas%20Taleb%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28PhD%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Richard%20Dawkins%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Robert%20Iger%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28Simon%20Winchester%29=sortByNewest()
LastLibrarySorter_author_filterByAuthor%28the%20free%29=sortByNewest()
LastLibrarySorter_books_filterByAllItems%28%29=sortByNewest()
LastLibrarySorter_series_filterBySeries%285890ad21-74d9-5c72-a9f7-81d8523c33aa%29=sortByBookNumber()
LastLibrarySorter_series_filterBySeries%28fa6daece-c358-5efe-82ff-c860dca7fa96%29=sortByBookNumber()
LastLibrarySorter_shelf_filterByBookshelf%28Incerto%29=sortByNewest()
LastLibrarySorter_shelf_filterByBookshelf%28Kobo%20Forma%29=sortByNewest()
LastLibrarySorter_shelf_filterByBookshelf%28Kobo%29=sortByNewest()
LastLibrarySorter_shelf_filterByBookshelf%28Oakville%20Library%29=sortByNewest()
LastLibrarySorter_shelf_filterByBookshelf%28Photography%29=sortByNewest()
LastLibrarySubFilter_ManageBooks_filterByAllItems%28%29=
LastLibrarySubFilter_articles_filterByArticles%28%29=
LastLibrarySubFilter_author_filterByAuthor%28Brian%20Christian%29=
LastLibrarySubFilter_author_filterByAuthor%28Brian%20W.%20Kernighan%29=
LastLibrarySubFilter_author_filterByAuthor%28David%20Graeber%29=
LastLibrarySubFilter_author_filterByAuthor%28Ethan%20Siegel%29=
LastLibrarySubFilter_author_filterByAuthor%28Jason%20Fung%29=
LastLibrarySubFilter_author_filterByAuthor%28Kevin%20Horsley%29=
LastLibrarySubFilter_author_filterByAuthor%28Monty%20Lyman%29=
LastLibrarySubFilter_author_filterByAuthor%28Nassim%20Nicholas%20Taleb%29=
LastLibrarySubFilter_author_filterByAuthor%28PhD%29=
LastLibrarySubFilter_author_filterByAuthor%28Richard%20Dawkins%29=
LastLibrarySubFilter_author_filterByAuthor%28Robert%20Iger%29=
LastLibrarySubFilter_author_filterByAuthor%28Simon%20Winchester%29=
LastLibrarySubFilter_author_filterByAuthor%28the%20free%29=
LastLibrarySubFilter_books_filterByAllItems%28%29=
LastLibrarySubFilter_series_filterBySeries%285890ad21-74d9-5c72-a9f7-81d8523c33aa%29=
LastLibrarySubFilter_series_filterBySeries%28fa6daece-c358-5efe-82ff-c860dca7fa96%29=
LastLibrarySubFilter_shelf_filterByBookshelf%28Incerto%29=
LastLibrarySubFilter_shelf_filterByBookshelf%28Kobo%20Forma%29=
LastLibrarySubFilter_shelf_filterByBookshelf%28Kobo%29=
LastLibrarySubFilter_shelf_filterByBookshelf%28Oakville%20Library%29=
LastLibrarySubFilter_shelf_filterByBookshelf%28Photography%29=
LastLibraryTab=Collections
LastLibraryViewType_articles=viewBy3x3ArticleGrid()
LastLibraryViewType_author=viewBy5List()
LastLibraryViewType_books=viewBy5List()
LastLibraryViewType_series=viewBy5List()
LastLibraryViewType_seriesList=viewBy5List()
LastLibraryViewType_shelf=viewBy5Shelf()
LastManageBooksSorter_ManageBooks_filterByAllItems%28%29=sortByNewest()
LastMostPopularSyncTime=@Variant(\0\0\0\x10\0%\x8d|\x3\x9b\x45L\x2)
LastSearchType_Home=Library
LastSearchType_Library=Dictionary
LastSearchType_ReadingView=Dictionary
LastSearchType_Store=OverDrive
LastSeriesListSorter_seriesList_=sortByRecent()
LastShelfListSorter_shelfList_=sortByShelfName()
LastShelfListSorter_shelfList_filterByAddToShelf=sortByShelfName()
LastShelfSorter_books_filterByAllItems%28%29=sortByNewest()
LastSimilarLibrarySorter_books_filterByAllItems%28%29=sortByNewest()
LastStoreTab=eBooks
LastSyncTime=@Variant(\0\0\0\x10\0%\x8d|\x3\x9f\x13\xe3\x2)
LastTopPicksSyncTime=@Variant(\0\0\0\x10\0%\x8d|\0\xf3w\xe9\x2)
LastUpdateCheckTime=@Variant(\0\0\0\x10\0%\x8d|\x3\x9b\x37\xae\x2)
LibraryCuratedListsDialogShown=true
LibraryViewVisitCount=30
LongPressDialogShown=true
MarkAsFinishedLastShown=@Variant(\0\0\0\x10\0%\x8c\xc1\x1\xe8p\xcf\xff)
MarkAsUnreadLastShown=@Variant(\0\0\0\x10\0%\x8b\xf1\x3\x41\xddM\xff)
MostRecentReadID=99a8b0c9-94cd-400d-bef1-2b3fdb4a2cb7
OverDriveExpiryDialogShown=true
OverDriveFilterShown=true
OverDriveHoldListSorter_overDriveHoldList_=sortByEstimatedWait()
QuickTourWidgetShown=true
ReadABookShown2=true
ReadingSettingsChanged=true
SearchResultsviewVisitCount=2
SignInTime=@Variant(\0\0\0\x10\0%\x8a:\x4\xa6\n:\xff)
SmartLink_%05=3
SmartLink_%06=3
SmartLink_%07=3
SmartLink_%08=404
StylusTipWarning=true
SubscriptionPlanAbTestEnabled=true
SwipeDialogShown=true
VisitedFrontLightLearnMore=true
WifiRegulatoryDomain=CA
WifiReminderDialogShown=true
firstRotateDone=true
firstRunDate=@Variant(\0\0\0\x10\0%\x84\xd3\x4\x3\xb5\x92\x2)
hasSyncedExistingRelatedItems=true
lastPlugTime=@Variant(\0\0\0\x10\0%\x8d|\0\xf4\x16\xe3\x2)
lockedOrientation=5
sleepOnNextBoot=false
syncOnNextBoot=false
[Browser]
certExceptions=@Variant(\0\0\0\x1c\0\0\0\x2\0\0\0\x32\0s\0\x65\0r\0v\0i\0\x63\0\x65\0.\0m\0\x61\0x\0y\0m\0i\0s\0\x65\0r\0.\0n\0\x65\0t\0:\0\x34\0\x34\0\x33\0\0\0\f\0\0\0 [\x81P\xc8\xd0:0\x86\x43\xe1t4\x8a`B\xb1\xee\xf2{\xa4]\xda}\xfe\xad\xb3\x65\x96\x33\xb2\x89\x9d\0\0\0$\0w\0w\0w\0.\0h\0i\0l\0t\0o\0n\0.\0\x63\0o\0m\0:\0\x34\0\x34\0\x33\0\0\0\f\0\0\0 [\x81P\xc8\xd0:0\x86\x43\xe1t4\x8a`B\xb1\xee\xf2{\xa4]\xda}\xfe\xad\xb3\x65\x96\x33\xb2\x89\x9d)
[DialogSettings]
InstapaperJitShown=true
ReleaseNotesShown=true
ReturningReaderDialogShown=true
[DropboxSettings]
AccessToken=G8wEe4GjZ0cAAAAAAAAa0CEDDyC4crP51r89PTM_XzhanzFFEUqsTgQAArJSVym6
SortType=sortByModifiedDate()
UserGuideId=id:4gkVQTWkSR8AAAAAAAAMqA
Username=jianfeng.cheng@gmail.com
[FeatureSettings]
ExcludeSyncFolders=(\\.(?!kobo|adobe).+|([^.][^/]*/)+\\..+)
[OneStoreServices]
account_page=https://www.kobo.com/account/settings
account_page_rakuten=https://my.rakuten.co.jp/
annotations_host=https://annotations.kobo.com
api_endpoint=http://10.168.168.5:8083/kobo/4020539f4c3a97748766f2895cd717a9
autocomplete=https://storeapi.kobo.com/v1/products/autocomplete
book=https://storeapi.kobo.com/v1/products/books/{ProductId}
book_detail_page=https://www.kobo.com/{region}/{language}/ebook/{slug}
book_detail_page_rakuten=http://books.rakuten.co.jp/rk/{crossrevisionid}
book_landing_page=https://www.kobo.com/ebooks
categories=https://storeapi.kobo.com/v1/categories
category=https://storeapi.kobo.com/v1/categories/{CategoryId}
category_products=https://storeapi.kobo.com/v1/categories/{CategoryId}/products
dictionary_host=https://ereaderfiles.kobo.com
discovery_host=https://discovery.kobobooks.com
display_accessibility_enabled=
display_parental_controls_enabled=
dropbox_link_account_poll=
eula_page="https://www.kobo.com/termsofuse?style=onestore"
featured_list=https://storeapi.kobo.com/v1/products/featured/{FeaturedListId}
featured_lists=https://storeapi.kobo.com/v1/products/featured
feedback=
fte_feedback=https://storeapi.kobo.com/v1/products/ftefeedback
googledrive_link_account_start=
image_host=http://10.168.168.5:8083
image_url_quality_template=http://10.168.168.5:8083/kobo/4020539f4c3a97748766f2895cd717a9/{ImageId}/{width}/{height}/{Quality}/isGreyscale/image.jpg
image_url_template=http://10.168.168.5:8083/kobo/4020539f4c3a97748766f2895cd717a9/{ImageId}/{width}/{height}/false/image.jpg
instapaper_enabled=
instapaper_env_url=
instapaper_link_account_start=
kobo_audiobooks_credit_redemption=False
kobo_audiobooks_enabled=True
kobo_dropbox_link_account_enabled=False
kobo_googledrive_link_account_enabled=False
kobo_nativeborrow_enabled=False
kobo_privacyCentre_url=https://www.kobo.com/privacy
kobo_redeem_enabled=True
kobo_subscriptions_enabled=True
kobo_superpoints_enabled=True
kobo_wishlist_enabled=True
love_data=@ByteArray(\0\0\0\x1\0\0\0\x10\0\x42\0\x65\0n\0\x65\0\x66\0i\0t\0s\0\0\0\b\0\0\0\0\0)
love_points_redemption_page="https://www.kobo.com/{region}/{language}/KoboSuperPointsRedemption?productId={ProductId}"
magazine_detail_page=
magazine_landing_page=https://store.kobobooks.com/emagazines
oauth_host=https://oauth.kobo.com
password_retrieval_page=https://www.kobo.com/passwordretrieval.html
pocket_link_account_start=https://authorize.kobo.com/{region}/{language}/linkpocket
privacy_page="https://www.kobo.com/privacypolicy?style=onestore"
product_recommendations=https://storeapi.kobo.com/v1/products/{ProductId}/recommendations
product_reviews=https://storeapi.kobo.com/v1/products/{ProductIds}/reviews
purchase_buy_templated=
reading_services_host=https://readingservices.kobo.com
registration_page="https://authorize.kobo.com/signup?returnUrl=http://kobo.com/"
review=https://storeapi.kobo.com/v1/products/reviews/{ReviewId}
review_sentiment=https://storeapi.kobo.com/v1/products/reviews/{ReviewId}/sentiment/{Sentiment}
sign_in_page="https://authorize.kobo.com/signin?returnUrl=http://kobo.com/"
social_authorization_host=https://social.kobobooks.com:8443
social_host=https://social.kobobooks.com
store_home=www.kobo.com/{region}/{language}
store_host=www.kobo.com
store_search="https://www.kobo.com/{region}/{language}/Search?Query={query}"
subs_landing_page=https://www.kobo.com/{region}/{language}/plus
subs_management_page=https://www.kobo.com/{region}/{language}/account/subscriptions
subs_plans_page=https://www.kobo.com/{region}/{language}/plus/plans
subs_purchase_buy_templated=https://www.kobo.com/{region}/{language}/Checkoutoption/{ProductId}/{TierId}
subscription_publisher_price_page=
taste_profile=https://storeapi.kobo.com/v1/products/tasteprofile
user_ratings=https://storeapi.kobo.com/v1/user/ratings
user_recommendations=https://storeapi.kobo.com/v1/user/recommendations
user_reviews=https://storeapi.kobo.com/v1/user/reviews
userguide_host=https://ereaderfiles.kobo.com
[OverDrive]
overdrive_account=https://auth.overdrive.com/account
overdrive_library=https://{libraryKey}.auth.overdrive.com/library
overdrive_library_finder_host=https://libraryfinder.api.overdrive.com
overdrive_thunder_host=https://thunder.api.overdrive.com
[PowerOptions]
AutoColorEnabled=true
BedTime=@Variant(\0\0\0\xf\x4\xefm\x80)
ColorSetting=2480
FrontLightLevel=29
[Reading]
chapterProgressType=3
deleteVolumeOnFinished=true
invertPageTurnButtons=false
newBookProgressType=0
numPartialUpdatePageTurns=1
readingAdobeShowPageNumbers=false
readingAlignment=
readingFontFamily=Amazon Ember
readingFontSharpness\AR%20UDJingxihei=-0.0666666666666667
readingFontSharpness\Bookerly=-0.0666666666666667
readingFontSharpness\KBJ-TsukuMin%20Pr6N%20RB=-0.28
readingFontSharpness\SonyReader%20Kai=-0.0666666666666667
readingFontSize=21
readingFontWeight\AR%20UDJingxihei=0.1
readingFontWeight\Bookerly=0.1
readingFontWeight\KBJ-TsukuMin%20Pr6N%20RB=-0.11
readingFontWeight\SonyReader%20Kai=0.1
readingLeftMargin=2
readingLineHeight=1.2
readingMenuState=
readingRightMargin=2
[ReadingLife]
LastActivityNavItem=1
LastReadingLifeSyncTime=@Variant(\0\0\0\x10\0%\x87-\x1\xd1\x38-\x2)
LastSocialAnnotationsSyncTime=@Variant(\0\0\0\x10\0%\x86~\x2H\xc2\xb0\x2)

View File

@@ -0,0 +1,9 @@
sqlite3 /config/app.db "SELECT * FROM kobo;"
http://10.168.168.5:8083/kobo/sync
http://10.168.168.5:8083/kobo
http://10.168.168.5:8083/kobo/0
http://10.168.168.5:8083/kobo/device

View File

@@ -0,0 +1,6 @@
-----BEGIN ARGO TUNNEL TOKEN-----
eyJ6b25lSUQiOiI3ZGY4MWRkMzM4NGI2MDU3ODBkZGYzZGNjYmQyOTI5MCIsImFj
Y291bnRJRCI6IjJmZWIxMWZkZDlmYTczYTJhYjQ4MDUyMjM4NmJkNzM1IiwiYXBp
VG9rZW4iOiJESmxwNFR3RzVUZlJUZlFRdmdwdlZZdUxodVI4cEhiXzNUVk9xeFJL
In0=
-----END ARGO TUNNEL TOKEN-----

43
cloudflared/commands.sh Normal file
View File

@@ -0,0 +1,43 @@
#cloudflare API token
# AutoUpdateIP WhAIOCeGjws2IFCD32BJn1r8TS1M8SWeGbEYVuVc
curl "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer WhAIOCeGjws2IFCD32BJn1r8TS1M8SWeGbEYVuVc"
#allow ping in cloudflared
sudo sysctl -w net.ipv4.ping_group_range="0 65535"
sudo mkdir -p /etc/sysctl.d
echo "net.ipv4.ping_group_range = 0 65535" | sudo tee /etc/sysctl.d/99-cloudflared.conf
docker exec cloudflare-tunnel tunnel create nas-tunnel
docker run -it --rm -v /volume1/docker/cloudflared:/etc/cloudflared cloudflare-tunnel tunnel login
docker run -it --rm \
-v /volume1/docker/cloudflared:/etc/cloudflared \
cloudflare/cloudflared:latest tunnel login
# tunnel uuid fb59f081-ac72-4fd9-bad3-9211b931d5e5
docker stop cloudflare-tunnel
docker rm cloudflare-tunnel
docker run -it --rm \
-v /volume1/docker/cloudflared:/root/.cloudflared \
-v /volume1/docker/cloudflared/etc:/etc/cloudflared \
cloudflare/cloudflared:latest tunnel login
docker run -it --rm \
-v /volume1/docker/cloudflared:/root/.cloudflared \
cloudflare/cloudflared:latest tunnel token nas

View File

@@ -0,0 +1,20 @@
# Define base path
BASE="/volume1/docker/cloudflared"
# Create folders
mkdir -p "${BASE}/etc"
# Set ownership and permissions
chown -R 1037:65538 "${BASE}"
chmod -R 750 "${BASE}"
# Define base path
BASE="/volume1/docker/ddns-updater"
# Create folders
mkdir -p "${BASE}"
# Set ownership and permissions
chown -R 1037:65538 "${BASE}"
chmod -R 750 "${BASE}"

View File

@@ -0,0 +1,14 @@
{
"settings": [
{
"provider": "cloudflare",
"zone_identifier": "7df81dd3384b605780ddf3dccbd29290",
"domain": "chengs.uk",
"host": "@",
"ttl": 600,
"proxied": true,
"token": "WhAIOCeGjws2IFCD32BJn1r8TS1M8SWeGbEYVuVc",
"ip_version": "ipv4"
}
]
}

View File

View File

@@ -0,0 +1,96 @@
# Docker Compose configuration for setting up a Cloudflare Tunnel container
#
# This configuration pulls the latest Cloudflare Tunnel image from the specified repository
# and includes options for logging, automatic updates using Watchtower, health checks, and volume mounting.
services:
# Cloudflare Tunnel Service
cloudflare-tunnel:
image: cloudflare/cloudflared:latest # Pull the latest version of the Cloudflare Tunnel image
container_name: cloudflare-tunnel # Name of the Cloudflare Tunnel container
hostname: cloudflare-tunnel # Hostname for the Cloudflare Tunnel container
user: root
restart: unless-stopped # Restart the container unless manually stopped
# Logging configuration for Cloudflare Tunnel container
logging:
driver: "json-file" # Use the default json-file logging driver
options:
max-size: "100m" # Maximum log file size before rotation (100 MB)
max-file: "10" # Maximum number of log files to retain (10)
# Network mode configuration
network_mode: "host" # Use the host network (no isolation between host and container)
# Command to run Cloudflare Tunnel
command: 'tunnel --no-autoupdate run' # Command to start the Cloudflare tunnel
# Volume configuration for time synchronization and hosts file persistence
volumes:
- /etc/localtime:/etc/localtime:ro # Synchronize time with the host
- /volume1/docker/cloudflared:/root/.cloudflared
- /volume1/docker/cloudflared/etc:/etc/cloudflared
#- ./config/hosts:/etc/hosts # Mount hosts file from host to container
# Environment variables for Cloudflare Tunnel
# cloudflared.exe service install eyJhIjoiMmZlYjExZmRkOWZhNzNhMmFiNDgwNTIyMzg2YmQ3MzUiLCJ0IjoiZmI1OWYwODEtYWM3Mi00ZmQ5LWJhZDMtOTIxMWI5MzFkNWU1IiwicyI6IllqWXdaVFEyTURrdFpHVXpPUzAwTnpNMkxUazJPREl0T0RGak9UZ3dOelV3Tm1ZeCJ9
environment:
- NO_AUTOUPDATE=true
- "TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}" # Pass the Cloudflare Tunnel token from environment variable
# Health check configuration to verify Cloudflare Tunnel readiness
healthcheck:
test: ["CMD", "cloudflared", "--version"] # Check if cloudflared version command works
interval: 30s # Time between health check attempts
timeout: 10s # Time to wait for a response
retries: 3 # Number of retries before marking as unhealthy
start_period: 10s # Delay before health checks begin
# Container labels for additional metadata
labels:
- "com.centurylinklabs.watchtower.enable=true" # Enable automatic updates with Watchtower
#
####################################################
# #
# -------DDNS-Updater------- #
# #
####################################################
#
ddns-updater:
container_name: ddns-updater
restart: always
hostname: ddns-updater
environment:
- TZ=America/Toronto
- PUID=$PUID
- PGID=$PGID
- PERIOD=5m
- UPDATE_COOLDOWN_PERIOD=5m
- PUBLICIP_FETCHERS=all
- PUBLICIP_HTTP_PROVIDERS=all
- PUBLICIPV4_HTTP_PROVIDERS=all
- PUBLICIPV6_HTTP_PROVIDERS=all
- PUBLICIP_DNS_PROVIDERS=all
- PUBLICIP_DNS_TIMEOUT=3s
- HTTP_TIMEOUT=10s
- LISTENING_PORT=8000
- HEALTH_SERVER_ADDRESS=127.0.0.1:9999
- ROOT_URL=/
- BACKUP_PERIOD=24h # 0 to disable
- BACKUP_DIRECTORY=/updater/data
- LOG_LEVEL=info
- LOG_CALLER=hidden
- SHOUTRRR_ADDRESSES=pushover://shoutrrr:$PUSHOVER_API@$PUSHOVER_USER_KEY
volumes:
- /volume1/docker/ddns-updater:/updater/data
ports:
- 8002:8000/tcp
user: $PUID:$PGID
image: 'qmcgaw/ddns-updater:latest'
#

View File

@@ -0,0 +1,35 @@
version: "3.9"
services:
openvscode:
image: ghcr.io/gitpod-io/openvscode-server:latest
container_name: openvscode
restart: unless-stopped
# Expose the web IDE
ports:
- "3000:3000"
# Persist extensions, settings, and workspace files
volumes:
- /volume1/docker/openvscode/config:/home/workspace/.openvscode-server
- /volume1/docker/openvscode/projects:/home/workspace/projects
# Optional: mount SSH keys for Gitea access
# Make sure permissions are correct (600)
# volumes:
# - /volume1/docker/ssh/id_rsa:/home/workspace/.ssh/id_rsa:ro
# - /volume1/docker/ssh/known_hosts:/home/workspace/.ssh/known_hosts:ro
environment:
# Ensures the server listens on all interfaces
OPENVSCODE_SERVER_HOST: "0.0.0.0"
OPENVSCODE_SERVER_PORT: "3000"
# Optional: put it on a shared network for Cloudflared or Traefik
networks:
- openvscode_net
networks:
openvscode_net:
driver: bridge

View File

@@ -0,0 +1,11 @@
services:
vert:
container_name: vert
image: ghcr.io/vert-sh/vert:latest
restart: unless-stopped
ports:
- 3002:80
environment:
- USER_UID=1039
- USER_GID=65538
- TZ=America/Toronto

View File

@@ -0,0 +1,18 @@
# Define base path
BASE="/volume1/docker/filebrowser"
# Create folders
mkdir -p "${BASE}/config" "${BASE}/database" "${BASE}/data"
# Set ownership and permissions
chown -R 1042:65538 "${BASE}"
chmod -R 750 "${BASE}"
touch "${BASE}/config/settings.json"
chown 1042:65538 "${BASE}/config/settings.json"
chmod 640 "${BASE}/config/settings.json"
touch "${BASE}/database/filebroser.db"
chown 1042:65538 "${BASE}/database/filebroser.db"
chmod 640 "${BASE}/database/filebroser.db"

View File

@@ -0,0 +1,16 @@
version: "3"
services:
filebrowser:
image: hurlenko/filebrowser
user: "1042:65538"
container_name: filebrowser
restart: unless-stopped
ports:
- 3020:8080
volumes:
- /volume1/docker/filebrowser/data:/data
- /volume1/docker/filebrowser/config:/config
environment:
- FB_BASEURL=/filebrowser

57
firefly/Categories.txt Normal file
View File

@@ -0,0 +1,57 @@
🟦 1. Housing
- Mortgage / Rent
- Property Tax
- Home Insurance
- Utilities (Hydro, Gas, Water)
- Internet
- Home Maintenance
- Furniture & Appliances
2. Transportation
- Fuel
- Public Transit
- Parking
- Car Insurance
- Car Maintenance
- Car Loan / Lease
- Ridesharing (Uber, Lyft)
🟦 3. Food & Dining
- Groceries
- Restaurants
- Coffee Shops
- Takeout / Delivery
🟦 4. Health & Wellness
- Health Insurance
- Dental
- Prescriptions
- Medical Services
- Gym / Fitness
- Therapy / Wellness
🟦 5. Personal & Family
- Clothing
- Personal Care (haircuts, cosmetics)
- Childcare
- School / Education
- Gifts
- Pets
🟦 6. Entertainment & Leisure
- Streaming Services
- Hobbies
- Books & Media
- Events / Tickets
- Travel
🟦 7. Financial
- Bank Fees
- Credit Card Interest
- Investment Contributions
- RRSP / TFSA / RESP
- Accountant / Legal Fees
🟦 8. Business / Work (optional)
- Software Subscriptions
- Office Supplies
- Professional Development
🟦 9. Miscellaneous
- Uncategorized
- Oneoff purchases

View File

@@ -0,0 +1,9 @@
# Define base path
BASE="/volume1/docker/fireflyiii"
# Create folders
mkdir -p "${BASE}/upload" "${BASE}/db"
# Set ownership and permissions
chown -R 1040:65538 "${BASE}"
chmod -R 750 "${BASE}"

45
firefly/dbcommand Normal file
View File

@@ -0,0 +1,45 @@
1uQ$g72*$9Gw4yFs
$2y$10$2OcSKhMVh6fXLVcxJ6gPx.jtJisfX/j5WM5DE8dAhIibH6hZp/2ze
INSERT INTO users (email, password, created_at, updated_at)
VALUES ('jeffcheng@live.ca', '$2y$10$2OcSKhMVh6fXLVcxJ6gPx.jtJisfX/j5WM5DE8dAhIibH6hZp/2ze', NOW(), NOW()
INSERT INTO user_groups (title, created_at, updated_at)
VALUES ('User group for jeffcheng@live.ca', NOW(), NOW());
SELECT id, title FROM user_groups ORDER BY id DESC LIMIT 1;
INSERT INTO user_group_membership (user_id, user_group_id, created_at, updated_at)
VALUES (2, 2, NOW(), NOW());
DROP DATABASE firefly;
CREATE DATABASE firefly CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
MULTIUSER=true
apt UPDATE
apt install mysql-client
mysql -u firefly -p
github token: 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

View File

@@ -0,0 +1,79 @@
#
# The Firefly III Data Importer will ask you for the Firefly III URL and a "Client ID".
# You can generate the Client ID at http://localhost/profile (after registering)
# The Firefly III URL is: http://app:8080
#
# Other URL's will give 500 | Server Error
#
services:
app:
image: fireflyiii/core:latest
hostname: app
container_name: firefly_iii_core
networks:
- firefly_iii
restart: always
volumes:
- /volume1/docker/fireflyiii/upload:/var/www/html/storage/upload
env_file: stack.env
ports:
- '8080:8080'
depends_on:
- db
db:
image: mariadb:lts
hostname: db
container_name: firefly_iii_db
networks:
- firefly_iii
restart: always
env_file: stack.env
volumes:
- /volume1/docker/fireflyiii/db:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
importer:
image: fireflyiii/data-importer:latest
hostname: importer
restart: always
container_name: firefly_iii_importer
networks:
- firefly_iii
ports:
- '8081:8080'
depends_on:
- app
env_file: stack.env
cron:
#
# To make this work, set STATIC_CRON_TOKEN in your .env file or as an environment variable
# The STATIC_CRON_TOKEN must be *exactly* 32 characters long
# Use this URL for inspiration: https://www.random.org/strings/?num=1&len=32&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new
#
image: alpine
container_name: firefly_iii_cron
restart: always
env_file: stack.env
command: sh -c "
apk add tzdata && \
(ln -fs /usr/share/zoneinfo/$$TZ /etc/localtime || true) && \
echo \"0 3 * * * wget -qO- http://app:8080/api/v1/cron/$$STATIC_CRON_TOKEN;echo\"
| crontab - && \
crond -f -L /dev/stdout"
networks:
- firefly_iii
depends_on:
- app
volumes:
firefly_iii_upload:
firefly_iii_db:
networks:
firefly_iii:
driver: bridge

View File

@@ -0,0 +1,80 @@
{
"version": 3,
"source": "ff3-importer-1.9.1",
"created_at": "2025-12-28T12:02:55-05:00",
"date": "d M Y",
"default_account": 9,
"delimiter": "comma",
"headers": true,
"rules": true,
"skip_form": false,
"add_import_tag": true,
"roles": [
"date_transaction",
"date_process",
"description",
"note",
"_ignore",
"amount_debit",
"amount_foreign",
"_ignore",
"_ignore",
"_ignore",
"_ignore",
"_ignore",
"_ignore",
"_ignore",
"_ignore",
"_ignore"
],
"do_mapping": [
true,
true,
true,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
],
"mapping": {},
"duplicate_detection_method": "classic",
"ignore_duplicate_lines": false,
"unique_column_index": 0,
"unique_column_type": "internal_reference",
"flow": "file",
"content_type": "csv",
"custom_tag": "Inbox",
"identifier": "0",
"connection": "0",
"ignore_spectre_categories": false,
"grouped_transaction_handling": "",
"use_entire_opposing_address": false,
"map_all_data": true,
"pending_transactions": false,
"access_token": "",
"accounts": {},
"new_accounts": [],
"date_range": "",
"date_range_number": 30,
"date_range_unit": "d",
"date_range_not_after_unit": "",
"date_range_not_after_number": 0,
"date_not_before": "",
"date_not_after": "",
"nordigen_country": "",
"nordigen_bank": "",
"nordigen_requisitions": {},
"nordigen_max_days": "90",
"lunch_flow_api_key": "",
"conversion": false,
"ignore_duplicate_transactions": true
}

165
firefly/stack.env Normal file
View File

@@ -0,0 +1,165 @@
# Firefly III
APP_ENV=production
APP_DEBUG=false
SITE_OWNER=mail@example.com
APP_KEY=cwj06oiSL03ua4auOUj6upS3X92QoSI3
DEFAULT_LANGUAGE=en_US
DEFAULT_LOCALE=equal
TZ=America/Toronto
TRUSTED_PROXIES=
LOG_CHANNEL=stack
APP_LOG_LEVEL=notice
AUDIT_LOG_LEVEL=emergency
AUDIT_LOG_CHANNEL=
PAPERTRAIL_HOST=
PAPERTRAIL_PORT=
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=m5wyMiU0CeEDmiptcZsCA2DC37Bsa5zH
DB_SOCKET=
MYSQL_USE_SSL=false
MYSQL_SSL_VERIFY_SERVER_CERT=true
MYSQL_SSL_CAPATH=/etc/ssl/certs/
MYSQL_SSL_CA=
MYSQL_SSL_CERT=
MYSQL_SSL_KEY=
MYSQL_SSL_CIPHER=
PGSQL_SSL_MODE=prefer
PGSQL_SSL_ROOT_CERT=null
PGSQL_SSL_CERT=null
PGSQL_SSL_KEY=null
PGSQL_SSL_CRL_FILE=null
PGSQL_SCHEMA=public
CACHE_DRIVER=file
SESSION_DRIVER=file
REDIS_SCHEME=tcp
REDIS_PATH=
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DB="0"
REDIS_CACHE_DB="1"
COOKIE_PATH="/"
COOKIE_DOMAIN=
COOKIE_SECURE=false
COOKIE_SAMESITE=lax
MAIL_MAILER=log
MAIL_HOST=null
MAIL_PORT=2525
MAIL_FROM=changeme@example.com
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_SENDMAIL_COMMAND=
MAIL_ALLOW_SELF_SIGNED=false
MAIL_VERIFY_PEER=true
MAIL_VERIFY_PEER_NAME=true
MAILGUN_DOMAIN=
MAILGUN_SECRET=
MAILGUN_ENDPOINT=api.mailgun.net
MANDRILL_SECRET=
SPARKPOST_SECRET=
MAILERSEND_API_KEY=
SEND_ERROR_MESSAGE=true
SEND_REPORT_JOURNALS=true
ENABLE_EXTERNAL_MAP=false
ENABLE_EXCHANGE_RATES=false
ENABLE_EXTERNAL_RATES=false
MAP_DEFAULT_LAT=51.983333
MAP_DEFAULT_LONG=5.916667
MAP_DEFAULT_ZOOM=6
VALID_URL_PROTOCOLS=
AUTHENTICATION_GUARD=web
AUTHENTICATION_GUARD_HEADER=REMOTE_USER
AUTHENTICATION_GUARD_EMAIL=
PASSPORT_PRIVATE_KEY=
PASSPORT_PUBLIC_KEY=
CUSTOM_LOGOUT_URL=
DISABLE_FRAME_HEADER=false
DISABLE_CSP_HEADER=false
TRACKER_SITE_ID=
TRACKER_URL=
REPORT_ERRORS_ONLINE=false
ALLOW_WEBHOOKS=false
STATIC_CRON_TOKEN=r6FLbFEYByBXy0kPBJEZzBADjPDYWxtl
DKR_CHECK_SQLITE=true
APP_NAME=FireflyIII
BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
CACHE_PREFIX=firefly
PUSHER_KEY=
IPINFO_TOKEN=
PUSHER_SECRET=
PUSHER_ID=
DEMO_USERNAME=
DEMO_PASSWORD=
USE_RUNNING_BALANCE=false
FIREFLY_III_LAYOUT=v1
QUERY_PARSER_IMPLEMENTATION=new
APP_URL=http://localhost
# Data Importer
FIREFLY_III_URL=http://app:8080
VANITY_URL=http://localhost
FIREFLY_III_ACCESS_TOKEN=
FIREFLY_III_CLIENT_ID=
LUNCH_FLOW_API_KEY=
LUNCH_FLOW_API_URL=https://lunchflow.app/api/v1/
NORDIGEN_ID=
NORDIGEN_KEY=
NORDIGEN_SANDBOX=false
RESPOND_TO_GOCARDLESS_LIMIT=wait
GOCARDLESS_GET_ACCOUNT_DETAILS=false
GOCARDLESS_GET_BALANCE_DETAILS=false
FALLBACK_LOCALE=en_US
SPECTRE_APP_ID=
SPECTRE_SECRET=
SIMPLEFIN_TOKEN=
SIMPLEFIN_DEMO_URL=
SIMPLEFIN_DEMO_TOKEN=
SIMPLEFIN_CONNECTION_TIMEOUT=30
SIMPLEFIN_REQUEST_TIMEOUT=60
SIMPLEFIN_RETRY_ATTEMPTS=3
SIMPLEFIN_RETRY_DELAY=
SIMPLEFIN_MAX_TRANSACTIONS=10000
SIMPLEFIN_DEFAULT_DATE_RANGE=90
SIMPLEFIN_ENABLE_CACHING=true
SIMPLEFIN_CACHE_DURATION=3600
SIMPLEFIN_SMART_EXPENSE_MATCHING=true
SIMPLEFIN_EXPENSE_MATCHING_THRESHOLD=0.7
SIMPLEFIN_AUTO_CREATE_EXPENSE_ACCOUNTS=true
SIMPLEFIN_ENABLE_TRANSACTION_CLUSTERING=true
SIMPLEFIN_CLUSTERING_SIMILARITY_THRESHOLD=0.7
USE_CACHE=true
IGNORE_DUPLICATE_ERRORS=false
IGNORE_NOT_FOUND_TRANSACTIONS=false
AUTO_IMPORT_SECRET=
CAN_POST_AUTOIMPORT=false
CAN_POST_FILES=false
IMPORT_DIR_ALLOWLIST=
FALLBACK_IN_DIR=false
VERIFY_TLS_SECURITY=true
JSON_CONFIGURATION_DIR=
CONNECTION_TIMEOUT=31.41
LOG_RETURN_JSON=false
LOG_LEVEL=debug
ENABLE_MAIL_REPORT=false
EXPECT_SECURE_URL=false
FAKE_DATA=false
MAIL_DESTINATION=noreply@example.com
MAIL_FROM_ADDRESS=noreply@example.com
POSTMARK_TOKEN=
QUEUE_CONNECTION=sync
SESSION_LIFETIME=120
IS_EXTERNAL=false
ASSET_URL=
# Database
MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_USER=firefly
MYSQL_PASSWORD=m5wyMiU0CeEDmiptcZsCA2DC37Bsa5zH
MYSQL_DATABASE=firefly

View File

@@ -0,0 +1,10 @@
# Define base path
BASE="/volume1/docker/obsidian"
# Create folders
mkdir -p "${BASE}/config"
# Set ownership and permissions
chown -R 1038:65538 "${BASE}"
chmod -R 750 "${BASE}"
chmod -R 770 "${BASE}/config"

View File

@@ -0,0 +1,16 @@
---
services:
obsidian:
image: lscr.io/linuxserver/obsidian:latest
container_name: obsidian
environment:
- PUID=1038
- PGID=65538
- TZ=America/Toronto
volumes:
- /volume1/docker/obsidian/config:/config
ports:
- 3010:3000
- 3011:3001
shm_size: "1gb"
restart: unless-stopped

View File

@@ -0,0 +1,10 @@
# Define base path
BASE="/volume1/docker/paperless"
# Create folders
mkdir -p "${BASE}/data" "${BASE}/media" "${BASE}/export" "${BASE}/consume" "${BASE}/redisdata"
# Set ownership and permissions
chown -R 1036:65538 "${BASE}"
chmod -R 750 "${BASE}"
chmod -R 770 "${BASE}/consume"

View File

@@ -0,0 +1,42 @@
###############################################################################
# Paperless-ngx settings #
###############################################################################
# See http://docs.paperless-ngx.com/configuration/ for all available options.
# The UID and GID of the user used to run paperless in the container. Set this
# to your UID and GID on the host so that you have write access to the
# consumption directory.
USERMAP_UID=1036
USERMAP_GID=65538
# See the documentation linked above for all options. A few commonly adjusted settings
# are provided below.
# This is required if you will be exposing Paperless-ngx on a public domain
# (if doing so please consider security measures such as reverse proxy)
#PAPERLESS_URL=https://paperless.example.com
# Adjust this key if you plan to make paperless available publicly. It should
# be a very long sequence of random characters. You don't need to remember it.
PAPERLESS_SECRET_KEY=CHzeaKbF7ZRpkaQT2rnVZUPpBF7KpUQiymVOuVLtdGACUS1h
# Use this variable to set a timezone for the Paperless Docker containers. Defaults to UTC.
PAPERLESS_TIME_ZONE=America/Toronto
# The default language to use for OCR. Set this to the language most of your
# documents are written in.
PAPERLESS_OCR_LANGUAGE=eng
# Additional languages to install for text recognition, separated by a whitespace.
# Note that this is different from PAPERLESS_OCR_LANGUAGE (default=eng), which defines
# the language used for OCR.
# The container installs English, German, Italian, Spanish and French by default.
# See https://packages.debian.org/search?keywords=tesseract-ocr-&searchon=names
# for available languages.
#PAPERLESS_OCR_LANGUAGES=tur ces
PAPERLESS_ADMIN_USER=admin
PAPERLESS_ADMIN_PASSWORD=2pplPtn!
PAPERLESS_FILENAME_FORMAT=personal/{{ created_year }}/{{ correspondent }}/{{ original_name }}

View File

@@ -0,0 +1,73 @@
# Docker Compose file for running paperless from the Docker Hub.
# This file contains everything paperless needs to run.
# Paperless supports amd64, arm and arm64 hardware.
#
# All compose files of paperless configure paperless in the following way:
#
# - Paperless is (re)started on system boot, if it was running before shutdown.
# - Docker volumes for storing data are managed by Docker.
# - Folders for importing and exporting files are created in the same directory
# as this file and mounted to the correct folders inside the container.
# - Paperless listens on port 8010.
#
# In addition to that, this Docker Compose file adds the following optional
# configurations:
#
# - Instead of SQLite (default), PostgreSQL is used as the database server.
#
# To install and update paperless with this file, do the following:
#
# - Open portainer Stacks list and click 'Add stack'
# - Paste the contents of this file and assign a name, e.g. 'paperless'
# - Upload 'docker-compose.env' by clicking on 'Load variables from .env file'
# - Modify the environment variables as needed
# - Click 'Deploy the stack' and wait for it to be deployed
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8
restart: unless-stopped
volumes:
- /volume1/docker/paperless/redisdata:/data
networks:
- backend-net
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
- broker
ports:
- "8010:8000"
volumes:
- /volume1/docker/paperless/data:/usr/src/paperless/data
- /volume1/docker/paperless/media:/usr/src/paperless/media
- /volume1/docker/paperless/export:/usr/src/paperless/export
- /volume1/docker/paperless/consume:/usr/src/paperless/consume
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBENGINE: postgres
PAPERLESS_DBHOST: postgres
PAPERLESS_DBPORT: 5432
PAPERLESS_DBNAME: paperless
PAPERLESS_DBUSER: paperless
PAPERLESS_DBPASS: kH8rwrUREJmjOBSb9uV0yXXhCRM9pQxdSk0TOZ8yi0oZTaPZ
CSRF_TRUSTED_ORIGINS: https://paperless.chengs.uk
env_file:
- stack.env
networks:
- frontend-net
- backend-net
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8000 || exit 1"]
interval: 30s
timeout: 5s
retries: 5
networks:
frontend-net:
external: true
backend-net:
external: true

9
paperless/postgres.sql Normal file
View File

@@ -0,0 +1,9 @@
psql -U pgadm homelab
CREATE DATABASE paperless;
CREATE USER paperless with PASSWORD 'kH8rwrUREJmjOBSb9uV0yXXhCRM9pQxdSk0TOZ8yi0oZTaPZ';
GRANT ALL PRIVILEGES ON DATABASE paperless TO paperless;
\c paperless
GRANT ALL ON SCHEMA public TO paperless;

View File

@@ -0,0 +1,11 @@
services:
vert:
container_name: vert
image: ghcr.io/vert-sh/vert:latest
restart: unless-stopped
ports:
- 3002:80
environment:
- USER_UID=1039
- USER_GID=65538
- TZ=America/Toronto