title: Linux Server Applications breadcrumbs:
{:.no_toc}
Outdated and missing information
apt install apache2
Update security.conf
:
ServerTokens Prod
ServerSignature Off
a2<en|dis><conf|mod|site> <...>
apache2ctl
Sends an emails when APT updates are available.
apt install apticron
/etc/apticron/apticron.conf
cp /usr/lib/apticron/apticron.conf /etc/apticron/apticron.conf
/etc/cron.d/apticron
(e.g. 30 23 * * *
).IPADDRESSNUM
and always print all IP adresses:
/usr/sbin/apticron
.IPADDRESSES=`(echo $( /bin/hostname --all-ip-addresses ) ;
IPADDRESSES=`(
apticron
TODO
apt install avahi-daemon
Possibly outdated
awscli
through pip3chmod +x /usr/local/bin/aws
aws configure [--profile <profile>]
eu-west-2
json
aws s3 cp <local_file> s3://<bucket>/
A free community backend for Bitwarden.
TODO
See Storage: Ceph.
apt install certbot
/etc/letsencrypt/cli.ini
, add renew-hook = systemctl reload nginx
or equivalent.certbot -d <domain> --preferred-challenges=http --webroot --webroot-path=<webroot> certonly
certbot -d <domain> --preferred-challenges=dns --manual certonly
certbot renew --dry-run [--staging]
certbot revoke --cert-path <cert>
docker info
contains WARNING: No swap limit support
, it's not working and should maybe be fixed./etc/default/grub
, add cgroup_enable=memory swapaccount=1
to GRUB_CMDLINE_LINUX
.update-grub
and reboot./etc/docker/daemon.json
:
"ipv6": true
and "fixed-cidr-v6": "<ipv6-subnet>/64"
"dns": ["1.1.1.1", "2606:4700:4700::1111"]
8.8.8.8
and 8.8.4.4
by default./etc/resolv.conf
is limited to only three name servers, so don't provide too many. One may be set by the container itself."iptables": false
docker
group.docker system df -v
docker image prune -a
docker volume prune
--name=<name>
-d
-it
--rm
--restart=unless-stopped
--init
-e <var>=<val>
-p <host-port>:<cont-port>[/udp]
-v <vol>:<cont-path>
(<vol>
must have a path prefix like ./
or /
if it is a directory and not a named volume)docker network create --driver=bridge --subnet=<ipv4-net> --ipv6 --subnet=<ipv6-net> <name>
docker network create --driver=bridge --subnet=<ipv4-net> --gateway=<ipv4-gateway> --ipv6 --subnet=<ipv6-net> --gateway=<ipv6-gateway> -o "com.docker.network.bridge.name=<host-if> <name>
docker network create --driver=macvlan --subnet=<ipv4-net> --gateway=<ipv4-gateway> --ipv6 --subnet=<ipv6-net> --gateway=<ipv6-gateway> -o parent=<netif>[.<vid>] <name>
docker network create --driver=ipvlan --subnet=<ipv4-net> --gateway=<ipv4-gateway> --ipv6 --subnet=<ipv6-net> --gateway=<ipv6-gateway> -o parent=<netif> <name>
docker run --network=<net-name> --ip=<ipv4-addr> --ip6=<ipv6-addr> --dns=<dns-server> [...] <image>
Docker Compose will fail to work if /tmp
has noexec
.
/usr/local/bin/docker-compose
to /usr/local/bin/docker-compose-normal
./usr/local/bin/docker-compose
with the contents below and make it executable.New docker-compose
:
#!/bin/bash
# Some dir without noexec
export TMPDIR=/var/lib/docker-compose-tmp
/usr/local/bin/docker-compose-normal "$@"
fail2ban
.fail2ban-client status [sshd]
.Possibly outdated
This setup requires pubkey plus MFA (if configured) plus password.
apt install libpam-google-authenticator
/etc/pam.d/sshd
, add auth required pam_google_authenticator.so nullok
after @include common-auth
.In /etc/ssh/sshd_config
, set:
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive
Restart sshd
and check that you can login with pubkey and MFA now.
(Optional) Add my google-auth-config-prompter.sh profile script to /etc/profile.d/
to ask user to configure Google Auth on login.
To allow a group to use only pubkey (no password or OTP):
/etc/ssh/sshd_config
, add Match Group no-mfa
containing AuthenticationMethods publickey
(indented) at the bottom.no-mfa
and add special users to it.To manually configure MFA for a user:
google-authenticator -tduW
See Storage: isdct.
Typically used with a data source like Prometheus.
./grafana.ini:/etc/grafana/grafana.ini:ro
./data:/var/lib/grafana/:rw
(requires UID 472)./logs:/var/log/grafana/:rw
(requires UID 472)grafana.ini
.See Home Assistant.
isc-dhcp-server
./etc/dhcp/dhcpd.conf
/etc/dhcp/dhcpd6.conf
authorative
statement in subnet declarations so that the server will reply with DHCPNAK for misconfigured clients.
This may significantly reduce reconfiguration delay when a client moves between subnets.range6
, prefer using CIDR notation.
If using range notation, try to align the start and end on a CIDR block to avoid excessive memory usage./116
gives 8191 addresses.Get sensor values like temperature, voltage, fan speeds, etc.
apt install lm-sensors
sensors
sensors-detect
. When it asks, add the modules to /etc/modules
.systemctl restart kmod
sensors
journalctl
:
chip "<chip>"\n ignore <sensor>
in /etc/sensors3.conf
. Re-run sensors
. (See Kernel ACPI Error SMBus/IPMI/GenericSerialBus (ServerAdminBlog) for an example on certain HP servers.)sensors
. If it worked, then remove it from /etc/modules
to make it permanent.A MySQL fork that is generally MySQL compatible.
apt install mariadb-server
mysql_secure_installation
mariadb [-u <user> [-p]]
root
.-p
.GRANT ALL ON *.* TO '<user>'@'127.0.0.1' IDENTIFIED BY '<password>' WITH GRANT OPTION;
The instructions below use NFSv4 without Kerberos. This should only be used on trusted networks and requires manual user and group ID management.
apt install nfs-kernel-server
portmap
if you need support for NFSv2 and v3 (not NFSv4).(Recommended) Enable only v4:
In /etc/default/nfs-common
, set:
NEED_STATD="no"
NEED_IDMAPD="yes"
In /etc/default/nfs-kernel-server
, set:
RPCNFSDOPTS="-N 2 -N 3"
RPCMOUNTDOPTS="--manage-gids -N 2 -N 3"
Mask "rpcbind":
systemctl disable --now rpcbind.service
systemctl mask rpcbind.service
systemctl mask rpcbind.socket
Restart it: systemctl restart nfs-server.service
See which versions are running: cat /proc/fs/nfsd/versions
(-
means disabled)
mkdir /export
/zfspool/alpha /export/alpha none bind,defaults,nofail,x-systemd.requires=zfs-mount.service 0 0
/etc/exports
.
exports(5)
.exportfs -ra
systemctl restart nfs-server.service
exportfs -v
Example /etc/exports
:
# "fsid=root" is a special root export in NFSv4 where other exports are accessible relative to it.
# "sync" should generally always be used. While "async" gives better performance, it violates the spec and may cause data loss in case of power loss.
# "root_squash" maps client root users to an anon user to prevent remote root access. If that's desired, set "no_root_squash" instead.
# "no_subtree_check" disables subtree checking. Subtree checking may be appropriate for certain file systems, but in general it may cause more problems than it solves.
# "insecure" allows clients connecting from non-well-known ports.
/export/ *(fsid=root,ro,sync,root_squash,no_subtree_check,insecure)
/export/projects/ *(rw,sync,root_squash,no_subtree_check,insecure)
apt install nfs-common
mount -t nfs4 <server-hostname>:<export> <mountpoint>
/etc/fstab
entry: <nfs-server>:<export> <local-dir> nfs4 defaults 0 0
ntopng
.ntopng
is enabled and running.chown nobody:nogroup /var/log/ntopng
/etc/ntopng.conf
.-W=<new_port>
to enable HTTPS.-w=0
to disable HTTP.systemd-timesyncd
.ntp
./etc/ntp.conf
, replace existing servers/pools with ntp.justervesenet.no
with the iburst
option.ntpq -pn
(it may take a minute to synchronize).Instructions for both servers and clients. Exclusive steps are marked "(Server)" or "(Client)".
Since SSL/TLS is not enabled by default for client-server communication, use only trusted networks for this communication.
apt install nut
/etc/nut/nut.conf
and set MODE=netserver
for server or MODE=netclient
for client./etc/nut/ups.conf
and add a declaration for all UPSes (see example below).
usbhid-ups
driver if using USB. Otherwise, check the hardware compatibility list to find the correct driver. If the exact model isn't there, try a similar one.usbhid-ups
, see the example below and usbhid-ups(8).systemctl restart nut-driver.service
/etc/nut/upsd.conf
and set LISTEN ::
.
LISTEN
directives for only the endpoints you wish to listen on./etc/nut/upsd.users
and add users (see example below).
systemctl restart nut-server.service
nut-client.service
./etc/nut/upsmon.conf
and add MONITOR <ups>@<host>[:<port>] <ups-count> <user> <password> <master|slave>
.
ups-count
is typically 1
. If this system is not powered by the UPS but you want to monitor it without shutting down, set it to 0
.RBWARNTIME
(how often upsmon should complain about batteries needing replacement) to an appropriate value, e.g. 604800 (1 week)./etc/nut/upsmon.conf
, add EXEC
to all NOTIFYFLAG
entries you want to run the script for (typically all except LOWBATT
)./etc/nut/upsmon.conf
, set the script to run using format NOTIFYCMD /opt/scripts/nut-notify.sh
.systemctl restart nut-monitor.service
nut-monitor
successfully connected to the server.
upsc
does not use a server user or the monitoring service, so it's not very useful for debugging that.upsrw -s battery.runtime.low=<seconds> <ups>
and upsrw -s battery.charge.low=<percent> <ups>
usbhid-ups
, this is set using offdelay
and ondelay
. Otherwise, it's set using ups.delay.shutdown
and ups.delay.start
. The start delay must be greater than the stop delay.
upsmon -c fsd
Example USB UPS declaration for usbhid-ups
(/etc/nut/ups.conf
):
[alpha]
desc = "PowerWalker VI 3000 RLE"
# usbhid-ups should work for most UPSes with
driver = usbhid-ups
# If you have multiple UPSes connected, see usbhid-ups(8) for more specifying which USB device it should use
port = auto
# Sets "ups.delay.shutdown", the delay between the shutdown command and when the UPS powers off (default 20s)
offdelay = 60
# Sets "ups.delay.start", which has something to do with letting the UPS charge enough to make sure devices may fully boot (default 30s, must be greater than offdelay)
ondelay = 120
Example server users (/etc/nut/upsd.users
):
[admin]
password = <password>
actions = SET
instcmds = ALL
[local]
password = <password>
upsmon master
Example notify script:
#!/bin/bash
echo -e "Time: $(date)\nMessage: $@" | mail -s "NUT: $@" root
-noout -text
prints the data as formatted text instead of raw Base64.openssl req -new -x509 -sha256 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 3650 -subj "/C=ZZ/ST=Local/L=Local/O=Local/OU=Local/CN=localhost"
docker logs pihole 2>&1 | grep "random password"
/etc/pihole/adlists.list
./etc/pihole/whitelist.txt
.pihole -g
to update lists.Is typically run on a Docker host. Includes the agent.
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v ./data:/data portainer/portainer:<version>
/var/run/docker.sock
was mounted, use "local".Must be run on a Docker host. For extra Docker hosts you want to control with another Portainer server.
docker run -d -p 9001:9001 --name portainer_agent --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes portainer/agent:<version>
postfix libsasl2-modules mailutils
/etc/postfix/main.cf
./etc/aliases
, then run newaliases
.main.cf
config (example not provided here).
inet_interfaces = loopback-only
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
smtpd_banner = $myhostname ESMTP
apikey
.To
and From
fields, which is typically from root to root.smtp_header_checks
in the main config.postmap -fq "From: root@$(hostname --fqdn)" regexp:smtp_header_checks
/etc/postfix/sasl_passwd
[relay_domain]:port user@domain:password
postmap sasl_passwd
chmod 600 sasl_passwd*
postfix
.echo "Test from $(hostname) at time $(date)." | mail -s "Test" root
File smtp_header_checks
:
/^From:\s*.*\S+@node\.example\.bet.*.*$/ REPLACE From: "Node" <node@example.net>
/^To:\s*.*\S+@node\.example\.net.*$/ REPLACE To: "Someone" <someone@example.net>
echo "Test from $HOSTNAME at time $(date)." | mail -s "Test" root
postconf > /dev/null
postconf -n
mailq
tells you mails are stuck in the mail queue because of previous errors, run postqueue -f
to flush them.Typically used with Grafana and sometimes with Cortex/Thanos in-between.
docker inspect
or the source code.--storage.tsdb.retention.time=15d
and/or --storage.tsdb.retention.size=100GB
(with example values).storage.local.*
and storage.remote.*
flags no longer work../prometheus.yml:/etc/prometheus/prometheus.yml:ro
./data/:/prometheus/:rw
prometheus.yml
.
scrape_interval
, scrape_timeout
and evaluation_interval
) and scrape configs.sum(scrape_series_added) by (job)
, sum(scrape_samples_scraped) by (job)
, prometheus_tsdb_symbol_table_size_bytes
, rate(prometheus_tsdb_head_series_created_total[5m])
, sum(sum_over_time(scrape_series_added[5m])) by (job)
. You can also find some useful stats in the dashboard.This list contains exporters and software with built-in exposed metrics I typically use. Some are described in more detail in separate subsections.
Can be set up either using Docker (prom/node-exporter), using the package manager (prometheus-node-exporter
on Debian), or by building it from source. The Docker method provides a small level of protection as it's given only read-only system access. The package version is almost always out of date and is typically not optimal to use. If Docker isn't available and you want the latest version, build it from source.
See Building and running.
Details:
prometheus
/usr/bin/prometheus-node-exporter
/etc/systemd/system/prometheus-node-exporter.service
/etc/default/prometheus-node-exporter
/var/lib/prometheus/node-exporter/
Instructions:
apt install moreutils
wget <url>
and tar xvf <file>
cp node_exporter*/node_exporter /usr/bin/prometheus-node-exporter
node_exporter -h
useradd -r prometheus
touch /etc/default/prometheus-node-exporter
mkdir -p /var/lib/prometheus/node-exporter/
/etc/systemd/system/prometheus-node-exporter.service
, see prometheus-node-exporter.service./etc/default/prometheus-node-exporter
ARGS="--collector.processes --collector.interrupts --collector.systemd"
(enables more detailed process and interrupt collectors)systemctl enable --now prometheus-node-exporter
Some I typically use.
--collector.textfile.directory=<dir>
.
/var/lib/prometheus/node-exporter/
ARGS
variable in /etc/default/prometheus-node-exporter
./opt/prometheus/node-exporter/textfile-collectors/
sponge
is installed. For Debian, it's found in the moreutils
package./etc/cron.d/prometheus-node-exporter-textfile-collectors
0 * * * * root /opt/prometheus/node-exporter/textfile-collectors/apt.sh | sponge /var/lib/prometheus/node-exporter/apt.prom
Add a HTTP probe job for the services and query for probe success over time.
Example query: avg_over_time(probe_success{job="node"}[1d]) * 100
Add a HTTP probe job for the services and query for probe_ssl_earliest_cert_expiry - time()
.
Example alert rule: probe_ssl_earliest_cert_expiry{job="blackbox"} - time() < 86400 * 30
(30 days)
TODO
Logs are located in /app/storage/logs/laravel/
inside the container.
unzip
.{ "dns": ["1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"] }
to /etc/docker/daemon.json
.See Counter-Strike: Global Offensive (CS:GO).
radvd
./etc/radvd.conf
apt install samba
systemctl disable --now nmbd
and systemctl mask nmbd
server signing
and smb encrypt
) on important volumes.socket options = TCP_NODELAY SO_KEEPALIVE IPTOS_LOWDELAY
smb encrypt = disabled
read raw = yes
and read raw = yes
use sendfile = yes
min receivefile size = 16384
aio read size = 16384
and aio write size = 16384
/etc/samba/smb.conf
testparm -t
systemctl restart smbd
useradd -r <name>
useradd
smbpasswd -a <user>
sudo pdbedit -L -v
apt install cifs-utils
Add permanent share:
Create a credentials file (/root/.credentials/smb/<whatever>
):
user=<user>
password=<password>
In /etc/fstab
, add: //<share> <mountpoint> cifs vers=3.1.1,uid=<uid>,gid=<gid>,credentials=<file>,iocharset=utf8 0 0
Test it: mount -a
apt install smartmontools
smartctl -a <dev>
smartctl -t <short|long|conveyance|select> [-C] <dev>
-C
: Foreground mode.tftpd-hpa
./etc/default/tftpd-hpa
based on the config below./var/tftp
with permissions 777
and user-group pair tftp:tftp
.File /etc/default/tftpd-hpa
:
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/var/tftp"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--create --secure"
apt install unbound dns-root-data
/etc/unbound/unbound.conf
/etc/hosts
contains the short and FQDN hostnames./etc/resolv.conf
.DNSStubListener=no
.DNS=::1
.systemd-resolved
./etc/resolv.conf
.Set:
nameserver 127.0.0.1
nameserver ::1
domain <domain>
search <domain-list>
systemctl restart unbound
drill sigfail.verteiltesysteme.net
should give an rcode of SERVFAIL
.drill sigok.verteiltesysteme.net
should give an rcode of NOERROR
./usr/share/dns/root.hints
.See Ubiquiti UniFi Controller (Debian).
See Storage: ZFS.
{% include footer.md %}