Compare commits
15 Commits
ip-rate-li
...
master
Author | SHA1 | Date | |
---|---|---|---|
c90cb7d000 | |||
ac51f5d3ae | |||
7a08ba4ac2 | |||
d449146207 | |||
86e9ab7c88 | |||
25df631ce8 | |||
1fd090e379 | |||
56580c2afe | |||
6845a6f232 | |||
55c01499dd | |||
21caa3f7a1 | |||
095de45d54 | |||
e276004266 | |||
2d28923d3b | |||
75ef33e181 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
server.log
|
||||
map
|
||||
map-old
|
||||
secrets.py
|
||||
|
@ -1,12 +1,10 @@
|
||||
import calendar
|
||||
import logging
|
||||
import shlex
|
||||
import subprocess
|
||||
from datetime import datetime, timedelta
|
||||
import unicodedata
|
||||
|
||||
import redis
|
||||
from flask import Flask, request
|
||||
|
||||
conn = redis.Redis('localhost')
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@ -16,27 +14,31 @@ def setup_logging():
|
||||
app.logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def sanitize_input(input):
|
||||
input = "".join(ch for ch in input if unicodedata.category(ch)[0] != "C")
|
||||
return shlex.quote(input.replace('^', ''))
|
||||
|
||||
|
||||
@app.route('/chat/', methods=['POST'])
|
||||
def send_chat():
|
||||
if request.method == 'POST':
|
||||
ip = request.headers.get('X-Forwarded-For', request.remote_addr)
|
||||
recent_ips = conn.hgetall("minecraft_chat_recent_ips")
|
||||
now = datetime.utcnow()
|
||||
if ip in recent_ips:
|
||||
if (now - datetime.fromutctimestamp(recent_ips[ip])) > timedelta.seconds(30):
|
||||
recent_ips[ip] = calendar.timegm(now.utctimetuple())
|
||||
if request.form.get('email', None):
|
||||
return 'Text was entered into honeypot!', 200
|
||||
if not request.form.get('say-text', None):
|
||||
return 'No message to send!', 422
|
||||
if request.form.get('say-username', None):
|
||||
subprocess.call(['/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
|
||||
'/say [{}]: {}\015'.format(request.form['say-username'], request.form['say-text'])])
|
||||
subprocess.call([
|
||||
'/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
|
||||
'/say [{}]: {}\015'.format(
|
||||
sanitize_input(request.form['say-username']),
|
||||
sanitize_input(request.form['say-text']))
|
||||
])
|
||||
else:
|
||||
subprocess.call(['/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
|
||||
'/say {}\015'.format(request.form['say-text'])])
|
||||
subprocess.call([
|
||||
'/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
|
||||
'/say {}\015'.format(sanitize_input(request.form['say-text']))
|
||||
])
|
||||
return 'Sending chat: ' + request.form.get('say-username', '') + ': ' + request.form['say-text']
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host='0.0.0.0', port="8888")
|
||||
|
13
config/minecraft-chat.service
Normal file
13
config/minecraft-chat.service
Normal file
@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Gunicorn instance to serve minecraft-chat wsgi service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=thallada
|
||||
Group=www-data
|
||||
WorkingDirectory=/var/www/panic-shack/chat
|
||||
Environment="PATH=/home/thallada/.virtualenvs/minecraft-chat/bin"
|
||||
ExecStart=/home/thallada/.virtualenvs/minecraft-chat/bin/gunicorn --workers 1 --bind unix:minecraft-chat.sock -m 007 server:app --log-file /srv/minecraft-panic-shack/gunicorn.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
50
config/minecraft@.service
Normal file
50
config/minecraft@.service
Normal file
@ -0,0 +1,50 @@
|
||||
[Unit]
|
||||
Description=Minecraft Server %i
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/srv/minecraft-%i
|
||||
User=thallada
|
||||
Group=thallada
|
||||
ProtectSystem=full
|
||||
ProtectHome=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
|
||||
|
||||
ExecStart=/bin/sh -c '/usr/bin/screen -DmLS mc-%i /usr/bin/java -server -Xms1G -Xmx2G -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar $(ls -v | grep -i "FTBServer.*jar\|minecraft_server.*jar" | head -n 1) nogui'
|
||||
|
||||
ExecReload=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "reload"\\015'
|
||||
|
||||
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 15 SECONDS..."\015'
|
||||
ExecStop=/bin/sleep 5
|
||||
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 10 SECONDS..."\015'
|
||||
ExecStop=/bin/sleep 5
|
||||
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 5 SECONDS..."\015'
|
||||
ExecStop=/bin/sleep 5
|
||||
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN. Saving map..."\\015'
|
||||
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\\015'
|
||||
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\\015'
|
||||
ExecStop=/bin/sleep 2
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=60s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
#########
|
||||
# HowTo
|
||||
#########
|
||||
#
|
||||
# Create directory in /opt/minecraft-XX where XX is a name like 'survival'
|
||||
# Add minecraft_server.jar into dir with other conf files for minecraft server
|
||||
#
|
||||
# Enable/Start systemd service
|
||||
# systemctl enable minecraft@survival
|
||||
# systemctl start minecraft@survival
|
||||
#
|
||||
# To run multiple servers simply create a new dir structure and enable/start it
|
||||
# systemctl enable minecraft@creative
|
||||
# systemctl start minecraft@creative
|
12
config/nginx-panic-shack
Normal file
12
config/nginx-panic-shack
Normal file
@ -0,0 +1,12 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
root /var/www/panic-shack;
|
||||
|
||||
server_name panic-shack.hallada.net;
|
||||
|
||||
location / {
|
||||
return 301 https://panic-shack.hallada.net$request_uri;
|
||||
}
|
||||
}
|
36
config/nginx-panic-shack-https
Normal file
36
config/nginx-panic-shack-https
Normal file
@ -0,0 +1,36 @@
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name panic-shack.hallada.net;
|
||||
root /var/www/panic-shack;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/panic-shack.hallada.net/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/panic-shack.hallada.net/privkey.pem;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/panic-shack.hallada.net/fullchain.pem;
|
||||
|
||||
location /notify {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
location /config {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.php?$args =404;
|
||||
}
|
||||
|
||||
location /old-worlds {
|
||||
autoindex on;
|
||||
try_files $uri $uri/ $uri.php?$args =404;
|
||||
}
|
||||
|
||||
location /chat {
|
||||
include uwsgi_params;
|
||||
proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Forwarded-Server $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass http://unix:/var/www/panic-shack/chat/minecraft-chat.sock;
|
||||
}
|
||||
}
|
130
config/overviewerConfig.py
Normal file
130
config/overviewerConfig.py
Normal file
@ -0,0 +1,130 @@
|
||||
worlds["Death Pit"] = "/srv/minecraft-panic-shack/world"
|
||||
|
||||
renders["normalrender"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "North",
|
||||
"rendermode": smooth_lighting,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "upper-left",
|
||||
}
|
||||
|
||||
renders["normalrendersouth"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "South",
|
||||
"rendermode": smooth_lighting,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "lower-right",
|
||||
}
|
||||
|
||||
renders["normalrenderwest"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "West",
|
||||
"rendermode": smooth_lighting,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "upper-right",
|
||||
}
|
||||
|
||||
renders["normalrendereast"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "East",
|
||||
"rendermode": smooth_lighting,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "lower-left",
|
||||
}
|
||||
|
||||
renders["nightrender"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Night North",
|
||||
"rendermode": smooth_night,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "upper-left",
|
||||
}
|
||||
|
||||
renders["nightrendersouth"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Night South",
|
||||
"rendermode": smooth_night,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "lower-right",
|
||||
}
|
||||
|
||||
renders["nightrenderwest"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Night West",
|
||||
"rendermode": smooth_night,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "upper-right",
|
||||
}
|
||||
|
||||
renders["nightrendereast"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Night East",
|
||||
"rendermode": smooth_night,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "lower-left",
|
||||
}
|
||||
|
||||
renders["caverender"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Cave North",
|
||||
"rendermode": cave,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "upper-left",
|
||||
}
|
||||
|
||||
renders["caverendersouth"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Cave South",
|
||||
"rendermode": cave,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "lower-right",
|
||||
}
|
||||
|
||||
renders["caverenderwest"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Cave West",
|
||||
"rendermode": cave,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "upper-right",
|
||||
}
|
||||
|
||||
renders["caverendereast"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Cave East",
|
||||
"rendermode": cave,
|
||||
"dimension": "overworld",
|
||||
"northdirection": "lower-left",
|
||||
}
|
||||
|
||||
renders["netherrender"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Nether North",
|
||||
"rendermode": nether,
|
||||
"dimension": "nether",
|
||||
"northdirection": "upper-left",
|
||||
}
|
||||
|
||||
renders["netherrendersouth"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Nether South",
|
||||
"rendermode": nether,
|
||||
"dimension": "nether",
|
||||
"northdirection": "lower-right",
|
||||
}
|
||||
|
||||
renders["netherrenderwest"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Nether West",
|
||||
"rendermode": nether,
|
||||
"dimension": "nether",
|
||||
"northdirection": "upper-right",
|
||||
}
|
||||
renders["netherrendereast"] = {
|
||||
"world": "Death Pit",
|
||||
"title": "Nether East",
|
||||
"rendermode": nether,
|
||||
"dimension": "nether",
|
||||
"northdirection": "lower-left",
|
||||
}
|
||||
|
||||
outputdir = "/var/www/panic-shack/map/"
|
@ -68,7 +68,7 @@ ol li code {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#map-link {
|
||||
.map-link {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
@ -130,3 +130,18 @@ ol li code {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.maintenance-notice {
|
||||
padding: 20px;
|
||||
background: darkred;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.maintenance-notice h3 {
|
||||
margin: 0;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.maintenance-notice h3,span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
BIN
img/deathpit.png
Normal file
BIN
img/deathpit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 328 KiB |
BIN
img/deathpit_shader_sm.png
Normal file
BIN
img/deathpit_shader_sm.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 496 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
80
index.html
80
index.html
@ -7,9 +7,13 @@
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<!-- <div class="maintenance-notice"> -->
|
||||
<!-- <h3>Server is down</h3> -->
|
||||
<!-- <span>ETA: 15 hours for generating a new Minecraft 1.13 map.</span> -->
|
||||
<!-- </div> -->
|
||||
<div class="width-limit">
|
||||
<h1>Panic Shack - Minecraft Server</h1>
|
||||
<img src="img/bridge.jpg" alt="Screenshot from the Minecraft server of a bridge over a lake in a jungle biome">
|
||||
<img src="img/deathpit_shader_sm.png" alt="Screenshot from the Minecraft server of the swamp and the large house in the distance">
|
||||
|
||||
<h2>Server Status</h2>
|
||||
<div id="server-status-error">
|
||||
@ -60,6 +64,7 @@
|
||||
|
||||
<h2>How to Connect</h2>
|
||||
<ol>
|
||||
<li>Email me at tyler@hallada.net with your Minecraft username to request to join the server</li>
|
||||
<li>Launch Minecraft (version <span id="info-server-name">1.12.2</span>)</li>
|
||||
<li>Go to "Multiplayer"</li>
|
||||
<li>Click "Add Server"</li>
|
||||
@ -69,16 +74,22 @@
|
||||
<li>You should now see the server in the list and be able to join it!</li>
|
||||
</ol>
|
||||
|
||||
<h2>Server Map</h2>
|
||||
<a href="map/" id="map-link">
|
||||
<img src="img/map.jpg" alt="Screenshot from the in-browser map of the server centered on the lake and bridge">
|
||||
View the server map
|
||||
<h2>Server Maps</h2>
|
||||
<a href="map/" class="map-link">
|
||||
<img src="img/deathpit.png" alt="Screenshot from the in-browser map of the death pit server">
|
||||
View Death Pit map
|
||||
</a>
|
||||
<p class="small-text">
|
||||
Map is updated every day around 3 am EST. Last updated:
|
||||
<span id="map-last-updated" class="small-text"></span>
|
||||
This map is updated every day around 3 am EST. Last updated:
|
||||
<span id="map-last-updated" class="small-text"></span><br>
|
||||
</p>
|
||||
<a href="map-old/" class="map-link">
|
||||
<img src="img/map-old.jpg" alt="Screenshot from the in-browser map of the panic-shack server centered on the lake and bridge">
|
||||
View Panic Shack map
|
||||
</a>
|
||||
<p class="small-text">
|
||||
This map was last updated: 04/04/2019.
|
||||
</p>
|
||||
|
||||
<h2>Server Log</h2>
|
||||
</div>
|
||||
<pre id="server-log"></pre>
|
||||
@ -109,6 +120,59 @@
|
||||
<span id="say-error" class="inline"></span>
|
||||
<p id="say-notice" class="small-text">It may take a minute or two before the message appears in the above server log.</p>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Download Old Worlds</h2>
|
||||
<p>
|
||||
<a href="/old-worlds">Visit here to download all of the previous worlds on this server.</a> You can load
|
||||
them in Minecraft and play them in single player by following
|
||||
<a href="https://minecraft.gamepedia.com/Tutorials/Map_downloads">these instructions</a>.
|
||||
</p>
|
||||
|
||||
<h2>Notices</h2>
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>September 5, 2020</strong>
|
||||
Server is back up and running on Minecraft 1.16.2 with a new map.
|
||||
</li>
|
||||
<li>
|
||||
<strong>May 18, 2020</strong>
|
||||
Hibernating this server for a while to save resources for a 7DaysToDie server instead.
|
||||
</li>
|
||||
<li>
|
||||
<strong>April 19, 2020</strong>
|
||||
I switched the server over to a Spigot 1.15.2 server with the Vivecraft extension installed.
|
||||
</li>
|
||||
<li>
|
||||
<strong>July 14, 2019:</strong>
|
||||
Upgraded the server to 1.14.3 and regenerated the map. It's now using the seed "hardlead".
|
||||
</li>
|
||||
<li>
|
||||
<strong>August 22, 2018:</strong>
|
||||
Upgraded the server yet again to 1.13.1.
|
||||
</li>
|
||||
<li>
|
||||
<strong>August 22, 2018:</strong>
|
||||
The map should now be updating again nightly at 3 am EST.
|
||||
</li>
|
||||
<li>
|
||||
<strong>August 16, 2018:</strong>
|
||||
I upgraded the server to Minecraft version 1.13. The map is no longer working on this version and
|
||||
won't update. I'll upgrade the map once it supports 1.13.
|
||||
</li>
|
||||
<li>
|
||||
<strong>April 15, 2018:</strong>
|
||||
The server has a user white-list. If you are not added to it then you cannot join the server.
|
||||
Email me at tyler@hallada.net to request to join the server.
|
||||
</li>
|
||||
<li>
|
||||
<strong>April 13, 2018:</strong>
|
||||
I doubled the memory on the server so the server shouldn't keep running out of memory and crashing.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="https://mcapi.us/scripts/minecraft.js"></script>
|
||||
|
52
notify/notify_joins.py
Executable file
52
notify/notify_joins.py
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
# Read the Minecraft server log and diff it against the server log it saw last. If there any new joins in the diff, send
|
||||
# a notification.
|
||||
import codecs
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
from secrets import IFTTT_WEBHOOK_KEY_TYLER, IFTTT_WEBHOOK_KEY_KAELAN
|
||||
|
||||
LOG_FILENAME = '/srv/minecraft-panic-shack/logs/latest.log'
|
||||
OLD_LOG_FILENAME = '/srv/minecraft-panic-shack/logs/last-read.log'
|
||||
USERNAME_BLACKLIST = ['anarchyeight', 'kinedactyl']
|
||||
IFTTT_EVENT_NAME = 'user_joined_panic_shack'
|
||||
|
||||
|
||||
def read_log(filename):
|
||||
with codecs.open(filename, encoding='utf-8') as log:
|
||||
return log.readlines()
|
||||
|
||||
|
||||
def save_log(filename, lines):
|
||||
with codecs.open(filename, 'w', encoding='utf-8') as log:
|
||||
log.writelines(lines)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if (datetime.fromtimestamp(os.path.getmtime(LOG_FILENAME)) >
|
||||
datetime.fromtimestamp(os.path.getmtime(OLD_LOG_FILENAME))):
|
||||
new_log = read_log(LOG_FILENAME)
|
||||
old_log = read_log(OLD_LOG_FILENAME)
|
||||
if new_log[0] != old_log[0]:
|
||||
# A log rotate occured
|
||||
old_log = []
|
||||
if len(new_log) > len(old_log):
|
||||
for new_line in new_log[len(old_log):]:
|
||||
match = re.match('[\[][0-9:]+[\]]\s[\[]Server thread/INFO]: (\S+) joined the game', new_line)
|
||||
if match:
|
||||
username = match.group(1)
|
||||
if username not in USERNAME_BLACKLIST:
|
||||
# IFTTT does not support sharing Applets anymore :(
|
||||
r = requests.post(
|
||||
'https://maker.ifttt.com/trigger/{}/with/key/{}'.format(IFTTT_EVENT_NAME,
|
||||
IFTTT_WEBHOOK_KEY_TYLER),
|
||||
data={'value1': username})
|
||||
r = requests.post(
|
||||
'https://maker.ifttt.com/trigger/{}/with/key/{}'.format(IFTTT_EVENT_NAME,
|
||||
IFTTT_WEBHOOK_KEY_KAELAN),
|
||||
data={'value1': username})
|
||||
save_log(OLD_LOG_FILENAME, new_log)
|
1
old-worlds
Symbolic link
1
old-worlds
Symbolic link
@ -0,0 +1 @@
|
||||
/srv/minecraft-panic-shack/old-worlds
|
Loading…
Reference in New Issue
Block a user