diff --git a/README.md b/README.md index 72ab414..6ef5b35 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,24 @@ -# self-hosting + + + +# self-hosting # Contents The repo contains setup guides for the following: @@ -16,11 +35,9 @@ Each directory contains (or will contain) its own `README.md` to aid with the installation of that specific setup. # General info - This info applies to all configs. ## Docker - All the setups named above use Docker and docker-compose. If you're on a Linux-based server, you can find both `docker` and `docker-compose` in your package manager (do note that the Docker package might be called `docker.io`). @@ -28,27 +45,23 @@ Otherwise, the install instructions can be found [here](https://docs.docker.com/engine/install/). ## Configuration - Most configuration can be done using a `.env` file with a provided `.env.example` file to start from. This means that you never have to edit the compose files, unless you wish to deviate from the default format. ## Building the image - You can build the container image using the command `docker-compose build`. This will build all services specified in the `docker-compose.yml` file. Any build configuration/environment variables can be defined in a `.env` file. A `.env.example` file is given for each configuration. ## Running the container - For running the server, we can use `docker-compose up -d`. This will start the service in the background. You can then see any logs using `docker-compose logs`. If you want the logs to update automatically, use `docker-compose logs -f`. # Why did I make this? - Well, I just wanted to put all my knowledge in one basket. this makes it easier to manage and share with others. I spend a lot of time tweaking these configs and figuring out how they work best (for me at least), and wanted to share this diff --git a/backups/.gitignore b/backups/.gitignore new file mode 100644 index 0000000..205abbb --- /dev/null +++ b/backups/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +backup_tool diff --git a/backups/README.md b/backups/README.md new file mode 100644 index 0000000..3edfd50 --- /dev/null +++ b/backups/README.md @@ -0,0 +1,4 @@ +# Backups +I wrote this Python program to manage backups of the stuff running on our +server. I know there's probably better ways to do this, but I really liked +working on this and it works well enough for our usecase. diff --git a/backups/app/__main__.py b/backups/app/__main__.py new file mode 100644 index 0000000..535d616 --- /dev/null +++ b/backups/app/__main__.py @@ -0,0 +1,41 @@ +import argparse +import sys +from specs import parse_specs_file + + +# This just displays the error type and message, not the stack trace +def except_hook(ext_type, value, traceback): + sys.stderr.write("{}: {}\n".format(ext_type.__name__, value)) + +sys.excepthook = except_hook + + +# Define parser +parser = argparse.ArgumentParser( + description='Backup directories and Docker volumes.') +parser.add_argument('-f', '--file', action='append', dest='file', + help='File containing spec definitions.') +parser.add_argument('-j', '--json', action='store_const', const=True, + default=False, help='Print out the parsed specs as JSON ' + 'and exit') +parser.add_argument('spec', nargs='*', + help='The specs to process. Defaults to all.') + +# Parse arguments +args = parser.parse_args() +specs = sum([parse_specs_file(path) for path in args.file], []) + +# Filter specs if needed +if args.spec: + specs = filter(lambda s: s.name in args.spec, specs) + +# Dump parsed data as json +if args.json: + import json + print(json.dumps([spec.to_dict() for spec in specs], indent=4)) + +else: + pass + # Run the backups + # for spec in specs: + # spec.backup() diff --git a/backups/app/notifier.py b/backups/app/notifier.py new file mode 100644 index 0000000..e69de29 diff --git a/backups/app/specs/__init__.py b/backups/app/specs/__init__.py new file mode 100644 index 0000000..5104164 --- /dev/null +++ b/backups/app/specs/__init__.py @@ -0,0 +1,2 @@ +from .specs import Spec +from .parser import parse_specs_file diff --git a/backups/app/specs/parser.py b/backups/app/specs/parser.py new file mode 100644 index 0000000..fab362a --- /dev/null +++ b/backups/app/specs/parser.py @@ -0,0 +1,114 @@ +import yaml +from pathlib import Path +from specs import Spec +from typing import List, Dict + + +class InvalidKeyError(Exception): + def __init__(self, key): + message = "Invalid key: {}".format(key) + + super().__init__(key) + + +class MissingKeyError(Exception): + def __init__(self, key): + message = "Missing key: {}".format(key) + + super().__init__(key) + + +def parse_specs_file(path: Path) -> List[Spec]: + """ + Parse a YAML file defining backup specs. + + Args: + path: path to the specs file + + Returns: + A list of specs + """ + + # Skeleton of a spec config + # If a value is None, this means it doesn't have a default value and must be + # defined + spec_skel = { + "source": None, + "destination": None, + "limit": None, + "volume": False, + "notify": { + "title": "Backup Notification", + "events": ["failure"] + } + } + + # Read YAML file + with open(path, "r") as yaml_file: + data = yaml.load(yaml_file, Loader=yaml.Loader) + + # Check specs section exists + if "specs" not in data: + raise MissingKeyError("specs") + + # Allow for default notify settings + if "notify" in data: + spec_skel["notify"] = data["notify"] + + specs = [] + # Check format for each spec + for key in data["specs"]: + specs.append(Spec.from_dict(key, combine_with_skeleton( + data["specs"][key], spec_skel) + )) + + return specs + + +def combine_with_skeleton(data: Dict, skel: Dict) -> Dict: + """ + Compare a dict with a given skeleton dict, and fill in default values where + needed. + """ + + # First, check for illegal keys + for key in data: + if key not in skel: + raise InvalidKeyError(key) + + # Then, check the default values + for key, value in skel.items(): + if key not in data: + # Raise error if there's not default value + if value is None: + raise MissingKeyError(key) + + # Replace with default value + data[key] = value + + # Error if value is not same type as default value + elif type(data[key]) != type(value) and value is not None: + raise TypeError("Invalid value type") + + # Recurse into dicts + elif type(value) == dict: + data[key] = combine_with_skeleton(data[key], value) + + return data + + +# Test cases +if __name__ == "__main__": + d1 = { + "a": 5 + } + s1 = { + "a": 7, + "b": 2 + } + r1 = { + "a": 5, + "b": 2 + } + + assert combine_with_skeleton(d1, s1) == r1 diff --git a/backups/app/specs/specs.py b/backups/app/specs/specs.py new file mode 100644 index 0000000..f2971ca --- /dev/null +++ b/backups/app/specs/specs.py @@ -0,0 +1,146 @@ +from pathlib import Path +from datetime import datetime +import requests +import os + + +class Spec: + def __init__(self, name, destination, limit, title, events=None): + self.name = name + self.destination = Path(destination) + self.limit = limit + self.title = title + self.events = [] if events is None else events + + def to_dict(self): + return { + "name": self.name, + "destination": str(self.destination), + "limit": self.limit, + "notify": { + "title": self.title, + "events": self.events + } + } + + def backup(self): + raise NotImplementedError() + + def remove_redundant(self): + tarballs = sorted(self.destination.glob('*.tar.gz'), + key=os.path.getmtime, reverse=True) + + if len(tarballs) >= self.limit: + for path in tarballs[self.limit - 1:]: + path.unlink() + + def notify(self, status_code): + if status_code: + if "failure" not in self.events: + return + + message = "backup for {} failed.".format(self.name) + + else: + if "success" not in self.events: + return + + message = "backup for {} succeeded.".format(self.name) + + # Read API key from env vars + try: + key = os.environ["IFTTT_API_KEY"] + + # Don't send notification if there's not API key defined + except KeyError: + return + + url = "https://maker.ifttt.com/trigger/{}/with/key/{}".format( + "phone_notifications", + key + ) + + data = { + "value1": self.title, + "value2": message + } + + requests.post(url, data=data) + + def get_filename(self): + return '{}_{}.tar.gz'.format( + self.name, + datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + ) + + @staticmethod + def from_dict(name, data) -> "Specification": + if data.get("volume", False): + return VolumeSpec.from_dict(name, data) + + return DirSpec.from_dict(name, data) + + @staticmethod + def from_file(path: str): + with open(path, 'r') as yaml_file: + data = yaml.load(yaml_file, Loader=yaml.Loader) + + return [Spec.from_dict(name, info) + for name, info in data["specs"].items()] + + +class DirSpec(Spec): + def __init__(self, name, source, destination, limit, title, events=None): + super().__init__(name, destination, limit, title, events) + + self.source = Path(source) + + def backup(self): + self.remove_redundant() + + status_code = os.system( + "tar -C '{}' -czf '{}' -- .".format( + self.source, + self.destination / self.get_filename() + ) + ) + + self.notify(status_code) + + @staticmethod + def from_dict(name, data): + return DirSpec( + name, + data["source"], + data["destination"], + data["limit"], + data["notify"]["title"], + data["notify"]["events"] + ) + +class VolumeSpec(Spec): + def __init__(self, name, volume, destination, limit, title, events=None): + super().__init__(name, destination, limit, title, events) + + self.volume = volume + + def backup(self): + status_code = os.system( + "docker run --rm -v '{}:/from' -v '{}:/to' alpine:latest " + "tar -C /from -czf '/to/{}' -- .".format( + self.volume, + self.destination, + self.get_filename() + ) + ) + + @staticmethod + def from_dict(name, data): + return VolumeSpec( + name, + data["source"], + data["destination"], + data["limit"], + data["notify"]["title"], + data["notify"]["events"] + ) diff --git a/backups/backups.yaml.example b/backups/backups.yaml.example new file mode 100644 index 0000000..68a203b --- /dev/null +++ b/backups/backups.yaml.example @@ -0,0 +1,15 @@ +notify: + title: "title" + events: + - 'random' + +specs: + test-spec: + source: '/some/path' + destination: '/some/other/path' + limit: 7 + + test-2: + source: '/path/to' + destination: '/to/some/other/path' + limit: 2 diff --git a/backups/install.sh b/backups/install.sh new file mode 100755 index 0000000..d846c29 --- /dev/null +++ b/backups/install.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +# Zip app +(cd app && zip -r ../app.zip * -x "__pycache__/*" "**/__pycache__/*" ".vim/*" "**/.vim/*") + +# Add shebang to top of file +echo "#!/usr/bin/env python3" | cat - app.zip > backup_tool +chmod a+x backup_tool + +# Move executable over +mv backup_tool /usr/local/bin + +# Remove zip +rm app.zip diff --git a/firefly/.env.example b/firefly/.env.example index 58202bb..164c22c 100644 --- a/firefly/.env.example +++ b/firefly/.env.example @@ -63,7 +63,7 @@ DB_HOST=db DB_PORT=5432 DB_DATABASE=firefly DB_USERNAME=firefly -DB_PASSWORD=firefly +DB_PASSWORD=password # MySQL supports SSL. You can configure it here. # If you use Docker or similar, you can set these variables from a file by appending them with _FILE diff --git a/firefly/docker-compose.yml b/firefly/docker-compose.yml index 7547831..65e501e 100644 --- a/firefly/docker-compose.yml +++ b/firefly/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2.4' +version: '2.8' services: app: @@ -6,23 +6,24 @@ services: context: '.' args: - 'LOCALE=$DEFAULT_LOCALE' - image: 'chewingbever/firefly-iii-cron:latest' + image: 'firefly-iii-cron:latest' restart: 'always' - healthcheck: test: 'curl -f localhost:8080 || exit 1' interval: '1m' timeout: '10s' retries: 3 start_period: '10s' + depends_on: db: condition: 'service_healthy' redis: condition: 'service_healthy' - env_file: - '.env' + labels: + - 'com.centurylinklabs.watchtower.enable=true' networks: - 'nginx' - 'default' @@ -30,33 +31,35 @@ services: - 'upload:/var/www/html/storage/upload' db: - image: 'postgres:13.2-alpine' + image: 'postgres:13-alpine' restart: 'always' - healthcheck: - test: 'pg_isready -U firefly' + test: 'pg_isready -U $DB_USERNAME' interval: '10s' timeout: '5s' retries: 5 - start_period: '0s' environment: - - 'POSTGRES_DB=firefly' - - 'POSTGRES_PASSWORD=firefly' - - 'POSTGRES_USER=firefly' + - 'POSTGRES_DB=$DB_DATABASE' + - 'POSTGRES_PASSWORD=$DB_PASSWORD' + - 'POSTGRES_USER=$DB_USERNAME' + labels: + - 'com.centurylinklabs.watchtower.enable=true' volumes: - 'db-data:/var/lib/postgresql/data' redis: - image: 'redis:6.2.2-alpine' + image: 'redis:6-alpine' restart: 'always' - healthcheck: test: 'redis-cli -h localhost ping' interval: '10s' timeout: '5s' retries: 3 + labels: + - 'com.centurylinklabs.watchtower.enable=true' + networks: nginx: external: true diff --git a/gitea/.env.example b/gitea/.env.example deleted file mode 100644 index 95e1324..0000000 --- a/gitea/.env.example +++ /dev/null @@ -1,16 +0,0 @@ -# User to run container as -USER_UID=1000 -USER_GID=1000 - -# Database settings -DB_TYPE=postgres -DB_HOST=db:5432 -DB_NAME=gitea -DB_USER=gitea -DB_PASSWD=gitea - -# Wether to start LFS -LFS_START_SERVER=true - -# Wether to allow registration -DISABLE_REGISTRATION=true diff --git a/gitea/docker-compose.yml b/gitea/docker-compose.yml deleted file mode 100644 index 6e65af8..0000000 --- a/gitea/docker-compose.yml +++ /dev/null @@ -1,59 +0,0 @@ -version: '2.4' - -services: - app: - # Latest contains a development version - image: 'gitea/gitea:1.14.1-rootless' - restart: 'always' - - depends_on: - db: - condition: 'service_healthy' - healthcheck: - test: 'curl -f localhost:3000 || exit 1' - interval: '30s' - timeout: '5s' - retries: 3 - start_period: '5s' - - env_file: - - '.env' - networks: - - 'default' - - 'nginx' - ports: - - '22:22' - volumes: - - 'data:/data' - - 'repos:/data/git/repositories' - - 'lfs:/data/git/lfs' - - '/etc/timezone:/etc/timezone:ro' - - '/etc/localtime:/etc/localtime:ro' - - db: - image: 'postgres:13.2-alpine' - restart: 'always' - - healthcheck: - test: 'pg_isready -U gitea' - interval: '30s' - timeout: '5s' - retries: 3 - start_period: '0s' - - environment: - - 'POSTGRES_USER=gitea' - - 'POSTGRES_PASSWORD=gitea' - - 'POSTGRES_DB=gitea' - volumes: - - 'db-data:/var/lib/postgresql/data' - -networks: - nginx: - external: true - -volumes: - data: - lfs: - db-data: - repos: diff --git a/koel/.env.example b/koel/.env.example index 9ba0882..d58e408 100644 --- a/koel/.env.example +++ b/koel/.env.example @@ -12,7 +12,7 @@ DB_HOST=db DB_PORT=3306 DB_DATABASE=koel DB_USERNAME=koel -DB_PASSWORD=koel +DB_PASSWORD=changeme # A random 32-char string. You can leave this empty if use php artisan koel:init. APP_KEY= diff --git a/koel/docker-compose.yml b/koel/docker-compose.yml index c207d71..19d6e1a 100644 --- a/koel/docker-compose.yml +++ b/koel/docker-compose.yml @@ -1,22 +1,14 @@ -version: '2.4' +version: '3.5' services: app: - # This repository sadly only has a 'latest' flag image: 'hyzual/koel:latest' restart: 'always' - healthcheck: - test: 'curl -f localhost:80 || exit 1' - interval: '1m' - timeout: '10s' - retries: 3 - start_period: '10s' depends_on: - db: - # Haven't found a good MySQL healthcheck yet - condition: 'service_started' - + - 'db' + labels: + - 'com.centurylinklabs.watchtower.enable=true' networks: - 'default' - 'nginx' @@ -24,18 +16,19 @@ services: - './.env:/var/www/html/.env' - 'covers:/var/www/html/public/img/covers' - 'music:/music' - - 'index:/var/www/html/storage/search-indexes' db: - image: 'mariadb:10.5.9-focal' + image: 'mysql:8' restart: 'always' command: '--default-authentication-plugin=mysql_native_password' environment: - 'MYSQL_DATABASE=koel' - - 'MYSQL_USER=koel' - - 'MYSQL_PASSWORD=koel' - - 'MYSQL_RANDOM_ROOT_PASSWORD=yes' + - 'MYSQL_PASSWORD=$DB_PASSWORD' + - 'MYSQL_ROOT_PASSWORD=$DB_PASSWORD' + - 'MYSQL_USER=$DB_USERNAME' + labels: + - 'com.centurylinklabs.watchtower.enable=true' volumes: - 'db-data:/var/lib/mysql' @@ -46,5 +39,4 @@ networks: volumes: covers: db-data: - index: music: diff --git a/minecraft/fabric/docker-compose.yml b/minecraft/fabric/docker-compose.yml index 440ad2b..28d43bf 100644 --- a/minecraft/fabric/docker-compose.yml +++ b/minecraft/fabric/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2.0' +version: '3.5' services: app: build: diff --git a/minecraft/forge/docker-compose.yml b/minecraft/forge/docker-compose.yml index 95ba6e4..f8077d2 100644 --- a/minecraft/forge/docker-compose.yml +++ b/minecraft/forge/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2.0' +version: '3.5' services: app: build: diff --git a/minecraft/papermc/docker-compose.yml b/minecraft/papermc/docker-compose.yml index c9a41bc..fd4afec 100644 --- a/minecraft/papermc/docker-compose.yml +++ b/minecraft/papermc/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2.0' +version: '3.5' services: app: build: @@ -7,7 +7,7 @@ services: - 'BASE_IMAGE' - 'MC_VERSION' - 'PAPERMC_VERSION' - image: 'localhost:5000/mc-papermc:${MC_VERSION}-${PAPERMC_VERSION}' + image: 'chewingbever/mc-papermc:${MC_VERSION}-${PAPERMC_VERSION}' restart: 'always' # Needed to interact with server console diff --git a/miniflux/db.env.example b/miniflux/db.env.example new file mode 100644 index 0000000..79ebaff --- /dev/null +++ b/miniflux/db.env.example @@ -0,0 +1,3 @@ +POSTGRES_DB=miniflux +POSTGRES_USER=miniflux +POSTGRES_PASSWORD=changeme diff --git a/miniflux/docker-compose.yml b/miniflux/docker-compose.yml index 24aae5a..4a59057 100644 --- a/miniflux/docker-compose.yml +++ b/miniflux/docker-compose.yml @@ -1,44 +1,28 @@ -version: '2.4' +version: '3.5' services: app: - image: 'miniflux/miniflux:2.0.29' + image: 'miniflux/miniflux:latest' restart: 'always' depends_on: - db: - condition: 'service_healthy' - healthcheck: - test: 'wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1' - interval: '1m' - timeout: '5s' - retries: 3 - start_period: '5s' - + - 'db' env_file: - - '.env' - environment: - # This is always the same, so we just put it here - - 'DATABASE_URL=postgres://miniflux:miniflux@db/miniflux?sslmode=disable' + - 'miniflux.env' + labels: + - 'com.centurylinklabs.watchtower.enable=true' networks: - 'default' - 'nginx' db: - image: 'postgres:13.2-alpine' + image: 'postgres:13-alpine' restart: 'always' - healthcheck: - test: 'pg_isready -U miniflux' - interval: '10s' - timeout: '5s' - retries: 5 - start_period: '0s' - - environment: - - 'POSTGRES_DB=miniflux' - - 'POSTGRES_USER=miniflux' - - 'POSTGRES_PASSWORD=miniflux' + env_file: + - 'db.env' + labels: + - 'com.centurylinklabs.watchtower.enable=true' volumes: - 'db-data:/var/lib/postgresql/data' diff --git a/miniflux/.env.example b/miniflux/miniflux.env.example similarity index 63% rename from miniflux/.env.example rename to miniflux/miniflux.env.example index 0a429a9..161f6c8 100644 --- a/miniflux/.env.example +++ b/miniflux/miniflux.env.example @@ -1,4 +1,5 @@ # Database settings +DATABASE_URL=postgres://miniflux:changeme@db/miniflux?sslmode=disable RUN_MIGRATIONS=1 # Auto-create admin user diff --git a/monica/.env.example b/monica/.env.example deleted file mode 100644 index 27ad3e7..0000000 --- a/monica/.env.example +++ /dev/null @@ -1,168 +0,0 @@ -# -# Welcome, friend ❤. Thanks for trying out Monica. We hope you'll have fun. -# - -# Two choices: local|production. Use local if you want to install Monica as a -# development version. Use production otherwise. -APP_ENV=production - -# true if you want to show debug information on errors. For production, put this -# to false. -APP_DEBUG=false - -# The encryption key. This is the most important part of the application. Keep -# this secure otherwise, everyone will be able to access your application. -# Must be 32 characters long exactly. -# Use `php artisan key:generate` or `pwgen -s 32 1` to generate a random key. -APP_KEY=ChangeMeBy32KeyLengthOrGenerated - -# Prevent information leakage by referring to IDs with hashIds instead of -# the actual IDs used in the database. -HASH_SALT=ChangeMeBy20+KeyLength -HASH_LENGTH=18 - -# The URL of your application. -APP_URL=http://localhost - -# Force using APP_URL as base url of your application. -# You should not need this, unless you are using subdirectory config. -APP_FORCE_URL=false - -# Database information -# To keep this information secure, we urge you to change the default password -# Currently only "mysql" compatible servers are working -DB_CONNECTION=mysql -DB_HOST=db -DB_PORT=3306 -# You can use mysql unix socket if available, it overrides DB_HOST and DB_PORT values. -#DB_UNIX_SOCKET=/var/run/mysqld/mysqld.sock -DB_DATABASE=monica -DB_USERNAME=monica -DB_PASSWORD=monica -DB_PREFIX= -DB_TEST_HOST=127.0.0.1 -DB_TEST_DATABASE=monica_test -DB_TEST_USERNAME=homestead -DB_TEST_PASSWORD=secret - -# Use utf8mb4 database charset format to support emoji characters -# ⚠ be sure your DBMS supports utf8mb4 format -DB_USE_UTF8MB4=true - -# Mail credentials used to send emails from the application. -MAIL_MAILER=smtp -MAIL_HOST=mailtrap.io -MAIL_PORT=2525 -MAIL_USERNAME= -MAIL_PASSWORD= -MAIL_ENCRYPTION= -# Outgoing emails will be sent with these identity -MAIL_FROM_ADDRESS= -MAIL_FROM_NAME="Monica instance" -# New registration notification sent to this email -APP_EMAIL_NEW_USERS_NOTIFICATION= - -# Ability to disable signups on your instance. -# Can be true or false. Default to false. -APP_DISABLE_SIGNUP=true - -# Enable user email verification. -APP_SIGNUP_DOUBLE_OPTIN=false - -# Set trusted proxy IP addresses. -# To trust all proxies that connect directly to your server, use a "*". -# To trust one or more specific proxies that connect directly to your server, -# use a comma separated list of IP addresses. -APP_TRUSTED_PROXIES=* - -# Enable automatic cloudflare trusted proxy discover -APP_TRUSTED_CLOUDFLARE=false - -# Frequency of creation of new log files. Logs are written when an error occurs. -# Refer to config/logging.php for the possible values. -LOG_CHANNEL=daily - -# Error tracking. Specific to hosted version on .com. You probably don't need -# those. -SENTRY_SUPPORT=false -SENTRY_LARAVEL_DSN= - -# Send a daily ping to https://version.monicahq.com to check if a new version -# is available. When a new version is detected, you will have a message in the -# UI, as well as the release notes for the new changes. Can be true or false. -# Default to true. -CHECK_VERSION=true - -# Cache, session, and queue parameters -# ⚠ Change this only if you know what you are doing -#. Cache: database, file, memcached, redis, dynamodb -#. Session: file, cookie, database, apc, memcached, redis, array -#. Queue: sync, database, beanstalkd, sqs, redis -# If Queue is not set to 'sync', you'll have to set a queue worker -# See https://laravel.com/docs/5.7/queues#running-the-queue-worker -CACHE_DRIVER=redis -SESSION_DRIVER=file -SESSION_LIFETIME=120 -QUEUE_CONNECTION=sync - -# If you use redis, set the redis host or ip, like: -REDIS_HOST=redis - -# Maximum allowed size for uploaded files, in kilobytes. -# Make sure this is an integer, without commas or spaces. -DEFAULT_MAX_UPLOAD_SIZE=10240 - -# Maximum allowed storage size per account, in megabytes. -# Make sure this is an integer, without commas or spaces. -DEFAULT_MAX_STORAGE_SIZE=512 - -# Default filesystem to store uploaded files. -# Possible values: public|s3 -DEFAULT_FILESYSTEM=public - -# AWS keys for S3 when using this storage method -AWS_KEY= -AWS_SECRET= -AWS_REGION=us-east-1 -AWS_BUCKET= -AWS_SERVER= - -# Allow Two Factor Authentication feature on your instance -MFA_ENABLED=true - -# Enable DAV support -DAV_ENABLED=true - -# CLIENT ID and SECRET used for OAuth authentication -PASSPORT_PERSONAL_ACCESS_CLIENT_ID= -PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET= - -# Allow to access general statistics about your instance through a public API -# call -ALLOW_STATISTICS_THROUGH_PUBLIC_API_ACCESS=false - -# Indicates that each user in the instance must comply to international policies -# like CASL or GDPR -POLICY_COMPLIANT=true - -# Enable geolocation services -# This is used to translate addresses to GPS coordinates. -ENABLE_GEOLOCATION=false - -# API key for geolocation services -# We use LocationIQ (https://locationiq.com/) to translate addresses to -# latitude/longitude coordinates. We could use Google instead but we don't -# want to give anything to Google, ever. -# LocationIQ offers 10,000 free requests per day. -LOCATION_IQ_API_KEY= - -# Enable weather on contact profile page -# Weather can only be fetched if we know longitude/latitude - this is why -# you also need to activate the geolocation service above to make it work -ENABLE_WEATHER=false - -# Access to weather data from darksky api -# https://darksky.net/dev/register -# Darksky provides an api with 1000 free API calls per day -# You need to enable the weather above if you provide an API key here. -DARKSKY_API_KEY= diff --git a/monica/docker-compose.yml b/monica/docker-compose.yml deleted file mode 100644 index 2556e8e..0000000 --- a/monica/docker-compose.yml +++ /dev/null @@ -1,58 +0,0 @@ -version: '2.4' - -services: - app: - image: 'monica:2.20.0-apache' - restart: 'always' - - healthcheck: - test: 'curl -f localhost:80 || exit 1' - interval: '1m' - timeout: '10s' - retries: 3 - start_period: '10s' - depends_on: - db: - condition: 'service_started' - redis: - condition: 'service_healthy' - - env_file: - - '.env' - networks: - - 'default' - - 'nginx' - volumes: - - 'data:/var/www/html/storage' - - db: - image: 'mariadb:10.5.9-focal' - restart: 'always' - command: '--default-authentication-plugin=mysql_native_password' - - environment: - - 'MYSQL_RANDOM_ROOT_PASSWORD=true' - - 'MYSQL_DATABASE=monica' - - 'MYSQL_USER=monica' - - 'MYSQL_PASSWORD=monica' - - volumes: - - 'db-data:/var/lib/mysql' - - redis: - image: 'redis:6.2.2-alpine' - restart: 'always' - - healthcheck: - test: 'redis-cli -h localhost ping' - interval: '10s' - timeout: '5s' - retries: 3 - -networks: - nginx: - external: true - -volumes: - data: - db-data: diff --git a/nextcloud/.env.example b/nextcloud/.env.example index 2c43195..526887b 100644 --- a/nextcloud/.env.example +++ b/nextcloud/.env.example @@ -2,7 +2,7 @@ POSTGRES_HOST=db POSTGRES_DB=nextcloud POSTGRES_USER=nextcloud -POSTGRES_PASSWORD=nextcloud +POSTGRES_PASSWORD=pass # Redis REDIS_HOST=redis diff --git a/nextcloud/docker-compose.yml b/nextcloud/docker-compose.yml index bb6be0d..b287465 100644 --- a/nextcloud/docker-compose.yml +++ b/nextcloud/docker-compose.yml @@ -1,24 +1,17 @@ -version: '2.4' +version: '3.5' services: app: - image: 'nextcloud:21.0.1-apache' + image: 'nextcloud:20-apache' restart: 'always' - healthcheck: - test: 'curl -f localhost || exit 1' - interval: '1m' - timeout: '10s' - retries: 3 - start_period: '10s' depends_on: - db: - condition: 'service_healthy' - redis: - condition: 'service_healthy' - + - 'db' + - 'redis' env_file: - '.env' + labels: + - 'com.centurylinklabs.watchtower.enable=true' networks: - 'default' - 'nginx' @@ -28,41 +21,40 @@ services: - 'root:/var/www/html' cron: - image: 'nextcloud:21.0.1-apache' - restart: 'always' + image: 'nextcloud:20-apache' entrypoint: '/cron.sh' + restart: 'always' depends_on: - app: - condition: 'service_healthy' - + - 'app' env_file: - '.env' + labels: + - 'com.centurylinklabs.watchtower.enable=true' volumes: - 'config:/var/www/html/config' - 'data:/var/www/html/data' - 'root:/var/www/html' db: - image: 'postgres:13.2-alpine' + image: 'postgres:13-alpine' restart: 'always' environment: - - 'POSTGRES_DB=nextcloud' - - 'POSTGRES_USER=nextcloud' - - 'POSTGRES_PASSWORD=nextcloud' + - 'POSTGRES_DB' + - 'POSTGRES_USER' + - 'POSTGRES_PASSWORD' + labels: + - 'com.centurylinklabs.watchtower.enable=true' volumes: - 'db-data:/var/lib/postgresql/data' redis: - image: 'redis:6.2.2-alpine' + image: 'redis:6-alpine' restart: 'always' - healthcheck: - test: 'redis-cli -h localhost ping' - interval: '10s' - timeout: '5s' - retries: 3 + labels: + - 'com.centurylinklabs.watchtower.enable=true' networks: nginx: diff --git a/nginx/.env.example b/nginx/.env.example index d63211e..445e483 100644 --- a/nginx/.env.example +++ b/nginx/.env.example @@ -1,65 +1,12 @@ -# =====COMMON CONFIGURATION===== -## Comma-seperated list of domains to generate certs for -## NOTE: you should only add domains here that aren't used in any of -## the specific configurations below +# Main domain; also name of certificate +MAIN_DOMAIN= + +# Comma-separated list of other domains which also arrive here DOMAINS= -## Admin email; used for certificates +# Admin email; used for certificates EMAIL= -## HTTP(S) Port +# HTTP(S) Port HTTP_PORT=80 HTTPS_PORT=443 - - -# =====PER-SERVICE CONFIGURATION===== -# Domain name: domain name that points to the instance -# Hostname: basically the argument to proxy_pass - -## Firefly III -### Domain name -FIREFLY_DOMAIN= -### Hostname -FIREFLY_HOST=firefly_app_1 - -## Koel -### Domain name -KOEL_DOMAIN= -### Hostname -KOEL_HOST=koel_app_1 - -## Miniflux -### Domain name -MINIFLUX_DOMAIN= -### Hostname -MINIFLUX_HOST=miniflux_app_1 - -## Monica -### Domain name -MONICA_DOMAIN= -### Hostname -MONICA_HOST=monica_app_1 - -## Nextcloud -### Domain name -NEXTCLOUD_DOMAIN= -### Hostname -NEXTCLOUD_HOST=nextcloud_app_1 - -## Portainer -### Domain name -PORTAINER_DOMAIN= -### Hostname -PORTAINER_HOST=portainer_app_1 - -## Gitea -### Domain name -GITEA_DOMAIN= -### Hostname -GITEA_HOST=gitea_app_1 - -## Podgrab -### Domain name -PODGRAB_DOMAIN= -### Hostname -PODGRAB_HOST=podgrab_app_1 diff --git a/nginx/build/Dockerfile b/nginx/build/Dockerfile new file mode 100644 index 0000000..309ea38 --- /dev/null +++ b/nginx/build/Dockerfile @@ -0,0 +1,17 @@ +FROM nginx:stable-alpine + +RUN apk add --no-cache certbot + +COPY entrypoint.sh ./entrypoint.sh +RUN chmod +x ./entrypoint.sh + +RUN mkdir /var/lib/certbot +COPY renew /etc/periodic/weekly/renew +RUN chmod +x /etc/periodic/weekly/renew + +# Default.conf file is annoying +RUN rm -rf /etc/nginx/conf.d/* + +RUN /usr/sbin/crond -f -d 8 & + +ENTRYPOINT [ "./entrypoint.sh" ] diff --git a/nginx/build/entrypoint.sh b/nginx/build/entrypoint.sh new file mode 100644 index 0000000..d652550 --- /dev/null +++ b/nginx/build/entrypoint.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +certbot certonly --standalone -d "$MAIN_DOMAIN,$DOMAINS" --email "$EMAIL" -n --agree-tos --expand + +# The original script handles the template subsitution +exec /docker-entrypoint.sh nginx -g "daemon off;" diff --git a/nginx/build/renew b/nginx/build/renew new file mode 100644 index 0000000..98327d4 --- /dev/null +++ b/nginx/build/renew @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew --webroot --webroot-path /var/lib/certbot/ --post-hook "/usr/sbin/nginx -s reload" diff --git a/nginx/docker-compose.yml b/nginx/docker-compose.yml index f991d1b..c8e51f1 100644 --- a/nginx/docker-compose.yml +++ b/nginx/docker-compose.yml @@ -1,13 +1,15 @@ -version: '2.4' - +version: '3.5' services: app: - build: './nginx' + build: './build' image: 'nginx-certbot:stable-alpine' - restart: 'always' - env_file: - - '.env' + environment: + - 'DOMAINS' + - 'EMAIL' + - 'HTTPS_PORT' + - 'HTTP_PORT' + - 'MAIN_DOMAIN' networks: - 'nginx' ports: diff --git a/nginx/nginx.conf b/nginx/nginx.conf index c3e3167..6f321f0 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -5,4 +5,4 @@ user nginx nginx; worker_processes auto; # Load config segments -include conf.d/*.conf; +include conf.d/*; diff --git a/nginx/nginx/Dockerfile b/nginx/nginx/Dockerfile deleted file mode 100644 index 19a359b..0000000 --- a/nginx/nginx/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM nginx:1.20.0-alpine - -COPY entrypoint.sh /entrypoint.sh -COPY renew /etc/periodic/weekly/renew - -# Install certbot -# Remove default configs -RUN apk add --no-cache certbot && \ - rm -rf /etc/nginx/conf.d/* - -ENTRYPOINT [ "./entrypoint.sh" ] diff --git a/nginx/nginx/entrypoint.sh b/nginx/nginx/entrypoint.sh deleted file mode 100755 index 1205a79..0000000 --- a/nginx/nginx/entrypoint.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env sh - -# Start cron -/usr/sbin/crond -d 8 & - -# Renew all certificates -for url in $(env | grep '^[^=]\+_DOMAIN=' | sed 's/^.*\?=\(.*\)$/\1/g') $(echo "$DOMAINS" | sed 's/,/ /g') -do - certbot certonly \ - --standalone \ - -d "$url" \ - --email "$EMAIL" \ - -n \ - --agree-tos \ - --expand -done - -# The original script handles the template subsitution -exec /docker-entrypoint.sh nginx -g "daemon off;" diff --git a/nginx/nginx/renew b/nginx/nginx/renew deleted file mode 100755 index bdbebcf..0000000 --- a/nginx/nginx/renew +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env sh - -python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && \ - certbot renew \ - --webroot \ - --webroot-path /var/lib/certbot/ \ - --post-hook "/usr/sbin/nginx -s reload" diff --git a/nginx/sites-available/firefly-iii.conf.template b/nginx/sites-available/firefly-iii.conf similarity index 60% rename from nginx/sites-available/firefly-iii.conf.template rename to nginx/sites-available/firefly-iii.conf index e9447fc..1a9f1c4 100644 --- a/nginx/sites-available/firefly-iii.conf.template +++ b/nginx/sites-available/firefly-iii.conf @@ -1,11 +1,6 @@ server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${FIREFLY_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${FIREFLY_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - server_name ${FIREFLY_DOMAIN}; + listen 443 ssl; + server_name DOMAIN; location / { proxy_set_header Host $host; @@ -18,7 +13,7 @@ server { proxy_set_header Connection "upgrade"; resolver 127.0.0.11; - proxy_pass http://${FIREFLY_HOST}:8080; + proxy_pass http://firefly_app_1:8080; } } diff --git a/nginx/sites-available/gitea.conf.template b/nginx/sites-available/gitea.conf.template deleted file mode 100644 index 477f4be..0000000 --- a/nginx/sites-available/gitea.conf.template +++ /dev/null @@ -1,23 +0,0 @@ -server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${GITEA_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${GITEA_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - server_name ${GITEA_DOMAIN}; - - location / { - resolver 127.0.0.11; - proxy_pass http://#{GITEA_HOST}:3000/; - - # Static content caching - location ~* \.(?:jpg|jpeg|png|gif|ico|css|js|ttf)$ { - expires 1h; - add_header Cache-Control public; - - proxy_pass http://${GITEA_HOST}:3000; - } - } -} - diff --git a/nginx/sites-available/koel.conf b/nginx/sites-available/koel.conf new file mode 100644 index 0000000..82832a5 --- /dev/null +++ b/nginx/sites-available/koel.conf @@ -0,0 +1,9 @@ +server { + listen 443 ssl; + server_name DOMAIN; + + location / { + resolver 127.0.0.11; + proxy_pass http://koel_app_1:80; + } +} diff --git a/nginx/sites-available/koel.conf.template b/nginx/sites-available/koel.conf.template deleted file mode 100644 index 93f4fc5..0000000 --- a/nginx/sites-available/koel.conf.template +++ /dev/null @@ -1,21 +0,0 @@ -server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${KOEL_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${KOEL_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - server_name ${KOEL_DOMAIN}; - - location / { - 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-Host $server_name; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Ssl on; - - resolver 127.0.0.11; - proxy_pass http://${KOEL_HOST}:80; - } -} diff --git a/nginx/sites-available/miniflux.conf b/nginx/sites-available/miniflux.conf new file mode 100644 index 0000000..da25654 --- /dev/null +++ b/nginx/sites-available/miniflux.conf @@ -0,0 +1,10 @@ +server { + listen 443 ssl; + server_name DOMAIN; + + location / { + resolver 127.0.0.11; + proxy_pass http://miniflux_app_1:8080; + } +} + diff --git a/nginx/sites-available/miniflux.conf.template b/nginx/sites-available/miniflux.conf.template deleted file mode 100644 index eefbe26..0000000 --- a/nginx/sites-available/miniflux.conf.template +++ /dev/null @@ -1,15 +0,0 @@ -server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${MINIFLUX_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${MINIFLUX_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - server_name ${MINIFLUX_DOMAIN}; - - location / { - resolver 127.0.0.11; - proxy_pass http://${MINIFLUX_HOST}:8080; - } -} - diff --git a/nginx/sites-available/monica.conf.template b/nginx/sites-available/monica.conf.template deleted file mode 100644 index 05e5803..0000000 --- a/nginx/sites-available/monica.conf.template +++ /dev/null @@ -1,25 +0,0 @@ -server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${MONICA_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${MONICA_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - server_name ${MONICA_DOMAIN}; - - client_max_body_size 1G; - - location / { - 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-Host $server_name; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Ssl on; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - resolver 127.0.0.11; - proxy_pass http://${MONICA_HOST}:80; - } -} diff --git a/nginx/sites-available/nefarious.conf.template b/nginx/sites-available/nefarious.conf similarity index 100% rename from nginx/sites-available/nefarious.conf.template rename to nginx/sites-available/nefarious.conf diff --git a/nginx/sites-available/nextcloud.conf.template b/nginx/sites-available/nextcloud.conf similarity index 84% rename from nginx/sites-available/nextcloud.conf.template rename to nginx/sites-available/nextcloud.conf index 9ade02e..e36549d 100644 --- a/nginx/sites-available/nextcloud.conf.template +++ b/nginx/sites-available/nextcloud.conf @@ -1,12 +1,7 @@ server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${NEXTCLOUD_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${NEXTCLOUD_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - # Not sure why http2 is here, but let's keep it just in case - listen [::]:${HTTPS_PORT} ssl http2; - server_name ${NEXTCLOUD_DOMAIN}; + listen 443 ssl; + listen [::]:443 ssl http2; + server_name DOMAIN; # Enable gzip but do not remove ETag headers gzip on; @@ -28,7 +23,7 @@ server { add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location / { - proxy_pass http://${NEXTCLOUD_HOST}:80/; + proxy_pass http://nextcloud_app_1:80/; proxy_pass_request_headers on; diff --git a/nginx/sites-available/podgrab.conf.template b/nginx/sites-available/podgrab.conf.template deleted file mode 100644 index 81ef710..0000000 --- a/nginx/sites-available/podgrab.conf.template +++ /dev/null @@ -1,15 +0,0 @@ -server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${PODGRAB_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${PODGRAB_DOMAIN}/privkey.pem; - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - - server_name ${PODGRAB_DOMAIN}; - - location / { - resolver 127.0.0.11; - proxy_pass http://${PODGRAB_HOST}:8080/; - } -} - diff --git a/nginx/sites-available/portainer.conf b/nginx/sites-available/portainer.conf new file mode 100644 index 0000000..98b1e44 --- /dev/null +++ b/nginx/sites-available/portainer.conf @@ -0,0 +1,11 @@ +server { + listen 443 ssl; + server_name DOMAIN; + + location / { + proxy_set_header Connection "upgrade"; + + resolver 127.0.0.11; + proxy_pass http://portainer_app_1:9000; + } +} diff --git a/nginx/sites-available/portainer.conf.template b/nginx/sites-available/portainer.conf.template deleted file mode 100644 index c9ec72c..0000000 --- a/nginx/sites-available/portainer.conf.template +++ /dev/null @@ -1,16 +0,0 @@ -server { - # SSL Key locations - ssl_certificate /etc/letsencrypt/live/${PORTAINER_DOMAIN}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${PORTAINER_DOMAIN}/privkey.pem; - - listen ${HTTPS_PORT} ssl; - listen [::]:${HTTPS_PORT} ssl; - server_name ${PORTAINER_DOMAIN}; - - location / { - proxy_set_header Connection "upgrade"; - - resolver 127.0.0.11; - proxy_pass http://${PORTAINER_HOST}:9000; - } -} diff --git a/nginx/templates/http.conf.template b/nginx/templates/http.conf.template index bd928c6..2b62f29 100644 --- a/nginx/templates/http.conf.template +++ b/nginx/templates/http.conf.template @@ -1,5 +1,9 @@ http { - # COMMON SSL CONFIGURATION + # SSL CONFIGURATION + # Key locations + ssl_certificate /etc/letsencrypt/live/${MAIN_DOMAIN}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${MAIN_DOMAIN}/privkey.pem; + # Allowed protocols ssl_protocols TLSv1.2; @@ -25,6 +29,7 @@ http { return 301 https://$host:${HTTPS_PORT}$request_uri; } + # LOAD SITES - include conf.d/sites-enabled/*.conf; + include sites-enabled/*.conf; } diff --git a/nginx/templates/sites-enabled/.gitignore b/nginx/templates/sites-enabled/.gitignore deleted file mode 100644 index cec9082..0000000 --- a/nginx/templates/sites-enabled/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* - -!.gitignore diff --git a/podgrab/.env.example b/podgrab/.env.example deleted file mode 100644 index 6c69f28..0000000 --- a/podgrab/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -# How often to check for new episodes in seconds -CHECK_FREQUENCY=240 - -# Password the basic auth -PASSWORD=changeme diff --git a/podgrab/docker-compose.yml b/podgrab/docker-compose.yml deleted file mode 100644 index 47e3707..0000000 --- a/podgrab/docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: '2.4' - -services: - app: - image: 'akhilrex/podgrab:1.0.0' - restart: 'always' - - healthcheck: - test: 'curl -f localhost:8080 || exit 1' - interval: '1m' - timeout: '10s' - retries: 3 - start_period: '10s' - - env_file: - - '.env' - networks: - - 'nginx' - volumes: - - 'config:/config' - - 'assets:/assets' - -networks: - nginx: - external: true - -volumes: - config: - assets: diff --git a/portainer/docker-compose.yml b/portainer/docker-compose.yml index 88165b0..31b62b3 100644 --- a/portainer/docker-compose.yml +++ b/portainer/docker-compose.yml @@ -1,17 +1,12 @@ -version: '2.4' +version: '3.5' services: app: - image: 'portainer/portainer-ce:2.1.1-alpine' + image: 'portainer/portainer-ce:latest' restart: 'always' - healthcheck: - test: 'curl -f localhost:9000 || exit 1' - interval: '1m' - timeout: '10s' - retries: 3 - start_period: '10s' - + labels: + - 'com.centurylinklabs.watchtower.enable=true' networks: - 'nginx' ports: @@ -22,7 +17,8 @@ services: networks: nginx: - external: true + external: + name: 'nginx' volumes: data: diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 7190a60..0000000 --- a/renovate.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json" -} diff --git a/tshock/.env.example b/tshock/.env.example index 0a562b3..fea30eb 100644 --- a/tshock/.env.example +++ b/tshock/.env.example @@ -1,15 +1,29 @@ -# What version of TShock to use +# Copyright (C) 2020 Jef Roosens + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# Build arguments RELEASE_TAG= -# What world size to create: -# 1 for small, 2 for medium, 3 for large +# Environment variables AUTOCREATE=2 -# Mount points for the data directories -# By default, it creates volumes -CONFIG_DIR=config -LOGS_DIR=logs -WORLDS_DIR=worlds +# Mount points +CONFIG_DIR= +LOGS_DIR= +WORLDS_DIR= -# The port to publish the server on +# Other PORT=7777 diff --git a/tshock/Dockerfile b/tshock/Dockerfile index c9f2d50..2c694c1 100644 --- a/tshock/Dockerfile +++ b/tshock/Dockerfile @@ -1,27 +1,49 @@ -FROM alpine:3.13.5 AS base +# Copyright (C) 2020 Jef Roosens + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +FROM alpine:latest AS base # Build arguments ARG RELEASE_TAG +# Add unzip & curl +RUN apk update && apk add --no-cache unzip curl + WORKDIR /terraria -RUN apk update && apk add --no-cache unzip curl && \ - curl -s "https://api.github.com/repos/Pryaxis/TShock/releases/tags/${RELEASE_TAG}" | \ - grep "browser_download_url" | \ - grep -o "https[^\"]\+" | \ - xargs curl -sLo tshock.zip && \ - unzip -d tshock tshock.zip && \ - rm tshock.zip +# Download & unzip +# TODO convert this to jq? +RUN curl -s "https://api.github.com/repos/Pryaxis/TShock/releases/tags/${RELEASE_TAG}" | \ +grep "browser_download_url" | \ +grep -o "https[^\"]\+" | \ +xargs curl -sLo tshock.zip && \ +unzip tshock.zip && \ +rm tshock.zip && \ +# Is there a better way to do this? +mv TShock* tshock -FROM mono:6.12.0.107 +FROM mono:latest WORKDIR /terraria COPY --from=base /terraria/tshock /terraria # Create worlds directory & symlink it RUN mkdir -p worlds logs config /root/.local/share/Terraria && \ - ln -s /terraria/worlds /root/.local/share/Terraria/Worlds +ln -s /terraria/worlds /root/.local/share/Terraria/Worlds ENTRYPOINT \ mono /terraria/TerrariaServer.exe \ diff --git a/tshock/README.md b/tshock/README.md index 8cda9d8..4351aa4 100644 --- a/tshock/README.md +++ b/tshock/README.md @@ -1,3 +1,23 @@ + + + # Build arguments The only required build argument is `RELEASE_TAG`. This is the GitHub tag of the release you wish to use. The releases can be found diff --git a/tshock/docker-compose.yml b/tshock/docker-compose.yml index 32181e7..31ad2a0 100644 --- a/tshock/docker-compose.yml +++ b/tshock/docker-compose.yml @@ -1,25 +1,37 @@ -version: '2.4' +# Copyright (C) 2020 Jef Roosens + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +version: '3.5' services: - app: + tshock: build: context: . args: - 'RELEASE_TAG=${RELEASE_TAG}' - image: 'chewingbever/terraria-tshock:${RELEASE_TAG}' - restart: 'always' + image: 'terraria-tshock:${RELEASE_TAG}' + + restart: 'unless-stopped' stdin_open: true tty: true environment: - - 'AUTOCREATE' + - AUTOCREATE ports: - '$PORT:7777' volumes: - '$CONFIG_DIR:/terraria/config' - '$LOGS_DIR:/terraria/logs' - '$WORLDS_DIR:/terraria/worlds' - -volumes: - config: - logs: - worlds: diff --git a/vim/de b/vim/de index fb00846..18f7acf 100755 --- a/vim/de +++ b/vim/de @@ -1,3 +1,2 @@ -#!/usr/bin/env sh - +#!/usr/bin/env bash docker run --rm -it -v "$1":/data -w '/data' chewingbever/nvim:latest