This port generator generates a random TCP/UDP port between 1024 and 65535
Your personal random port: Port
Click here to generate a new random port number
This port generator generates a random TCP/UDP port between 1024 and 65535
Your personal random port: Port
Click here to generate a new random port number
In order to find out if your Ubuntu or other WSL linux installation is running on WSL1 or WSL2, open a Powershell and run
wsl --list -v
This will show you all WSL installations and the associated WSL versions:
PS C:\WINDOWS\system32> wsl --list -v NAME STATE VERSION * Ubuntu Running 1
As you can see, the Ubuntu
VM is running WSL VERSION 1
.
Go to the WSL2 installation page for instructions on how to upgrade to WSL2.
Run this in the directory where docker-compose.yml
is located:
curl -fsSL https://techoverflow.net/scripts/create-docker-compose-service.sh | sudo bash /dev/stdin
This script will automatically create a systemd service that starts docker-compose up
and shuts down using docker-compose down
. Our script will also systemctl enable
the script (i.e. start automatically on boot) and systemctl start
it (start it immediately).
The command above will download the script from TechOverflow and run it in bash
:
#!/bin/bash # Create a systemd service that autostarts & manages a docker-compose instance in the current directory # by Uli Köhler - https://techoverflow.net # Licensed as CC0 1.0 Universal SERVICENAME=$(basename $(pwd)) echo "Creating systemd service... /etc/systemd/system/${SERVICENAME}.service" # Create systemd service file sudo cat >/etc/systemd/system/$SERVICENAME.service <<EOF [Unit] Description=$SERVICENAME Requires=docker.service After=docker.service [Service] Restart=always User=root Group=docker TimeoutStopSec=15 WorkingDirectory=$(pwd) # Shutdown container (if running) when unit is started ExecStartPre=$(which docker-compose) -f docker-compose.yml down # Start container when unit is started ExecStart=$(which docker-compose) -f docker-compose.yml up # Stop container when unit is stopped ExecStop=$(which docker-compose) -f docker-compose.yml down [Install] WantedBy=multi-user.target EOF echo "Enabling & starting $SERVICENAME" # Autostart systemd service sudo systemctl enable $SERVICENAME.service # Start systemd service now sudo systemctl start $SERVICENAME.service
The service name is the directory name:
SERVICENAME=$(basename $(pwd))
Now we will create the service file in /etc/systemd/system/${SERVICENAME}.service
using the template embedded in the script
The script will automatically determine the location of docker-compose
using $(which docker-compose)
and finally enable and start the systemd
service:
# Autostart systemd service sudo systemctl enable $SERVICENAME.service # Start systemd service now sudo systemctl start $SERVICENAME.service
In this post we’ll show how to run Portainer Community Edition on a computer using docker-compose and systemd. In case you haven’t installed docker
or docker-compose
, see How to install docker and docker-compose on Ubuntu in 30 seconds.
If you already have a Portainer instance and want to run a Portainer Edge Agent on a remote computer, see Running Portainer Edge Agent using docker-compose and systemd!
First, create the directory where the docker-compose.yml
will live and edit it:
sudo mkdir -p /var/lib/portainer sudo nano /var/lib/portainer/docker-compose.yml
Now paste this config file:
version: '2' services: portainer: image: portainer/portainer command: -H unix:///var/run/docker.sock restart: always ports: - 9192:9000 - 8000:8000 volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer_data:/data volumes: portainer_data:
In this case, we’re exposing the Web UI on port 9192
since we’re using a reverse proxy setup in order to access the web UI. Using Portainer over HTTP without a HTTPS frontend is a security risk!
This is my nginx config that is used to reverse proxy my Portainer instance. Note that I generate the HTTPS config using certbot --nginx
, hence it’s not shown here:
server { server_name portainer.mydomain.com; location / { proxy_pass http://localhost:9192/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_redirect default; } listen 80; }
Now we can create the systemd service that will automatically start Portainer:
sudo nano /etc/systemd/system/portainer.service
[Unit] Description=Portainer Requires=docker.service After=docker.service [Service] Restart=always User=root Group=docker WorkingDirectory=/var/lib/portainer # Shutdown container (if running) when unit is stopped ExecStartPre=/usr/local/bin/docker-compose -f docker-compose.yml down # Start container when unit is started ExecStart=/usr/local/bin/docker-compose -f docker-compose.yml up # Stop container when unit is stopped ExecStop=/usr/local/bin/docker-compose -f docker-compose.yml down [Install] WantedBy=multi-user.target
Now we can can enable autostart on boot and start Portainer:
sudo systemctl enable portainer.service sudo systemctl start portainer.service
You are trying to run a Portainer Edge Agent, but can’t connect to the endpoint in the Portainer UI, but you see an error message like this in the logs:
2020/10/24 13:58:23 [ERROR] [internal,edge,poll] [message: an error occured during short poll] [error: short poll request failed]
First, check your EDGE_ID
and your EDGE_KEY
. In most cases, these are incorrectly set and prevent proper communication between the Edge Agent and the Portainer instance.
If that doesn’t help, check your firewall. Both port 8000 of the portainer instance . When creating a new Endpoint, Portainer will show you a message like
The agent will communicate with Portainer via https://portainer.mydomain.com and tcp://portainer.mydomain.com:8000
Depending on your system configuration, you need enable port 8000 on your firewall, e.g. using
sudo ufw enable 8000/tcp
In order to test the connectivity, you can use nc
:
echo -e "\n" | nc portainer.techoverflow.net 8000
This is how it looks on a working Portainer instance:
$ echo -e "\n" | nc portainer.mydomain.com 8000 HTTP/1.1 400 Bad Request Content-Type: text/plain; charset=utf-8 Connection: close 400 Bad Request
In case you don’t see any response, check your firewall and check if you’ve exposed port 8000 on the Portainer container.
Also, you can decode your EDGE_KEY
(use the one that is actually used in the Portainer Edge Agent instance) in any online base64 decoder like base64code.com: Decoding
aHR0cHM6Ly9wb3J0YWluZXIubXlkb21haW4uY29tfHBvcnRhaW5lci5teWRvbWFpbi5jb206ODAwMHw3MTphNTpiYTpkMjo4MToxOToxMTo4NzplYTowZjo0NDo0YTpmYTo0Mjo4YTphNnwz
will result in this string:
https://portainer.mydomain.com|portainer.mydomain.com:8000|71:a5:ba:d2:81:19:11:87:ea:0f:44:4a:fa:42:8a:a6|3
in which you can check the URLs. For example, check if the protocol (http or https) mismatches what you used to configure your main Portainer instance.
Finally, on the host that is running the Portainer Edge Agent, check if the hostname resolves correctly:
host portainer.mydomain.com
This should show you at least the IPv4 address of the Portainer instance. If that is not correct, these are most likely culprits:
echo nameserver 1.1.1.1 > /etc/resolv.conf
will typically fix that temporarily).Always check if you get the same results from your local computer as you get from the host that is running the Portainer Edge Agent.
In this post we’ll show how to run the Portainer Edge Agent on a computer using docker-compose and systemd. In case you haven’t installed docker
or docker-compose
, see How to install docker and docker-compose on Ubuntu in 30 seconds.
If you don’t have a Portainer instance running to which the Edge Agent can connect, see Running Portainer using docker-compose and systemd!
First, create the directory where the docker-compose.yml
will live and edit it:
sudo mkdir -p /var/lib/portainer-edge-agent sudo nano /var/lib/portainer-edge-agent/docker-compose.yml
Now paste this config file:
version: "3" services: portainer_edge_agent: image: portainer/agent command: -H unix:///var/run/docker.sock restart: always volumes: - /:/host - /var/lib/docker/volumes:/var/lib/docker/volumes - /var/run/docker.sock:/var/run/docker.sock - portainer_agent_data:/data environment: - CAP_HOST_MANAGEMENT=1 - EDGE=1 - EDGE_ID=[YOUR EDGE ID] - EDGE_KEY=[YOUR EDGE KEY] volumes: portainer_agent_data:
Don’t forget to fill in [YOUR EDGE ID]
and [YOUR EDGE KEY]
. You can find those by creating a new endpoint in your Portainer instance.
Now we can create the systemd service that will automatically start the Edge Agent:
sudo nano /etc/systemd/system/PortainerEdgeAgent.service
[Unit] Description=PortainerEdgeAgent Requires=docker.service After=docker.service [Service] Restart=always User=root Group=docker WorkingDirectory=/var/lib/portainer-edge-agent # Shutdown container (if running) when unit is stopped ExecStartPre=/usr/local/bin/docker-compose -f docker-compose.yml down # Start container when unit is started ExecStart=/usr/local/bin/docker-compose -f docker-compose.yml up # Stop container when unit is stopped ExecStop=/usr/local/bin/docker-compose -f docker-compose.yml down [Install] WantedBy=multi-user.target
Now we can can enable and start the agent:
sudo systemctl enable PortainerEdgeAgent.service sudo systemctl start PortainerEdgeAgent.service
wget -qO- https://techoverflow.net/scripts/install-rabbitmq.sh | sudo bash /dev/stdin
This will install RabbitMQ and its dependencies from the official deb repositories.
Copy and paste these command blocks into your Linux shell. You need to copy & paste one block at a time – you can paste the next block once the previous block is finished!
sudo apt-get update -y sudo apt-get install apt-transport-https curl gnupg -y curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo apt-key add -
sudo tee /etc/apt/sources.list.d/bintray.rabbitmq.list <<EOF deb https://dl.bintray.com/rabbitmq-erlang/debian $(lsb_release -cs) erlang deb https://dl.bintray.com/rabbitmq/debian $(lsb_release -cs) main EOF
sudo apt-get update -y sudo apt-get install rabbitmq-server -y --fix-missing
Use this simple command in order to add the WoeUSB APT repository and install woeusb
:
sudo add-apt-repository -y ppa:tomtomtom/woeusb ; sudo apt -y install woeusb
For more informatio, refer to the Ubuntuusers wiki page on WoeUSB
In many of my dockerized Gitlab instances, the prometheus/data
folder was eating up multiple Gigabytes of hard drive space even though I was not using Prometheus at all.
In order to fix this, I first disabled Prometheus in the docker-compose.yml
config using
prometheus_monitoring['enable'] = false
Also see How I reduced gitlab memory consumption in my docker-based setup for a detailed explanantion.
After that, you need to restart gitlab in order for the settings change to take effect.
Now you can just delete the Prometheus data folder. Make a backup of the entire gitlab data folder before this step.
Run this command from within your gitlab data folder:
rm -rf prometheus/data
The Anycubic i3 Mega (-S) stock mainboard uses the Atmega2560 microcontroller which has the following properties:
The first resource can have a look at is the platform configuration option page. Additionally, check the manual on how to use the mbed CLI to show configuration options.
Additionally, you can look at targets.json
on GitHub:
For example, "Target" => "config" => "default-adc-vref"
would need to be entered like this into mbed_app.json
:
{ "target_overrides": { "*": { "target.default-adc-vref": 3300 } } }
You are trying to read an ADC voltage in mbed / PlatformIO like this:
AnalogIn myADC(PA_5); // Read and print voltage, then return float v = myADC.read_voltage(); printf("%f\n", v);
but this only prints nan
or 0.000
.
mbed doesn’t know the reference voltage for your platform. The easiest method is to provide the referene voltage in the constructor of AnalogIn
:
AnalogIn myADC(PA_5, 3.3);
This specifies a reference voltage of 3.3V
. While this applies to most applications in their default configuration, note that the reference voltage might be different depending on the configuration of your microcontroller.
In my experience, it’s almost always better to experimentally verify the reference voltage instead of trying to theorize about it if it’s not immediately obvious.
#include <mbed.h> BufferedSerial pc(USBTX, USBRX, 115200); // tx, rx AnalogIn myADC(PA_5, 3.3); FileHandle *mbed::mbed_override_console(int fd) { return &pc; } int main() { while(1) { float v = myADC.read_voltage(); printf("%f\n", v); ThisThread::sleep_for(100ms); } }
{ "target_overrides": { "*": { "target.printf_lib": "std" } } }
You are using code like
printf("%.2f\n", myFloat);
in your mbed/PlatformIO application, but instead of printing myFloat
with 2 decimal places, it always prints it with 6 decimal places (like 0.000000
).
mbed uses the minimal-printf
library by default which is configured to save space on the Microcontroller. Hence, float max decimals support is disabled by default. In order to get all printf
features at the expense of more flash usage and much slower executing, us add mbed_app.json
in the root directory of the PlatformIO project with "target.printf_lib": "std"
:
{ "target_overrides": { "*": { "target.printf_lib": "std" } } }
See the platform configuration option page for more details and similar options.
You are using code like
printf("%f\n", myFloat);
in your mbed/PlatformIO application, but instead of printing myFloat
it prints literal %f
.
mbed uses the minimal-printf
library by default which is configured to save space on the Microcontroller. Hence, float support (i.e. %f
support) is disabled by default. You need to enable it by adding mbed_app.json
in the root directory of the PlatformIO project with "platform.minimal-printf-enable-floating-point": true
:
{ "target_overrides": { "*": { "platform.minimal-printf-enable-floating-point": true } } }
See the platform configuration option page for more details and similar options.
While compiling your mbed / PlatformIO application, you see an error message like
src/actuators.cpp:253:5: error: 'wait' was not declared in this scope 253 | wait(1.0); | ^~~~
wait is an old API and has been deprecated in favour of the C++ standard ThisThread::sleep_for
. Use
ThisThread::sleep_for(1s);
You are trying to run your Python application, but you see an error message like
Traceback (most recent call last): [...] File "/mnt/KATranslationCheck/CrowdinLogin.py", line 38, in get_crowdin_tokens return asyncio.get_event_loop().run_until_complete(async_get_crowdin_tokens(username, password)) File "/usr/lib/python3.6/asyncio/events.py", line 694, in get_event_loop return get_event_loop_policy().get_event_loop() File "/usr/lib/python3.6/asyncio/events.py", line 602, in get_event_loop % threading.current_thread().name) RuntimeError: There is no current event loop in thread 'worker 3'.
You are trying to run asyncio.get_event_loop()
in some thread other than the main thread – however, asyncio only generates an event loop for the main thread.
Use this function instead of asyncio.get_event_loop()
:
import asyncio def get_or_create_eventloop(): try: return asyncio.get_event_loop() except RuntimeError as ex: if "There is no current event loop in thread" in str(ex): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) return asyncio.get_event_loop()
It will first try asyncio.get_event_loop()
. In case that doesn’t work, it will generate a new event loop for the current thread using
loop = asyncio.new_event_loop() asyncio.set_event_loop(loop)
and then returns this event loop.
Note that while this works well for generating the event loop, but depending on the way you use the event loop, you might encounter further error messages like
Traceback (most recent call last): File "/usr/local/lib/python3.6/dist-packages/pyppeteer/launcher.py", line 305, in launch return await Launcher(options, **kwargs).launch() File "/usr/local/lib/python3.6/dist-packages/pyppeteer/launcher.py", line 157, in launch signal.signal(signal.SIGINT, _close_process) File "/usr/lib/python3.6/signal.py", line 47, in signal handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler)) ValueError: signal only works in main thread
that are usually not as easy to fix and require some restructuring of your program.
This program just shows a message box and exits:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace MinimalMessageBoxProgram { class MinimalMessageBoxProgram { public static void Main(string[] args) { MessageBox.Show("This is the minimal text shown in the message dialog."); } } }
You want to run your Pyppeteer application on Linux, but you see an error message like
Traceback (most recent call last): File "PyppeteerExample.py", line 15, in <module> asyncio.get_event_loop().run_until_complete(main()) File "/usr/lib/python3.6/asyncio/base_events.py", line 484, in run_until_complete return future.result() File "PyppeteerExample.py", line 6, in main browser = await launch() File "/usr/local/lib/python3.6/dist-packages/pyppeteer/launcher.py", line 305, in launch return await Launcher(options, **kwargs).launch() File "/usr/local/lib/python3.6/dist-packages/pyppeteer/launcher.py", line 166, in launch self.browserWSEndpoint = get_ws_endpoint(self.url) File "/usr/local/lib/python3.6/dist-packages/pyppeteer/launcher.py", line 225, in get_ws_endpoint raise BrowserError('Browser closed unexpectedly:\n') pyppeteer.errors.BrowserError: Browser closed unexpectedly:
In most cases, the underlying error for this error message is Puppetteer’s libX11-xcb.so.1: cannot open shared object file: No such file or directory. In order to fix that, you need to install dependency libraries for Chromium which is used internally by Puppeteer / Pyppeteer:
sudo apt install -y gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
This script is a minimal example on how to use Pyppeteer to fetch a web page and extract the page title (the content of the .logo_default
HTML element)
#!/usr/bin/env python3 import asyncio from pyppeteer import launch async def main(): browser = await launch() page = await browser.newPage() await page.goto('https://www.techoverflow.net') # Get the URL and print it title = await page.evaluate("() => document.querySelector('.logo-default').textContent") print(f"Page title: {title}") # prints Page title: TechOverflow # Cleanup await browser.close() asyncio.get_event_loop().run_until_complete(main())
How to run:
sudo pip3 install pyppeteer python3 PyppeteerExample.py
If you encounter this error message during APT update:
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 78BD65473CB3BD13
you need to import the key using
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 78BD65473CB3BD13