Skip to main content

max / multithreaded

Hetzner deployment, switch to rustls-tls for cross-compilation Add deploy-hetzner.sh cross-compile script and env.hetzner config. Switch reqwest from native-tls to rustls-tls to avoid openssl-sys cross-compilation issues. OAuth app registered in MNW production DB. Deployed to forums.makenot.work behind Cloudflare proxy. Bump to v0.2.3. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-03-15 17:26 UTC
Commit: c7cb56810a3875f70ed1a9a08108da422051dad5
Parent: 289ed0b
5 files changed, +239 insertions, -245 deletions
M Cargo.lock +79 -240
@@ -248,6 +248,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
248 248 checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
249 249
250 250 [[package]]
251 + name = "cfg_aliases"
252 + version = "0.2.1"
253 + source = "registry+https://github.com/rust-lang/crates.io-index"
254 + checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
255 +
256 + [[package]]
251 257 name = "chrono"
252 258 version = "0.4.44"
253 259 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -288,26 +294,6 @@ dependencies = [
288 294 ]
289 295
290 296 [[package]]
291 - name = "core-foundation"
292 - version = "0.9.4"
293 - source = "registry+https://github.com/rust-lang/crates.io-index"
294 - checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
295 - dependencies = [
296 - "core-foundation-sys",
297 - "libc",
298 - ]
299 -
300 - [[package]]
301 - name = "core-foundation"
302 - version = "0.10.1"
303 - source = "registry+https://github.com/rust-lang/crates.io-index"
304 - checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
305 - dependencies = [
306 - "core-foundation-sys",
307 - "libc",
308 - ]
309 -
310 - [[package]]
311 297 name = "core-foundation-sys"
312 298 version = "0.8.7"
313 299 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -480,15 +466,6 @@ dependencies = [
480 466 ]
481 467
482 468 [[package]]
483 - name = "encoding_rs"
484 - version = "0.8.35"
485 - source = "registry+https://github.com/rust-lang/crates.io-index"
486 - checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
487 - dependencies = [
488 - "cfg-if",
489 - ]
490 -
491 - [[package]]
492 469 name = "equivalent"
493 470 version = "1.0.2"
494 471 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -527,12 +504,6 @@ dependencies = [
527 504 ]
528 505
529 506 [[package]]
530 - name = "fastrand"
531 - version = "2.3.0"
532 - source = "registry+https://github.com/rust-lang/crates.io-index"
533 - checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
534 -
535 - [[package]]
536 507 name = "find-msvc-tools"
537 508 version = "0.1.9"
538 509 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -550,33 +521,12 @@ dependencies = [
550 521 ]
551 522
552 523 [[package]]
553 - name = "fnv"
554 - version = "1.0.7"
555 - source = "registry+https://github.com/rust-lang/crates.io-index"
556 - checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
557 -
558 - [[package]]
559 524 name = "foldhash"
560 525 version = "0.1.5"
561 526 source = "registry+https://github.com/rust-lang/crates.io-index"
562 527 checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
563 528
564 529 [[package]]
565 - name = "foreign-types"
566 - version = "0.3.2"
567 - source = "registry+https://github.com/rust-lang/crates.io-index"
568 - checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
569 - dependencies = [
570 - "foreign-types-shared",
571 - ]
572 -
573 - [[package]]
574 - name = "foreign-types-shared"
575 - version = "0.1.1"
576 - source = "registry+https://github.com/rust-lang/crates.io-index"
577 - checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
578 -
579 - [[package]]
580 530 name = "form_urlencoded"
581 531 version = "1.2.2"
582 532 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -734,8 +684,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
734 684 checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
735 685 dependencies = [
736 686 "cfg-if",
687 + "js-sys",
737 688 "libc",
738 689 "wasi",
690 + "wasm-bindgen",
739 691 ]
740 692
741 693 [[package]]
@@ -789,25 +741,6 @@ dependencies = [
789 741 ]
790 742
791 743 [[package]]
792 - name = "h2"
793 - version = "0.4.13"
794 - source = "registry+https://github.com/rust-lang/crates.io-index"
795 - checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
796 - dependencies = [
797 - "atomic-waker",
798 - "bytes",
799 - "fnv",
800 - "futures-core",
801 - "futures-sink",
802 - "http",
803 - "indexmap",
804 - "slab",
805 - "tokio",
806 - "tokio-util",
807 - "tracing",
808 - ]
809 -
810 - [[package]]
811 744 name = "hashbrown"
812 745 version = "0.14.5"
813 746 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -950,7 +883,6 @@ dependencies = [
950 883 "bytes",
951 884 "futures-channel",
952 885 "futures-core",
953 - "h2",
954 886 "http",
955 887 "http-body",
956 888 "httparse",
@@ -977,22 +909,7 @@ dependencies = [
977 909 "tokio",
978 910 "tokio-rustls",
979 911 "tower-service",
980 - ]
981 -
982 - [[package]]
983 - name = "hyper-tls"
984 - version = "0.6.0"
985 - source = "registry+https://github.com/rust-lang/crates.io-index"
986 - checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
987 - dependencies = [
988 - "bytes",
989 - "http-body-util",
990 - "hyper",
991 - "hyper-util",
992 - "native-tls",
993 - "tokio",
994 - "tokio-native-tls",
995 - "tower-service",
912 + "webpki-roots",
996 913 ]
997 914
998 915 [[package]]
@@ -1013,11 +930,9 @@ dependencies = [
1013 930 "percent-encoding",
1014 931 "pin-project-lite",
1015 932 "socket2",
1016 - "system-configuration",
1017 933 "tokio",
1018 934 "tower-service",
1019 935 "tracing",
1020 - "windows-registry",
1021 936 ]
1022 937
1023 938 [[package]]
@@ -1246,12 +1161,6 @@ dependencies = [
1246 1161 ]
1247 1162
1248 1163 [[package]]
1249 - name = "linux-raw-sys"
1250 - version = "0.12.1"
1251 - source = "registry+https://github.com/rust-lang/crates.io-index"
1252 - checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
1253 -
1254 - [[package]]
1255 1164 name = "litemap"
1256 1165 version = "0.8.1"
1257 1166 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1274,6 +1183,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1274 1183 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
1275 1184
1276 1185 [[package]]
1186 + name = "lru-slab"
1187 + version = "0.1.2"
1188 + source = "registry+https://github.com/rust-lang/crates.io-index"
1189 + checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
1190 +
1191 + [[package]]
1277 1192 name = "mac"
1278 1193 version = "0.1.1"
1279 1194 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1367,14 +1282,14 @@ dependencies = [
1367 1282
1368 1283 [[package]]
1369 1284 name = "mt-core"
1370 - version = "0.2.1"
1285 + version = "0.2.2"
1371 1286 dependencies = [
1372 1287 "chrono",
1373 1288 ]
1374 1289
1375 1290 [[package]]
1376 1291 name = "mt-db"
1377 - version = "0.2.1"
1292 + version = "0.2.2"
1378 1293 dependencies = [
1379 1294 "chrono",
1380 1295 "sqlx",
@@ -1384,7 +1299,7 @@ dependencies = [
1384 1299
1385 1300 [[package]]
1386 1301 name = "multithreaded"
1387 - version = "0.2.1"
1302 + version = "0.2.2"
1388 1303 dependencies = [
1389 1304 "ammonia",
1390 1305 "askama",
@@ -1418,23 +1333,6 @@ dependencies = [
1418 1333 ]
1419 1334
1420 1335 [[package]]
1421 - name = "native-tls"
1422 - version = "0.2.18"
1423 - source = "registry+https://github.com/rust-lang/crates.io-index"
1424 - checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
1425 - dependencies = [
1426 - "libc",
1427 - "log",
1428 - "openssl",
1429 - "openssl-probe",
1430 - "openssl-sys",
1431 - "schannel",
1432 - "security-framework",
1433 - "security-framework-sys",
1434 - "tempfile",
1435 - ]
1436 -
1437 - [[package]]
1438 1336 name = "new_debug_unreachable"
1439 1337 version = "1.0.6"
1440 1338 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1526,50 +1424,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1526 1424 checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
1527 1425
1528 1426 [[package]]
1529 - name = "openssl"
1530 - version = "0.10.76"
1531 - source = "registry+https://github.com/rust-lang/crates.io-index"
1532 - checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf"
1533 - dependencies = [
1534 - "bitflags",
1535 - "cfg-if",
1536 - "foreign-types",
1537 - "libc",
1538 - "once_cell",
1539 - "openssl-macros",
1540 - "openssl-sys",
1541 - ]
1542 -
1543 - [[package]]
1544 - name = "openssl-macros"
1545 - version = "0.1.1"
1546 - source = "registry+https://github.com/rust-lang/crates.io-index"
1547 - checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
1548 - dependencies = [
1549 - "proc-macro2",
1550 - "quote",
1551 - "syn",
1552 - ]
1553 -
1554 - [[package]]
1555 - name = "openssl-probe"
1556 - version = "0.2.1"
1557 - source = "registry+https://github.com/rust-lang/crates.io-index"
1558 - checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
1559 -
1560 - [[package]]
1561 - name = "openssl-sys"
1562 - version = "0.9.112"
1563 - source = "registry+https://github.com/rust-lang/crates.io-index"
1564 - checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb"
1565 - dependencies = [
1566 - "cc",
1567 - "libc",
1568 - "pkg-config",
1569 - "vcpkg",
1570 - ]
1571 -
1572 - [[package]]
1573 1427 name = "parking"
1574 1428 version = "2.2.1"
1575 1429 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1820,6 +1674,61 @@ dependencies = [
1820 1674 ]
1821 1675
1822 1676 [[package]]
1677 + name = "quinn"
1678 + version = "0.11.9"
1679 + source = "registry+https://github.com/rust-lang/crates.io-index"
1680 + checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
1681 + dependencies = [
1682 + "bytes",
1683 + "cfg_aliases",
1684 + "pin-project-lite",
1685 + "quinn-proto",
1686 + "quinn-udp",
1687 + "rustc-hash",
1688 + "rustls",
1689 + "socket2",
1690 + "thiserror 2.0.18",
1691 + "tokio",
1692 + "tracing",
1693 + "web-time",
1694 + ]
1695 +
1696 + [[package]]
1697 + name = "quinn-proto"
1698 + version = "0.11.14"
1699 + source = "registry+https://github.com/rust-lang/crates.io-index"
1700 + checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
1701 + dependencies = [
1702 + "bytes",
1703 + "getrandom 0.3.4",
1704 + "lru-slab",
1705 + "rand 0.9.2",
1706 + "ring",
1707 + "rustc-hash",
1708 + "rustls",
1709 + "rustls-pki-types",
1710 + "slab",
1711 + "thiserror 2.0.18",
1712 + "tinyvec",
1713 + "tracing",
1714 + "web-time",
1715 + ]
1716 +
1717 + [[package]]
1718 + name = "quinn-udp"
1719 + version = "0.5.14"
1720 + source = "registry+https://github.com/rust-lang/crates.io-index"
1721 + checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
1722 + dependencies = [
1723 + "cfg_aliases",
1724 + "libc",
1725 + "once_cell",
1726 + "socket2",
1727 + "tracing",
1728 + "windows-sys 0.52.0",
1729 + ]
1730 +
1731 + [[package]]
1823 1732 name = "quote"
1824 1733 version = "1.0.45"
1825 1734 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1951,29 +1860,26 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
1951 1860 dependencies = [
1952 1861 "base64",
1953 1862 "bytes",
1954 - "encoding_rs",
1955 1863 "futures-core",
1956 - "h2",
1957 1864 "http",
1958 1865 "http-body",
1959 1866 "http-body-util",
1960 1867 "hyper",
1961 1868 "hyper-rustls",
1962 - "hyper-tls",
1963 1869 "hyper-util",
1964 1870 "js-sys",
1965 1871 "log",
1966 - "mime",
1967 - "native-tls",
1968 1872 "percent-encoding",
1969 1873 "pin-project-lite",
1874 + "quinn",
1875 + "rustls",
1970 1876 "rustls-pki-types",
1971 1877 "serde",
1972 1878 "serde_json",
1973 1879 "serde_urlencoded",
1974 1880 "sync_wrapper",
1975 1881 "tokio",
1976 - "tokio-native-tls",
1882 + "tokio-rustls",
1977 1883 "tower",
1978 1884 "tower-http",
1979 1885 "tower-service",
@@ -1981,6 +1887,7 @@ dependencies = [
1981 1887 "wasm-bindgen",
1982 1888 "wasm-bindgen-futures",
1983 1889 "web-sys",
1890 + "webpki-roots",
1984 1891 ]
1985 1892
1986 1893 [[package]]
@@ -2043,25 +1950,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2043 1950 checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
2044 1951
2045 1952 [[package]]
2046 - name = "rustix"
2047 - version = "1.1.4"
2048 - source = "registry+https://github.com/rust-lang/crates.io-index"
2049 - checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
2050 - dependencies = [
2051 - "bitflags",
2052 - "errno",
2053 - "libc",
2054 - "linux-raw-sys",
2055 - "windows-sys 0.61.2",
2056 - ]
2057 -
2058 - [[package]]
2059 1953 name = "rustls"
2060 1954 version = "0.23.37"
2061 1955 source = "registry+https://github.com/rust-lang/crates.io-index"
2062 1956 checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
2063 1957 dependencies = [
2064 1958 "once_cell",
1959 + "ring",
2065 1960 "rustls-pki-types",
2066 1961 "rustls-webpki",
2067 1962 "subtle",
@@ -2074,6 +1969,7 @@ version = "1.14.0"
2074 1969 source = "registry+https://github.com/rust-lang/crates.io-index"
2075 1970 checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
2076 1971 dependencies = [
1972 + "web-time",
2077 1973 "zeroize",
2078 1974 ]
2079 1975
@@ -2101,44 +1997,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2101 1997 checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
2102 1998
2103 1999 [[package]]
2104 - name = "schannel"
2105 - version = "0.1.29"
2106 - source = "registry+https://github.com/rust-lang/crates.io-index"
2107 - checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
2108 - dependencies = [
2109 - "windows-sys 0.61.2",
2110 - ]
2111 -
2112 - [[package]]
2113 2000 name = "scopeguard"
2114 2001 version = "1.2.0"
2115 2002 source = "registry+https://github.com/rust-lang/crates.io-index"
2116 2003 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
2117 2004
2118 2005 [[package]]
2119 - name = "security-framework"
2120 - version = "3.7.0"
2121 - source = "registry+https://github.com/rust-lang/crates.io-index"
2122 - checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
2123 - dependencies = [
2124 - "bitflags",
2125 - "core-foundation 0.10.1",
2126 - "core-foundation-sys",
2127 - "libc",
2128 - "security-framework-sys",
2129 - ]
2130 -
2131 - [[package]]
2132 - name = "security-framework-sys"
2133 - version = "2.17.0"
2134 - source = "registry+https://github.com/rust-lang/crates.io-index"
2135 - checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
2136 - dependencies = [
2137 - "core-foundation-sys",
2138 - "libc",
2139 - ]
2140 -
2141 - [[package]]
2142 2006 name = "semver"
2143 2007 version = "1.0.27"
2144 2008 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2606,40 +2470,6 @@ dependencies = [
2606 2470 ]
2607 2471
2608 2472 [[package]]
2609 - name = "system-configuration"
2610 - version = "0.7.0"
2611 - source = "registry+https://github.com/rust-lang/crates.io-index"
2612 - checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
2613 - dependencies = [
2614 - "bitflags",
2615 - "core-foundation 0.9.4",
2616 - "system-configuration-sys",
2617 - ]
2618 -
2619 - [[package]]
2620 - name = "system-configuration-sys"
2621 - version = "0.6.0"
2622 - source = "registry+https://github.com/rust-lang/crates.io-index"
2623 - checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
2624 - dependencies = [
2625 - "core-foundation-sys",
2626 - "libc",
2627 - ]
2628 -
2629 - [[package]]
2630 - name = "tempfile"
2631 - version = "3.27.0"
2632 - source = "registry+https://github.com/rust-lang/crates.io-index"
2633 - checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
Lines truncated
M Cargo.toml +2 -2
@@ -7,7 +7,7 @@ members = [
7 7 default-members = ["."]
8 8
9 9 [workspace.package]
10 - version = "0.2.2"
10 + version = "0.2.3"
11 11 edition = "2024"
12 12 license-file = "LICENSE"
13 13
@@ -28,7 +28,7 @@ tower-sessions = "0.14"
28 28 tower-sessions-sqlx-store = { version = "0.15", features = ["postgres"] }
29 29
30 30 # HTTP client / crypto
31 - reqwest = { version = "0.12", features = ["json"] }
31 + reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
32 32 sha2 = "0.10"
33 33 base64 = "0.22"
34 34 rand = "0.8"
@@ -0,0 +1,145 @@
1 + #!/bin/bash
2 + # Multithreaded Deployment Script — Hetzner (alpha-west-1)
3 + # Cross-compiles for x86_64 Linux on macOS, uploads, restarts.
4 + # Run from the multithreaded project root.
5 + #
6 + # Usage:
7 + # ./deploy/deploy-hetzner.sh # Build + deploy + restart
8 + # ./deploy/deploy-hetzner.sh --setup # First-time: create user, dirs, db, build, install, seed
9 + # ./deploy/deploy-hetzner.sh --config # Config only (Caddyfile, systemd, static, env)
10 + #
11 + # Prerequisites (one-time):
12 + # brew install zig
13 + # cargo install cargo-zigbuild
14 + # rustup target add x86_64-unknown-linux-gnu
15 +
16 + set -e
17 +
18 + # Configuration
19 + SERVER="root@100.120.174.96"
20 + REMOTE_DIR="/opt/multithreaded"
21 + BINARY_NAME="multithreaded"
22 + TARGET="x86_64-unknown-linux-gnu"
23 + DEPLOY_DIR="deploy"
24 +
25 + # Check we're in the right directory
26 + if [ ! -f "Cargo.toml" ] || ! grep -q 'name = "multithreaded"' Cargo.toml; then
27 + echo "Error: Run this script from active/multithreaded/"
28 + exit 1
29 + fi
30 +
31 + build_binary() {
32 + echo "[build] Cross-compiling for $TARGET..."
33 + ulimit -n 65536 2>/dev/null || true
34 + cargo zigbuild --release --target $TARGET
35 + echo "[build] Done: target/$TARGET/release/$BINARY_NAME"
36 + }
37 +
38 + upload_config() {
39 + echo "[config] Uploading configuration files..."
40 +
41 + # Systemd service
42 + scp $DEPLOY_DIR/multithreaded.service $SERVER:/etc/systemd/system/multithreaded.service
43 +
44 + # Static assets
45 + echo "[config] Uploading static assets..."
46 + ssh $SERVER "mkdir -p $REMOTE_DIR/static $REMOTE_DIR/migrations"
47 + rsync -az --delete static/ $SERVER:$REMOTE_DIR/static/
48 + rsync -az --delete migrations/ $SERVER:$REMOTE_DIR/migrations/
49 +
50 + # Fix ownership
51 + ssh $SERVER "chown -R multithreaded:multithreaded $REMOTE_DIR"
52 +
53 + # Reload systemd
54 + ssh $SERVER "systemctl daemon-reload"
55 + echo "[config] Done"
56 + }
57 +
58 + upload_binary() {
59 + echo "[upload] Stopping service and uploading binary..."
60 + ssh $SERVER "systemctl stop multithreaded || true"
61 + scp target/$TARGET/release/$BINARY_NAME $SERVER:$REMOTE_DIR/$BINARY_NAME
62 + ssh $SERVER "chmod +x $REMOTE_DIR/$BINARY_NAME && chown multithreaded:multithreaded $REMOTE_DIR/$BINARY_NAME"
63 + echo "[upload] Done"
64 + }
65 +
66 + restart_app() {
67 + echo "[restart] Restarting multithreaded..."
68 + ssh $SERVER "systemctl restart multithreaded"
69 + sleep 2
70 + echo ""
71 + ssh $SERVER "systemctl status multithreaded --no-pager"
72 + echo ""
73 + echo "[health] Checking..."
74 + ssh $SERVER "curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:3400/"
75 + }
76 +
77 + first_time_setup() {
78 + echo "=== First-Time Setup (Hetzner) ==="
79 +
80 + echo "[setup] Creating system user..."
81 + ssh $SERVER "
82 + useradd --system --shell /usr/sbin/nologin --home-dir $REMOTE_DIR multithreaded 2>/dev/null || echo 'User already exists'
83 + "
84 +
85 + echo "[setup] Creating directories..."
86 + ssh $SERVER "
87 + mkdir -p $REMOTE_DIR
88 + chown multithreaded:multithreaded $REMOTE_DIR
89 + "
90 +
91 + echo "[setup] Creating database role + database..."
92 + ssh $SERVER "
93 + sudo -u postgres createuser multithreaded 2>/dev/null || echo 'Role already exists'
94 + sudo -u postgres createdb -O multithreaded multithreaded 2>/dev/null || echo 'Database already exists'
95 + sudo -u postgres psql -c 'GRANT ALL PRIVILEGES ON DATABASE multithreaded TO multithreaded;' 2>/dev/null
96 + sudo -u postgres psql -d multithreaded -c 'GRANT ALL ON SCHEMA public TO multithreaded;' 2>/dev/null
97 + "
98 +
99 + build_binary
100 + upload_config
101 +
102 + echo "[setup] Installing binary..."
103 + upload_binary
104 +
105 + echo "[setup] Installing env file..."
106 + scp $DEPLOY_DIR/env.hetzner $SERVER:$REMOTE_DIR/.env
107 + ssh $SERVER "chmod 600 $REMOTE_DIR/.env && chown multithreaded:multithreaded $REMOTE_DIR/.env"
108 +
109 + echo "[setup] Enabling and starting service..."
110 + ssh $SERVER "systemctl enable multithreaded && systemctl start multithreaded"
111 + sleep 2
112 +
113 + echo "[setup] Running seed..."
114 + ssh $SERVER "cd $REMOTE_DIR && sudo -u multithreaded $REMOTE_DIR/$BINARY_NAME --seed"
115 +
116 + echo ""
117 + ssh $SERVER "systemctl status multithreaded --no-pager"
118 + echo ""
119 + echo "[health] Checking..."
120 + ssh $SERVER "curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:3400/"
121 + }
122 +
123 + case "${1:-deploy}" in
124 + --setup)
125 + first_time_setup
126 + ;;
127 + --config)
128 + echo "=== Config Deploy (Hetzner) ==="
129 + upload_config
130 + ;;
131 + deploy|"")
132 + echo "=== Deploy (Hetzner) ==="
133 + build_binary
134 + upload_config
135 + upload_binary
136 + restart_app
137 + ;;
138 + *)
139 + echo "Usage: $0 [--setup|--config]"
140 + exit 1
141 + ;;
142 + esac
143 +
144 + echo ""
145 + echo "=== Done ==="
@@ -0,0 +1,8 @@
1 + HOST=127.0.0.1
2 + PORT=3400
3 + DATABASE_URL=postgres:///multithreaded
4 + MNW_BASE_URL=https://makenot.work
5 + OAUTH_CLIENT_ID=mt-forums-6378957b452bbbc906c3db8edd072d64
6 + OAUTH_REDIRECT_URI=https://forums.makenot.work/auth/callback
7 + PLATFORM_ADMIN_ID=8d940646-480e-4a17-baf5-bc21fc3a4198
8 + COOKIE_SECURE=true
M todo.md +5 -3
@@ -1,6 +1,6 @@
1 1 # Multithreaded — Todo
2 2
3 - Done: Phases 0-11. 106 tests (65 integration + 25 unit lib + 16 unit mt-core). v0.2.1. Routes split into directory module (`routes/`). Graceful shutdown + reqwest timeouts. Unused deps removed. First formal audit: B+ (2026-03-14). All 10 audit findings resolved (1 HIGH + 4 MEDIUM + 5 SMALL). Rate limiting (tower-governor). Expired ban cleanup (opportunistic). Test coverage gaps closed. Ammonia HTML sanitizer (defense-in-depth). Audit grade: A. Initial git commit done. UI aligned with MNW: header nav (Library, Discover, Feed, Profile, Dashboard link to MNW), footer ("Powered by Makenot.work"), nav link styling (IBM Plex Mono, opacity transitions), dead CSS removed.
3 + Done: Phases 0-11. 106 tests (65 integration + 25 unit lib + 16 unit mt-core). v0.2.2. Routes split into directory module (`routes/`). Graceful shutdown + reqwest timeouts. Unused deps removed. First formal audit: B+ (2026-03-14). All 10 audit findings resolved (1 HIGH + 4 MEDIUM + 5 SMALL). Rate limiting (tower-governor). Expired ban cleanup (opportunistic). Test coverage gaps closed. Ammonia HTML sanitizer (defense-in-depth). Audit grade: A. Initial git commit done. UI aligned with MNW: header nav (Library, Discover, Feed, Profile, Dashboard link to MNW), footer ("Powered by Makenot.work"), nav link styling (IBM Plex Mono, opacity transitions), dead CSS removed. Deployed to hetzner (forums.makenot.work) alongside MNW (2026-03-15). Cross-compiled via cargo-zigbuild, reqwest uses rustls-tls. OAuth app registered in MNW production DB. Caddy reverse proxy + Cloudflare Origin CA + Authenticated Origin Pulls (mTLS). PoM monitoring configured. Public URL verified (HTTP 200 through Cloudflare).
4 4
5 5 Completed work archived in [todo_done.md](todo_done.md).
6 6
@@ -10,8 +10,10 @@ Alpha = forum is usable end-to-end: users can sign in via MNW OAuth, browse proj
10 10
11 11 ## Remaining from earlier phases
12 12
13 - - [ ] Caddy config on alpha-west-1 (reverse proxy alongside MNW, public domain when ready)
14 - - [ ] Deploy to alpha-west-1 (hetzner, alongside live MNW deployment)
13 + - [x] Caddy config on alpha-west-1 (reverse proxy alongside MNW, forums.makenot.work)
14 + - [x] Deploy to alpha-west-1 (hetzner, alongside live MNW deployment)
15 + - [x] DNS A record: `forums.makenot.work` → `5.78.144.244` (Cloudflare, proxy ON)
16 + - [x] Verify forums.makenot.work loads via public URL (HTTP 200 confirmed)
15 17 - [ ] Manual moderation testing (ban, mute, unban/unmute, mod log, admin dashboard)
16 18 - [ ] Paginate forum directory (if needed, when many projects exist)
17 19