blob: 9ed5e90e495283ba64b18b276be64cd137bd7d8b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
# This module implements a really simple and shitty WSGI app which streams
# journald logs to the client. I don't expect it to hang around for long, so
# it's just quickly hacked together.
#
# FIXME: There's still the issue with broken connections. Perhaps heartbeat would fix.
{
pkgs,
config,
...
}: let
# Enable HTTPS stuff.
useACME = true;
socket-path = "/run/minecraft-log-server.sock";
python = pkgs.python3.withPackages (ps:
with ps; [
gevent
gunicorn
]);
in {
users.users.minecraft-log-server = {
description = "Runs minecraft-log-server";
group = "minecraft-log-server";
isSystemUser = true;
};
users.groups.minecraft-log-server = {};
systemd.sockets.minecraft-log-server = {
description = "Socket where the service of the same name answers HTTP requests.";
socketConfig = {
ListenStream = socket-path;
# TODO: wtf apple maps
SocketUser = "nginx";
SocketGroup = "nginx";
SocketMode = "600";
};
wantedBy = ["sockets.target"];
};
# See: https://docs.gunicorn.org/en/23.0.0/deploy.html
systemd.services.minecraft-log-server = {
description = "Minecraft log server";
serviceConfig = {
# Using a non-sync worker class is super important because we have such long-running connections.
ExecStart = "${python}/bin/gunicorn --worker-class=gevent --chdir ${./.} minecraft_log_server:app";
ExecReload = "kill -s HUP $MAINPID";
KillMode = "mixed";
User = config.users.users.minecraft-log-server.uid;
Group = config.users.users.minecraft-log-server.group;
# gunicorn can let systemd know when it is ready
Type = "notify";
NotifyAccess = "main";
# Harden
ProtectSystem = "strict";
PrivateTmp = true;
};
requires = ["minecraft-log-server.socket"]; # Refuse to start without.
after = ["network.target"];
};
services.nginx = {
virtualHosts."minecraft.linus.onl" = {
enableACME = useACME;
forceSSL = useACME;
# Let's be safe and pass-word protect it just in case the logs contain some sensitive data.
basicAuthFile = ./.htpasswd;
# First try resolving files statically, before falling back to the CGI server.
locations."/" = {
alias = "${./public}/";
index = "index.html";
tryFiles = "$uri $uri/ @minecraft_log_server";
};
locations."@minecraft_log_server" = {
recommendedProxySettings = true;
# In addition to the important stuff set indirectly via `recommendedProxySettings`
# (especially `proxy_http_version`), we need these options for SSE.
extraConfig = ''
# Disable buffering. This is crucial for SSE to ensure that
# messages are sent immediately without waiting for a buffer to
# fill.
proxy_buffering off;
# Disable caching to ensure that all messages are sent and received
# in real-time without being cached by the proxy.
proxy_cache off;
# Set a long timeout for reading from the proxy to prevent the
# connection from timing out. You may need to adjust this value
# based on your specific requirements.
proxy_read_timeout 86400;
'';
proxyPass = "http://unix:${socket-path}:$request_uri";
};
};
};
services.cloudflare-dyndns.domains = ["minecraft.linus.onl"];
}
|